1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available at through the world-wide-web at the following url:        |
10   | http://www.php.net/license/3_01.txt.                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: George Wang <gwang@litespeedtech.com>                        |
16   +----------------------------------------------------------------------+
17*/
18
19/*
20Copyright (c) 2002-2014, Lite Speed Technologies Inc.
21All rights reserved.
22
23Redistribution and use in source and binary forms, with or without
24modification, are permitted provided that the following conditions are
25met:
26
27    * Redistributions of source code must retain the above copyright
28      notice, this list of conditions and the following disclaimer.
29    * Redistributions in binary form must reproduce the above
30      copyright notice, this list of conditions and the following
31      disclaimer in the documentation and/or other materials provided
32      with the distribution.
33    * Neither the name of the Lite Speed Technologies Inc nor the
34      names of its contributors may be used to endorse or promote
35      products derived from this software without specific prior
36      written permission.
37
38THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49*/
50
51
52#include <ctype.h>
53#include <dlfcn.h>
54#include <errno.h>
55#include <fcntl.h>
56
57#include <sys/stat.h>
58#include <signal.h>
59#include <stdlib.h>
60#include <stdio.h>
61#include <string.h>
62#include <sys/mman.h>
63#include <sys/resource.h>
64#include <sys/socket.h>
65#include <sys/time.h>
66#include <sys/uio.h>
67#include <sys/wait.h>
68#include <grp.h>
69#include <pwd.h>
70#include <time.h>
71#include <unistd.h>
72#include <arpa/inet.h>
73#include <netdb.h>
74#include <netinet/in.h>
75#include <netinet/tcp.h>
76#include <sys/un.h>
77
78#include "lsapilib.h"
79
80#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
81#include <sys/prctl.h>
82#endif
83
84#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
85    || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
86#include <sys/sysctl.h>
87#endif
88
89#include <inttypes.h>
90#ifndef uint32
91#define uint32 uint32_t
92#endif
93
94struct lsapi_MD5Context {
95    uint32 buf[4];
96    uint32 bits[2];
97    unsigned char in[64];
98};
99
100void lsapi_MD5Init(struct lsapi_MD5Context *context);
101void lsapi_MD5Update(struct lsapi_MD5Context *context, unsigned char const *buf,
102           unsigned len);
103void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *context);
104
105/*
106 * This is needed to make RSAREF happy on some MS-DOS compilers.
107 */
108typedef struct lsapi_MD5Context lsapi_MD5_CTX;
109
110
111#define LSAPI_ST_REQ_HEADER     1
112#define LSAPI_ST_REQ_BODY       2
113#define LSAPI_ST_RESP_HEADER    4
114#define LSAPI_ST_RESP_BODY      8
115
116#define LSAPI_RESP_BUF_SIZE     8192
117#define LSAPI_INIT_RESP_HEADER_LEN 4096
118
119
120
121static int g_inited = 0;
122static int g_running = 1;
123static int s_ppid;
124static int s_slow_req_msecs = 0;
125static int s_keepListener = 0;
126static int s_dump_debug_info = 0;
127static int s_pid_dump_debug_info = 0;
128
129LSAPI_Request g_req = { -1, -1 };
130
131static char         s_pSecret[24];
132
133
134void Flush_RespBuf_r( LSAPI_Request * pReq );
135
136static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
137{
138    "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET",
139    "HTTP_ACCEPT_ENCODING",
140    "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION",
141    "HTTP_CONNECTION", "CONTENT_TYPE",
142    "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2",
143    "HTTP_HOST", "HTTP_PRAGMA",
144    "HTTP_REFERER", "HTTP_USER_AGENT",
145    "HTTP_CACHE_CONTROL",
146    "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH",
147    "HTTP_IF_NONE_MATCH",
148    "HTTP_IF_RANGE",
149    "HTTP_IF_UNMODIFIED_SINCE",
150    "HTTP_KEEP_ALIVE",
151    "HTTP_RANGE",
152    "HTTP_X_FORWARDED_FOR",
153    "HTTP_VIA",
154    "HTTP_TRANSFER_ENCODING"
155};
156
157static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] =
158{    11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18,
159     22, 13, 18, 13, 24, 15, 10, 20, 8, 22 };
160
161
162static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] =
163{
164    "Accept", "Accept-Charset",
165    "Accept-Encoding",
166    "Accept-Language", "Authorization",
167    "Connection", "Content-Type",
168    "Content-Length", "Cookie", "Cookie2",
169    "Host", "Pragma",
170    "Referer", "User-Agent",
171    "Cache-Control",
172    "If-Modified-Since", "If-Match",
173    "If-None-Match",
174    "If-Range",
175    "If-Unmodified-Since",
176    "Keep-Alive",
177    "Range",
178    "X-Forwarded-For",
179    "Via",
180    "Transfer-Encoding"
181};
182
183static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] =
184{   6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent
185    13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17
186};
187
188static void lsapi_sigpipe( int sig )
189{
190}
191static void lsapi_siguser1( int sig )
192{
193    g_running = 0;
194}
195
196#ifndef sighandler_t
197typedef void (*sighandler_t)(int);
198#endif
199
200static void lsapi_signal(int signo, sighandler_t handler)
201{
202    struct sigaction sa;
203
204    sigaction(signo, NULL, &sa);
205
206    if (sa.sa_handler == SIG_DFL)
207    {
208        sigemptyset(&sa.sa_mask);
209        sa.sa_flags = 0;
210        sa.sa_handler = handler;
211        sigaction(signo, &sa, NULL);
212    }
213}
214
215
216static int s_enable_core_dump = 0;
217static void lsapi_enable_core_dump()
218{
219#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
220    || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
221    int  mib[2];
222    size_t len;
223
224    len = 2;
225    if ( sysctlnametomib("kern.sugid_coredump", mib, &len) == 0 )
226    {
227        len = sizeof(s_enable_core_dump);
228        if (sysctl(mib, 2, NULL, 0, &s_enable_core_dump, len) == -1)
229            perror( "sysctl: Failed to set 'kern.sugid_coredump', "
230                    "core dump may not be available!");
231    }
232
233
234#endif
235
236#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
237    if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1)
238        perror( "prctl: Failed to set dumpable, "
239                    "core dump may not be available!");
240#endif
241}
242
243
244static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader,
245                                char type, int len )
246{
247    pHeader->m_versionB0 = LSAPI_VERSION_B0;  /* LSAPI protocol version */
248    pHeader->m_versionB1 = LSAPI_VERSION_B1;
249    pHeader->m_type      = type;
250    pHeader->m_flag      = LSAPI_ENDIAN;
251    pHeader->m_packetLen.m_iLen = len;
252}
253
254static  int lsapi_set_nblock( int fd, int nonblock )
255{
256    int val = fcntl( fd, F_GETFL, 0 );
257    if ( nonblock )
258    {
259        if (!( val & O_NONBLOCK ))
260        {
261            return fcntl( fd, F_SETFL, val | O_NONBLOCK );
262        }
263    }
264    else
265    {
266        if ( val & O_NONBLOCK )
267        {
268            return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) );
269        }
270    }
271    return 0;
272}
273
274static int lsapi_close( int fd )
275{
276    int ret;
277    while( 1 )
278    {
279        ret = close( fd );
280        if (( ret == -1 )&&( errno == EINTR )&&(g_running))
281            continue;
282        return ret;
283    }
284}
285
286static inline ssize_t lsapi_read( int fd, void * pBuf, size_t len )
287{
288    ssize_t ret;
289    while( 1 )
290    {
291        ret = read( fd, (char *)pBuf, len );
292        if (( ret == -1 )&&( errno == EINTR )&&(g_running))
293            continue;
294        return ret;
295    }
296}
297
298/*
299static int lsapi_write( int fd, const void * pBuf, int len )
300{
301   int ret;
302   const char * pCur;
303   const char * pEnd;
304   if ( len == 0 )
305       return 0;
306   pCur = (const char *)pBuf;
307   pEnd = pCur + len;
308   while( g_running && (pCur < pEnd) )
309   {
310       ret = write( fd, pCur, pEnd - pCur );
311       if ( ret >= 0)
312           pCur += ret;
313       else if (( ret == -1 )&&( errno != EINTR ))
314           return ret;
315   }
316   return pCur - (const char *)pBuf;
317}
318*/
319
320static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
321{
322    int ret;
323    int left = totalLen;
324    int n = count;
325    while(( left > 0 )&&g_running )
326    {
327        ret = writev( fd, *pVec, n );
328        if ( ret > 0 )
329        {
330            left -= ret;
331            if (( left <= 0)||( !g_running ))
332                return totalLen - left;
333            while( ret > 0 )
334            {
335                if ( (*pVec)->iov_len <= (unsigned int )ret )
336                {
337                    ret -= (*pVec)->iov_len;
338                    ++(*pVec);
339                }
340                else
341                {
342                    (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret;
343                    (*pVec)->iov_len -= ret;
344                    break;
345                }
346            }
347        }
348        else if ( ret == -1 )
349        {
350            if ( errno == EAGAIN )
351            {
352                if ( totalLen - left > 0 )
353                    return totalLen - left;
354                else
355                    return -1;
356            }
357            else if ( errno != EINTR )
358                return ret;
359        }
360    }
361    return totalLen - left;
362}
363
364/*
365static int getTotalLen( struct iovec * pVec, int count )
366{
367   struct iovec * pEnd = pVec + count;
368   int total = 0;
369   while( pVec < pEnd )
370   {
371       total += pVec->iov_len;
372       ++pVec;
373   }
374   return total;
375}
376*/
377
378static inline int allocateBuf( LSAPI_Request * pReq, int size )
379{
380    char * pBuf = (char *)realloc( pReq->m_pReqBuf, size );
381    if ( pBuf )
382    {
383        pReq->m_pReqBuf = pBuf;
384        pReq->m_reqBufSize = size;
385        pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf;
386        return 0;
387    }
388    return -1;
389}
390
391
392static int allocateIovec( LSAPI_Request * pReq, int n )
393{
394    struct iovec * p = (struct iovec *)realloc(
395                pReq->m_pIovec, sizeof(struct iovec) * n );
396    if ( !p )
397        return -1;
398    pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec );
399    pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec );
400    pReq->m_pIovec = p;
401    pReq->m_pIovecEnd = p + n;
402    return 0;
403}
404
405static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size )
406{
407    char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size );
408    if ( !p )
409        return -1;
410    pReq->m_pRespHeaderBufPos   = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf );
411    pReq->m_pRespHeaderBuf      = p;
412    pReq->m_pRespHeaderBufEnd   = p + size;
413    return 0;
414}
415
416
417static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType )
418{
419    if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )||
420        ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )||
421        ( pktType != pHeader->m_type ))
422        return -1;
423    if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT ))
424    {
425        register char b;
426        b = pHeader->m_packetLen.m_bytes[0];
427        pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3];
428        pHeader->m_packetLen.m_bytes[3] = b;
429        b = pHeader->m_packetLen.m_bytes[1];
430        pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2];
431        pHeader->m_packetLen.m_bytes[2] = b;
432    }
433    return pHeader->m_packetLen.m_iLen;
434}
435
436static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList,
437                        int *curSize, int newSize )
438{
439    struct LSAPI_key_value_pair * pBuf;
440        if ( *curSize >= newSize )
441        return 0;
442    if ( newSize > 8192 )
443        return -1;
444    pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize *
445                    sizeof(struct LSAPI_key_value_pair) );
446    if ( pBuf )
447    {
448        *pEnvList = pBuf;
449        *curSize  = newSize;
450        return 0;
451    }
452    else
453        return -1;
454
455}
456
457static inline int isPipe( int fd )
458{
459    char        achPeer[128];
460    socklen_t   len = 128;
461    if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
462        ( errno == ENOTCONN ))
463        return 0;
464    else
465        return 1;
466}
467
468static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
469            char **pBegin, char * pEnd )
470{
471    struct LSAPI_key_value_pair * pEnvEnd;
472        int keyLen = 0, valLen = 0;
473    if ( count > 8192 )
474        return -1;
475    pEnvEnd = pEnvList + count;
476    while( pEnvList != pEnvEnd )
477    {
478        if ( pEnd - *pBegin < 4 )
479            return -1;
480        keyLen = *((unsigned char *)((*pBegin)++));
481        keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++));
482        valLen = *((unsigned char *)((*pBegin)++));
483        valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++));
484        if ( *pBegin + keyLen + valLen > pEnd )
485            return -1;
486        if (( !keyLen )||( !valLen ))
487            return -1;
488
489        pEnvList->pKey = *pBegin;
490        *pBegin += keyLen;
491        pEnvList->pValue = *pBegin;
492        *pBegin += valLen;
493
494        pEnvList->keyLen = keyLen - 1;
495        pEnvList->valLen = valLen - 1;
496        ++pEnvList;
497    }
498    if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 )
499        return -1;
500    *pBegin += 4;
501    return 0;
502}
503
504static inline void swapIntEndian( int * pInteger )
505{
506    char * p = (char *)pInteger;
507    register char b;
508    b = p[0];
509    p[0] = p[3];
510    p[3] = b;
511    b = p[1];
512    p[1] = p[2];
513    p[2] = b;
514
515}
516
517static inline void fixEndian( LSAPI_Request * pReq )
518{
519    struct lsapi_req_header *p= pReq->m_pHeader;
520    swapIntEndian( &p->m_httpHeaderLen );
521    swapIntEndian( &p->m_reqBodyLen );
522    swapIntEndian( &p->m_scriptFileOff );
523    swapIntEndian( &p->m_scriptNameOff );
524    swapIntEndian( &p->m_queryStringOff );
525    swapIntEndian( &p->m_requestMethodOff );
526    swapIntEndian( &p->m_cntUnknownHeaders );
527    swapIntEndian( &p->m_cntEnv );
528    swapIntEndian( &p->m_cntSpecialEnv );
529}
530
531static void fixHeaderIndexEndian( LSAPI_Request * pReq )
532{
533    int i;
534    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
535    {
536        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
537        {
538            register char b;
539            char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]);
540            b = p[0];
541            p[0] = p[1];
542            p[1] = b;
543            swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] );
544        }
545    }
546    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
547    {
548        struct lsapi_header_offset * pCur, *pEnd;
549        pCur = pReq->m_pUnknownHeader;
550        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
551        while( pCur < pEnd )
552        {
553            swapIntEndian( &pCur->nameOff );
554            swapIntEndian( &pCur->nameLen );
555            swapIntEndian( &pCur->valueOff );
556            swapIntEndian( &pCur->valueLen );
557            ++pCur;
558        }
559    }
560}
561
562static uid_t s_uid = 0;
563static uid_t s_defaultUid;  //web server need set this
564static gid_t s_defaultGid;
565
566#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
567
568#define LSAPI_LVE_DISABLED  0
569#define LSAPI_LVE_ENABLED   1
570#define LSAPI_CAGEFS_ENABLED 2
571#define LSAPI_CAGEFS_NO_SUEXEC 3
572struct liblve;
573static int s_enable_lve = LSAPI_LVE_DISABLED;
574static struct liblve * s_lve = NULL;
575
576static void *s_liblve;
577static int (*fp_lve_is_available)(void) = NULL;
578static int (*fp_lve_instance_init)(struct liblve *) = NULL;
579static int (*fp_lve_destroy)(struct liblve *) = NULL;
580static int (*fp_lve_enter)(struct liblve *, uint32_t, int32_t, int32_t, uint32_t *) = NULL;
581static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL;
582static int (*fp_lve_jail)( struct passwd *, char *) = NULL;
583static int lsapi_load_lve_lib()
584{
585    s_liblve = dlopen("liblve.so.0", RTLD_LAZY);
586    if (s_liblve)
587    {
588        fp_lve_is_available = dlsym(s_liblve, "lve_is_available");
589        if (dlerror() == NULL)
590        {
591            if ( !(*fp_lve_is_available)() )
592            {
593                int uid = getuid();
594                if ( uid )
595                {
596                    setreuid( s_uid, uid );
597                    if ( !(*fp_lve_is_available)() )
598                        s_enable_lve = 0;
599                    setreuid( uid, s_uid );
600                }
601            }
602        }
603    }
604    else
605    {
606        s_enable_lve = LSAPI_LVE_DISABLED;
607    }
608    return (s_liblve)? 0 : -1;
609}
610
611static int init_lve_ex()
612{
613    int rc;
614    if ( !s_liblve )
615        return -1;
616    fp_lve_instance_init = dlsym(s_liblve, "lve_instance_init");
617    fp_lve_destroy = dlsym(s_liblve, "lve_destroy");
618    fp_lve_enter = dlsym(s_liblve, "lve_enter");
619    fp_lve_leave = dlsym(s_liblve, "lve_leave");
620    if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED )
621        fp_lve_jail = dlsym(s_liblve, "jail" );
622
623    if ( s_lve == NULL )
624    {
625        rc = (*fp_lve_instance_init)(NULL);
626        s_lve = malloc(rc);
627    }
628    rc = (*fp_lve_instance_init)(s_lve);
629    if (rc != 0)
630    {
631        perror( "LSAPI: Unable to initialize LVE" );
632        free( s_lve );
633        s_lve = NULL;
634        return -1;
635    }
636    return 0;
637
638}
639
640#endif
641
642
643
644static int readSecret( const char * pSecretFile )
645{
646    struct stat st;
647    int fd = open( pSecretFile, O_RDONLY , 0600 );
648    if ( fd == -1 )
649    {
650        fprintf( stderr, "LSAPI: failed to open secret file: %s!\n", pSecretFile );
651        return -1;
652    }
653    if ( fstat( fd, &st ) == -1 )
654    {
655        fprintf( stderr, "LSAPI: failed to check state of file: %s!\n", pSecretFile );
656        close( fd );
657        return -1;
658    }
659/*
660    if ( st.st_uid != s_uid )
661    {
662        fprintf( stderr, "LSAPI: file owner check failure: %s!\n", pSecretFile );
663        close( fd );
664        return -1;
665    }
666*/
667    if ( st.st_mode & 0077 )
668    {
669        fprintf( stderr, "LSAPI: file permission check failure: %s\n", pSecretFile );
670        close( fd );
671        return -1;
672    }
673    if ( read( fd, s_pSecret, 16 ) < 16 )
674    {
675        fprintf( stderr, "LSAPI: failed to read secret from secret file: %s\n", pSecretFile );
676        close( fd );
677        return -1;
678    }
679    close( fd );
680    return 0;
681}
682
683int LSAPI_is_suEXEC_Daemon()
684{
685    if (( !s_uid )&&( s_pSecret[0] ))
686        return 1;
687    else
688        return 0;
689}
690
691static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char *pErr2 )
692{
693    char achError[1024];
694    int n = snprintf(achError, 1024, "%s:%s: %s\n", pErr1, (pErr2)?pErr2:"", strerror( errno ) );
695    if ( pReq )
696        LSAPI_Write_Stderr_r( pReq, achError, n );
697    else
698        write( STDERR_FILENO, achError, n );
699    return 0;
700}
701
702static int lsapi_lve_error( LSAPI_Request * pReq )
703{
704    static const char * headers[] =
705    {
706        "Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0",
707        "Pragma: no-cache",
708        "Retry-After: 60",
709        "Content-Type: text/html",
710        NULL
711    };
712    static const char achBody[] =
713        "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
714        "<HTML><HEAD>\n<TITLE>508 Resource Limit Is Reached</TITLE>\n"
715        "</HEAD><BODY>\n" "<H1>Resource Limit Is Reached</H1>\n"
716        "The website is temporarily unable to service your request as it exceeded resource limit.\n"
717        "Please try again later.\n"
718        "<HR>\n"
719        "</BODY></HTML>\n";
720
721    LSAPI_ErrResponse_r( pReq, 508, headers, achBody, sizeof( achBody ) - 1 );
722    return 0;
723}
724
725static int lsapi_enterLVE( LSAPI_Request * pReq, uid_t uid )
726{
727#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
728    if ( s_lve && uid ) //root user should not do that
729    {
730        uint32_t cookie;
731        int ret = -1;
732        ret = (*fp_lve_enter)(s_lve, uid, -1, -1, &cookie);
733        if ( ret < 0 )
734        {
735            fprintf( stderr, "Pid (%d): enter LVE (%d) : ressult: %d !\n", getpid(), uid, ret );
736            LSAPI_perror_r(pReq, "LSAPI: lve_enter() failure, reached resource limit.", NULL );
737            lsapi_lve_error( pReq );
738            return -1;
739        }
740    }
741#endif
742
743    return 0;
744}
745
746static int lsapi_jailLVE( LSAPI_Request * pReq, uid_t uid, struct passwd * pw )
747{
748    int ret = 0;
749#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
750    char  error_msg[1024] = "";
751    ret = (*fp_lve_jail)( pw, error_msg );
752    if ( ret < 0 )
753    {
754        fprintf( stderr, "LSAPI (%d): LVE jail(%d) ressult: %d, error: %s !\n",
755                        getpid(), uid, ret, error_msg );
756        LSAPI_perror_r( pReq, "LSAPI: jail() failure.", NULL );
757        return -1;
758    }
759#endif
760    return ret;
761}
762
763
764#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
765static int lsapi_initLVE()
766{
767    const char * pEnv;
768    if ( (pEnv = getenv( "LSAPI_LVE_ENABLE" ))!= NULL )
769    {
770        s_enable_lve = atol( pEnv );
771        pEnv = NULL;
772    }
773    else if ( (pEnv = getenv( "LVE_ENABLE" ))!= NULL )
774    {
775        s_enable_lve = atol( pEnv );
776        pEnv = NULL;
777    }
778    if ( s_enable_lve && !s_uid )
779    {
780        lsapi_load_lve_lib();
781        if ( s_enable_lve )
782        {
783            return init_lve_ex();
784        }
785
786    }
787    return 0;
788}
789#endif
790
791
792static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * pChroot)
793{
794    int rv;
795    struct passwd * pw;
796    pw = getpwuid( uid );
797#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
798    if ( s_lve )
799    {
800        if( lsapi_enterLVE( pReq, uid ) == -1 )
801            return -1;
802        if ( pw && fp_lve_jail)
803        {
804            rv = lsapi_jailLVE( pReq, uid, pw );
805            if ( rv == -1 )
806                return -1;
807            if (( rv == 1 )&&(s_enable_lve == LSAPI_CAGEFS_NO_SUEXEC ))    //this mode only use cageFS, does not use suEXEC
808            {
809                uid = s_defaultUid;
810                gid = s_defaultGid;
811                pw = getpwuid( uid );
812            }
813        }
814    }
815#endif
816    //if ( !uid || !gid )  //do not allow root
817    //{
818    //    return -1;
819    //}
820
821#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
822    || defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
823    if ( s_enable_core_dump )
824        lsapi_enable_core_dump();
825#endif
826
827    rv = setgid(gid);
828    if (rv == -1)
829    {
830        LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL);
831        return -1;
832    }
833    if ( pw && (pw->pw_gid == gid ))
834    {
835        rv = initgroups( pw->pw_name, gid );
836        if (rv == -1)
837        {
838            LSAPI_perror_r(pReq, "LSAPI: initgroups()", NULL);
839            return -1;
840        }
841    }
842    else
843    {
844        rv = setgroups(1, &gid);
845        if (rv == -1)
846        {
847            LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL);
848        }
849    }
850    if ( pChroot )
851    {
852        rv = chroot( pChroot );
853        if ( rv == -1 )
854        {
855            LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL);
856            return -1;
857        }
858    }
859    rv = setuid(uid);
860    if (rv == -1)
861    {
862        LSAPI_perror_r(pReq, "LSAPI: setuid()", NULL);
863        return -1;
864    }
865#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
866    if ( s_enable_core_dump )
867        lsapi_enable_core_dump();
868#endif
869    return 0;
870}
871
872static int lsapi_suexec_auth( LSAPI_Request *pReq,
873            char * pAuth, int len, char * pUgid, int ugidLen )
874{
875    lsapi_MD5_CTX md5ctx;
876    unsigned char achMD5[16];
877    if ( len < 32 )
878        return -1;
879    memmove( achMD5, pAuth + 16, 16 );
880    memmove( pAuth + 16, s_pSecret, 16 );
881    lsapi_MD5Init( &md5ctx );
882    lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 );
883    lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 );
884    lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx);
885    if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 )
886        return 0;
887    return 1;
888}
889
890
891static int lsapi_changeUGid( LSAPI_Request * pReq )
892{
893    int uid = s_defaultUid;
894    int gid = s_defaultGid;
895    const char * pChroot = NULL;
896    struct LSAPI_key_value_pair * pEnv;
897    struct LSAPI_key_value_pair * pAuth;
898    int i;
899    if ( s_uid )
900        return 0;
901    //with special ID  0x00
902    //authenticate the suEXEC request;
903    //first one should be MD5( nonce + lscgid secret )
904    //remember to clear the secret after verification
905    //it should be set at the end of special env
906    i = pReq->m_pHeader->m_cntSpecialEnv - 1;
907    if ( i >= 0 )
908    {
909        pEnv = pReq->m_pSpecialEnvList + i;
910        if (( *pEnv->pKey == '\000' )&&
911            ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 ))
912        {
913            --pReq->m_pHeader->m_cntSpecialEnv;
914            pAuth = pEnv--;
915            if (( *pEnv->pKey == '\000' )&&
916                ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 ))
917            {
918                --pReq->m_pHeader->m_cntSpecialEnv;
919                uid = *(uint32_t *)pEnv->pValue;
920                gid = *(((uint32_t *)pEnv->pValue) + 1 );
921                //fprintf( stderr, "LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid );
922            }
923            else
924            {
925                fprintf( stderr, "LSAPI: missing SUEXEC_UGID env, use default user!\n" );
926                pEnv = NULL;
927            }
928            if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 )
929            {
930                //read UID, GID from specialEnv
931
932            }
933            else
934            {
935                //authentication error
936                fprintf( stderr, "LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" );
937                uid = 0;
938            }
939        }
940        else
941        {
942            //fprintf( stderr, "LSAPI: no SUEXEC_AUTH env, use default user!\n" );
943        }
944    }
945
946
947    if ( !uid )
948    {
949        uid = s_defaultUid;
950        gid = s_defaultGid;
951    }
952
953    //change uid
954    if ( setUID_LVE( pReq, uid, gid, pChroot ) == -1 )
955    {
956        return -1;
957    }
958
959    s_uid = uid;
960
961    return 0;
962
963}
964
965static int parseContentLenFromHeader(LSAPI_Request * pReq)
966{
967    const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH );
968    if ( pContentLen )
969        pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 );
970    return 0;
971}
972
973
974static int parseRequest( LSAPI_Request * pReq, int totalLen )
975{
976    int shouldFixEndian;
977    char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header );
978    char * pEnd = pReq->m_pReqBuf + totalLen;
979    shouldFixEndian = ( LSAPI_ENDIAN != (
980                pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) );
981    if ( shouldFixEndian )
982    {
983        fixEndian( pReq );
984    }
985    if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&&
986            allocateEnvList( &pReq->m_pSpecialEnvList,
987                &pReq->m_specialEnvListSize,
988                pReq->m_pHeader->m_cntSpecialEnv ) == -1 )
989        return -1;
990    if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&&
991            allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize,
992                pReq->m_pHeader->m_cntEnv ) == -1 )
993        return -1;
994
995    if ( parseEnv( pReq->m_pSpecialEnvList,
996                pReq->m_pHeader->m_cntSpecialEnv,
997                &pBegin, pEnd ) == -1 )
998        return -1;
999    if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
1000                &pBegin, pEnd ) == -1 )
1001        return -1;
1002
1003    pReq->m_pScriptFile     = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff;
1004    pReq->m_pScriptName     = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff;
1005    pReq->m_pQueryString    = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff;
1006    pReq->m_pRequestMethod  = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff;
1007
1008    pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7));
1009    pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin;
1010    pBegin += sizeof( struct lsapi_http_header_index );
1011
1012    pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin;
1013    pBegin += sizeof( struct lsapi_header_offset) *
1014                    pReq->m_pHeader->m_cntUnknownHeaders;
1015
1016    pReq->m_pHttpHeader = pBegin;
1017    pBegin += pReq->m_pHeader->m_httpHeaderLen;
1018    if ( pBegin != pEnd )
1019    {
1020        fprintf( stderr, "%d: request header does match total size, total: %d, real: %ld\n", getpid(), totalLen,
1021                    pBegin - pReq->m_pReqBuf );
1022        return -1;
1023    }
1024    if ( shouldFixEndian )
1025    {
1026        fixHeaderIndexEndian( pReq );
1027    }
1028    pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen;
1029    if ( pReq->m_reqBodyLen == -2 )
1030    {
1031        parseContentLenFromHeader(pReq);
1032    }
1033
1034    return 0;
1035}
1036
1037//OPTIMIZATION
1038static char s_accept_notify = 0;
1039static char s_schedule_notify = 0;
1040static char s_notify_scheduled = 0;
1041static char s_notified_pid = 0;
1042
1043static struct lsapi_packet_header s_ack = {'L', 'S',
1044                LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
1045
1046
1047static inline int write_req_received_notification( int fd )
1048{
1049    if ( write( fd, &s_ack, LSAPI_PACKET_HEADER_LEN )
1050                < LSAPI_PACKET_HEADER_LEN )
1051        return -1;
1052    return 0;
1053}
1054
1055static void lsapi_sigalarm( int sig )
1056{
1057    if ( s_notify_scheduled )
1058    {
1059        s_notify_scheduled = 0;
1060        if ( g_req.m_fd != -1 )
1061            write_req_received_notification( g_req.m_fd );
1062    }
1063}
1064
1065static inline int lsapi_schedule_notify()
1066{
1067    if ( !s_notify_scheduled )
1068    {
1069        alarm( 2 );
1070        s_notify_scheduled = 1;
1071    }
1072    return 0;
1073}
1074
1075static inline int notify_req_received( int fd )
1076{
1077    if ( s_schedule_notify )
1078        return lsapi_schedule_notify();
1079    return write_req_received_notification( fd );
1080
1081}
1082
1083
1084static inline int lsapi_notify_pid( int fd )
1085{
1086    char achBuf[16];
1087    lsapi_buildPacketHeader( (struct lsapi_packet_header *)achBuf, LSAPI_STDERR_STREAM,
1088                        8 + LSAPI_PACKET_HEADER_LEN );
1089    memmove( &achBuf[8], "\0PID", 4 );
1090    *((int *)&achBuf[12]) = getpid();
1091
1092    if ( write( fd, achBuf, 16 ) < 16 )
1093        return -1;
1094    return 0;
1095}
1096
1097static char s_conn_key_packet[16];
1098static inline int init_conn_key( int fd )
1099{
1100    struct lsapi_packet_header * pHeader = (struct lsapi_packet_header *)s_conn_key_packet;
1101    struct timeval tv;
1102    int i;
1103    gettimeofday( &tv, NULL );
1104    srand( (tv.tv_sec % 0x1000 + tv.tv_usec) ^ rand() );
1105    for( i = 8; i < 16; ++i )
1106    {
1107        s_conn_key_packet[i]=(int) (256.0*rand()/(RAND_MAX+1.0));
1108    }
1109    lsapi_buildPacketHeader( pHeader, LSAPI_REQ_RECEIVED,
1110                        8 + LSAPI_PACKET_HEADER_LEN );
1111    if ( write( fd, s_conn_key_packet, LSAPI_PACKET_HEADER_LEN+8 )
1112                < LSAPI_PACKET_HEADER_LEN+8 )
1113        return -1;
1114    return 0;
1115
1116
1117}
1118
1119static int readReq( LSAPI_Request * pReq )
1120{
1121    int len;
1122    int packetLen;
1123    if ( !pReq )
1124        return -1;
1125    if ( pReq->m_reqBufSize < 8192 )
1126    {
1127        if ( allocateBuf( pReq, 8192 ) == -1 )
1128            return -1;
1129    }
1130
1131    while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN )
1132    {
1133        len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize );
1134        if ( len <= 0 )
1135            return -1;
1136        pReq->m_bufRead += len;
1137    }
1138    pReq->m_reqState = LSAPI_ST_REQ_HEADER;
1139
1140    packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST );
1141    if ( packetLen < 0 )
1142    {
1143        fprintf( stderr, "%d: packetLen < 0\n", getpid() );
1144        return -1;
1145    }
1146    if ( packetLen > LSAPI_MAX_HEADER_LEN )
1147    {
1148        fprintf( stderr, "%d: packetLen > %d\n", getpid(), LSAPI_MAX_HEADER_LEN );
1149        return -1;
1150    }
1151
1152    if ( packetLen + 1024 > pReq->m_reqBufSize )
1153    {
1154        if ( allocateBuf( pReq, packetLen + 1024 ) == -1 )
1155            return -1;
1156    }
1157    while( packetLen > pReq->m_bufRead )
1158    {
1159        len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead );
1160        if ( len <= 0 )
1161            return -1;
1162        pReq->m_bufRead += len;
1163    }
1164    if ( parseRequest( pReq, packetLen ) < 0 )
1165    {
1166        fprintf( stderr, "%d: parseRequest error\n", getpid() );
1167        return -1;
1168    }
1169
1170    pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER;
1171
1172    if ( !s_uid )
1173        if ( lsapi_changeUGid( pReq ) )
1174            return -1;
1175    pReq->m_bufProcessed = packetLen;
1176
1177    //OPTIMIZATION
1178    if ( !s_accept_notify && !s_notified_pid )
1179        return notify_req_received( pReq->m_fd );
1180    else
1181    {
1182        s_notified_pid = 0;
1183        return 0;
1184    }
1185}
1186
1187
1188
1189int LSAPI_Init(void)
1190{
1191    if ( !g_inited )
1192    {
1193        s_uid = geteuid();
1194        s_pSecret[0] = 0;
1195        lsapi_signal(SIGPIPE, lsapi_sigpipe);
1196        lsapi_signal(SIGUSR1, lsapi_siguser1);
1197
1198#if defined(SIGXFSZ) && defined(SIG_IGN)
1199        signal(SIGXFSZ, SIG_IGN);
1200#endif
1201        /* let STDOUT function as STDERR,
1202           just in case writing to STDOUT directly */
1203        dup2( 2, 1 );
1204        if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 )
1205            return -1;
1206        g_inited = 1;
1207        s_ppid = getppid();
1208    }
1209    return 0;
1210}
1211
1212void LSAPI_Stop(void)
1213{
1214    g_running = 0;
1215}
1216
1217int LSAPI_IsRunning(void)
1218{
1219    return g_running;
1220}
1221
1222int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
1223{
1224    int newfd;
1225    if ( !pReq )
1226        return -1;
1227    memset( pReq, 0, sizeof( LSAPI_Request ) );
1228    if ( allocateIovec( pReq, 16 ) == -1 )
1229        return -1;
1230    pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE );
1231    if ( !pReq->m_pRespBuf )
1232        return -1;
1233    pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE;
1234    pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
1235    pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5];
1236    if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 )
1237        return -1;
1238
1239    if ( fd == STDIN_FILENO )
1240    {
1241        fd = dup( fd );
1242        newfd = open( "/dev/null", O_RDWR );
1243        dup2( newfd, STDIN_FILENO );
1244    }
1245
1246    if ( isPipe( fd ) )
1247    {
1248        pReq->m_fdListen = -1;
1249        pReq->m_fd = fd;
1250    }
1251    else
1252    {
1253        pReq->m_fdListen = fd;
1254        pReq->m_fd = -1;
1255        lsapi_set_nblock( fd, 1 );
1256    }
1257    return 0;
1258}
1259
1260int LSAPI_Is_Listen( void )
1261{
1262    return LSAPI_Is_Listen_r( &g_req );
1263}
1264
1265int LSAPI_Is_Listen_r( LSAPI_Request * pReq)
1266{
1267    return pReq->m_fdListen != -1;
1268}
1269
1270
1271
1272int LSAPI_Accept_r( LSAPI_Request * pReq )
1273{
1274    char        achPeer[128];
1275    socklen_t   len;
1276    int         nodelay = 1;
1277
1278    if ( !pReq )
1279        return -1;
1280    if ( LSAPI_Finish_r( pReq ) == -1 )
1281        return -1;
1282    lsapi_set_nblock( pReq->m_fdListen , 0 );
1283    while( g_running )
1284    {
1285        if ( pReq->m_fd == -1 )
1286        {
1287            if ( pReq->m_fdListen != -1)
1288            {
1289                len = sizeof( achPeer );
1290                pReq->m_fd = accept( pReq->m_fdListen,
1291                            (struct sockaddr *)&achPeer, &len );
1292                if ( pReq->m_fd == -1 )
1293                {
1294                    if (( errno == EINTR )||( errno == EAGAIN))
1295                        continue;
1296                    else
1297                        return -1;
1298                }
1299                else
1300                {
1301                    lsapi_set_nblock( pReq->m_fd , 0 );
1302                    if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
1303                    {
1304                        setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY,
1305                                   (char *)&nodelay, sizeof(nodelay));
1306                    }
1307                    //init_conn_key( pReq->m_fd );
1308                    //OPTIMIZATION
1309                    if ( s_accept_notify )
1310                        if ( notify_req_received( pReq->m_fd ) == -1 )
1311                                return -1;
1312                }
1313            }
1314            else
1315                return -1;
1316        }
1317        if ( !readReq( pReq ) )
1318            break;
1319        //abort();
1320        lsapi_close( pReq->m_fd );
1321        pReq->m_fd = -1;
1322        LSAPI_Reset_r( pReq );
1323    }
1324    return 0;
1325}
1326
1327static struct lsapi_packet_header   finish = {'L', 'S',
1328                LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
1329
1330int LSAPI_Finish_r( LSAPI_Request * pReq )
1331{
1332    /* finish req body */
1333    if ( !pReq )
1334        return -1;
1335    if (pReq->m_reqState)
1336    {
1337        if ( pReq->m_fd != -1 )
1338        {
1339            if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
1340            {
1341                LSAPI_FinalizeRespHeaders_r( pReq );
1342            }
1343            if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
1344            {
1345                Flush_RespBuf_r( pReq );
1346            }
1347
1348            pReq->m_pIovecCur->iov_base = (void *)&finish;
1349            pReq->m_pIovecCur->iov_len  = LSAPI_PACKET_HEADER_LEN;
1350            pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN;
1351            ++pReq->m_pIovecCur;
1352            LSAPI_Flush_r( pReq );
1353        }
1354        LSAPI_Reset_r( pReq );
1355    }
1356    return 0;
1357}
1358
1359
1360void LSAPI_Reset_r( LSAPI_Request * pReq )
1361{
1362    pReq->m_pRespBufPos         = pReq->m_pRespBuf;
1363    pReq->m_pIovecCur           = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
1364    pReq->m_pRespHeaderBufPos   = pReq->m_pRespHeaderBuf;
1365
1366    memset( &pReq->m_pHeaderIndex, 0,
1367            (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex );
1368}
1369
1370
1371int LSAPI_Release_r( LSAPI_Request * pReq )
1372{
1373    if ( pReq->m_pReqBuf )
1374        free( pReq->m_pReqBuf );
1375    if ( pReq->m_pSpecialEnvList )
1376        free( pReq->m_pSpecialEnvList );
1377    if ( pReq->m_pEnvList )
1378        free( pReq->m_pEnvList );
1379    if ( pReq->m_pRespHeaderBuf )
1380        free( pReq->m_pRespHeaderBuf );
1381    return 0;
1382}
1383
1384
1385char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
1386{
1387    int off;
1388    if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) )
1389        return NULL;
1390    off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ];
1391    if ( !off )
1392        return NULL;
1393        if ( *(pReq->m_pHttpHeader + off +
1394                 pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) )
1395                *( pReq->m_pHttpHeader + off +
1396                        pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
1397    return pReq->m_pHttpHeader + off;
1398}
1399
1400static int readBodyToReqBuf( LSAPI_Request * pReq )
1401{
1402    off_t bodyLeft;
1403    ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed;
1404    if ( len > 0 )
1405        return len;
1406    pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen;
1407
1408    bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
1409    len = pReq->m_reqBufSize - pReq->m_bufRead;
1410    if ( len < 0 )
1411        return -1;
1412    if ( len > bodyLeft )
1413        len = bodyLeft;
1414
1415    len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len );
1416    if ( len > 0 )
1417        pReq->m_bufRead += len;
1418    return len;
1419}
1420
1421
1422int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq )
1423{
1424    if (!pReq || (pReq->m_fd ==-1) )
1425        return EOF;
1426    if ( pReq->m_bufProcessed >= pReq->m_bufRead )
1427    {
1428        if ( readBodyToReqBuf( pReq ) <= 0 )
1429            return EOF;
1430    }
1431    ++pReq->m_reqBodyRead;
1432    return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++);
1433}
1434
1435
1436
1437int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, int *getLF )
1438{
1439    ssize_t len;
1440    ssize_t left;
1441    char * pBufEnd = pBuf + bufLen - 1;
1442    char * pBufCur = pBuf;
1443    char * pCur;
1444    char * p;
1445    if (!pReq || (pReq->m_fd ==-1) ||( !pBuf )||(bufLen < 0 )|| !getLF )
1446        return -1;
1447    *getLF = 0;
1448    while( (left = pBufEnd - pBufCur ) > 0 )
1449    {
1450
1451        len = pReq->m_bufRead - pReq->m_bufProcessed;
1452        if ( len <= 0 )
1453        {
1454            if ( (len = readBodyToReqBuf( pReq )) <= 0 )
1455            {
1456                *getLF = 1;
1457                break;
1458            }
1459        }
1460        if ( len > left )
1461            len = left;
1462        pCur = pReq->m_pReqBuf + pReq->m_bufProcessed;
1463        p = memchr( pCur, '\n', len );
1464        if ( p )
1465            len = p - pCur + 1;
1466        memmove( pBufCur, pCur, len );
1467        pBufCur += len;
1468        pReq->m_bufProcessed += len;
1469
1470        pReq->m_reqBodyRead += len;
1471
1472        if ( p )
1473        {
1474            *getLF = 1;
1475            break;
1476        }
1477    }
1478    *pBufCur = 0;
1479
1480    return pBufCur - pBuf;
1481}
1482
1483
1484ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen )
1485{
1486    ssize_t len;
1487    off_t total;
1488    /* char *pOldBuf = pBuf; */
1489    if (!pReq || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 ))
1490        return -1;
1491
1492    total = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
1493
1494    if ( total <= 0 )
1495        return 0;
1496    if ( total < bufLen )
1497        bufLen = total;
1498
1499    total = 0;
1500    len = pReq->m_bufRead - pReq->m_bufProcessed;
1501    if ( len > 0 )
1502    {
1503        if ( len > bufLen )
1504            len = bufLen;
1505        memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len );
1506        pReq->m_bufProcessed += len;
1507        total += len;
1508        pBuf += len;
1509        bufLen -= len;
1510    }
1511    while( bufLen > 0 )
1512    {
1513        len = lsapi_read( pReq->m_fd, pBuf, bufLen );
1514        if ( len > 0 )
1515        {
1516            total += len;
1517            pBuf += len;
1518            bufLen -= len;
1519        }
1520        else if ( len <= 0 )
1521        {
1522            if ( !total)
1523                return -1;
1524            break;
1525        }
1526    }
1527    pReq->m_reqBodyRead += total;
1528    return total;
1529
1530}
1531
1532
1533ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
1534{
1535    struct lsapi_packet_header * pHeader;
1536    const char * pEnd;
1537    const char * p;
1538    ssize_t bufLen;
1539    ssize_t toWrite;
1540    ssize_t packetLen;
1541    int skip = 0;
1542
1543    if ( !pReq || !pBuf || (pReq->m_fd == -1) )
1544        return -1;
1545    if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
1546    {
1547        LSAPI_FinalizeRespHeaders_r( pReq );
1548/*
1549        if ( *pBuf == '\r' )
1550        {
1551            ++skip;
1552        }
1553        if ( *pBuf == '\n' )
1554        {
1555            ++skip;
1556        }
1557*/
1558    }
1559    pReq->m_reqState |= LSAPI_ST_RESP_BODY;
1560
1561    if ( (len - skip) < pReq->m_pRespBufEnd - pReq->m_pRespBufPos )
1562    {
1563        memmove( pReq->m_pRespBufPos, pBuf + skip, len - skip );
1564        pReq->m_pRespBufPos += len - skip;
1565        return len;
1566    }
1567
1568
1569    pHeader = pReq->m_respPktHeader;
1570    p       = pBuf + skip;
1571    pEnd    = pBuf + len;
1572    bufLen  = pReq->m_pRespBufPos - pReq->m_pRespBuf;
1573
1574    while( ( toWrite = pEnd - p ) > 0 )
1575    {
1576        packetLen = toWrite + bufLen;
1577        if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
1578        {
1579            packetLen = LSAPI_MAX_DATA_PACKET_LEN;
1580            toWrite = packetLen - bufLen;
1581        }
1582
1583        lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
1584                            packetLen + LSAPI_PACKET_HEADER_LEN );
1585        pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN;
1586
1587        pReq->m_pIovecCur->iov_base = (void *)pHeader;
1588        pReq->m_pIovecCur->iov_len  = LSAPI_PACKET_HEADER_LEN;
1589        ++pReq->m_pIovecCur;
1590        ++pHeader;
1591        if ( bufLen > 0 )
1592        {
1593            pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
1594            pReq->m_pIovecCur->iov_len  = bufLen;
1595            pReq->m_pRespBufPos = pReq->m_pRespBuf;
1596            ++pReq->m_pIovecCur;
1597            bufLen = 0;
1598        }
1599
1600        pReq->m_pIovecCur->iov_base = (void *)p;
1601        pReq->m_pIovecCur->iov_len  = toWrite;
1602        ++pReq->m_pIovecCur;
1603        p += toWrite;
1604
1605        if ( pHeader >= pReq->m_respPktHeaderEnd - 1)
1606        {
1607            if ( LSAPI_Flush_r( pReq ) == -1 )
1608                return -1;
1609            pHeader = pReq->m_respPktHeader;
1610        }
1611    }
1612    if ( pHeader != pReq->m_respPktHeader )
1613        if ( LSAPI_Flush_r( pReq ) == -1 )
1614            return -1;
1615    return p - pBuf;
1616}
1617
1618#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__)
1619ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
1620{
1621    ssize_t ret;
1622    off_t written;
1623    ret = sendfile( fdIn, fdOut, *off, size, NULL, &written, 0 );
1624    if ( written > 0 )
1625    {
1626        ret = written;
1627        *off += ret;
1628    }
1629    return ret;
1630}
1631#endif
1632
1633#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
1634ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
1635{
1636    ssize_t ret;
1637    off_t len = size;
1638    ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 );
1639    if (( ret == 0 )&&( len > 0 ))
1640    {
1641        ret = len;
1642        *off += len;
1643    }
1644    return ret;
1645}
1646#endif
1647
1648#if defined(sun) || defined(__sun)
1649#include <sys/sendfile.h>
1650ssize_t gsendfile( int fdOut, int fdIn, off_t *off, size_t size )
1651{
1652    int n = 0 ;
1653    sendfilevec_t vec[1];
1654
1655    vec[n].sfv_fd   = fdIn;
1656    vec[n].sfv_flag = 0;
1657    vec[n].sfv_off  = *off;
1658    vec[n].sfv_len  = size;
1659    ++n;
1660
1661    size_t written;
1662    ssize_t ret = sendfilev( fdOut, vec, n, &written );
1663    if (( !ret )||( errno == EAGAIN ))
1664        ret = written;
1665    if ( ret > 0 )
1666        *off += ret;
1667    return ret;
1668}
1669#endif
1670
1671#if defined(linux) || defined(__linux) || defined(__linux__) || \
1672    defined(__gnu_linux__)
1673#include <sys/sendfile.h>
1674#define gsendfile sendfile
1675#endif
1676#if defined(HPUX)
1677ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size )
1678{
1679    return sendfile( fdOut, fdIn, off, size, NULL, 0 );
1680}
1681#endif
1682
1683ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size )
1684{
1685    struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
1686    if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 )
1687        return -1;
1688    if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
1689    {
1690        LSAPI_FinalizeRespHeaders_r( pReq );
1691    }
1692    pReq->m_reqState |= LSAPI_ST_RESP_BODY;
1693
1694    LSAPI_Flush_r(pReq);
1695
1696    lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
1697                            size + LSAPI_PACKET_HEADER_LEN );
1698
1699
1700    if (write(pReq->m_fd,  (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN)
1701        return -1;
1702
1703    return gsendfile( pReq->m_fd, fdIn, off, size );
1704}
1705
1706
1707void Flush_RespBuf_r( LSAPI_Request * pReq )
1708{
1709    struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
1710    int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
1711    pReq->m_reqState |= LSAPI_ST_RESP_BODY;
1712    lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
1713                        bufLen + LSAPI_PACKET_HEADER_LEN );
1714    pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN;
1715
1716    pReq->m_pIovecCur->iov_base = (void *)pHeader;
1717    pReq->m_pIovecCur->iov_len  = LSAPI_PACKET_HEADER_LEN;
1718    ++pReq->m_pIovecCur;
1719    ++pHeader;
1720    if ( bufLen > 0 )
1721    {
1722        pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
1723        pReq->m_pIovecCur->iov_len  = bufLen;
1724        pReq->m_pRespBufPos = pReq->m_pRespBuf;
1725        ++pReq->m_pIovecCur;
1726        bufLen = 0;
1727    }
1728}
1729
1730
1731
1732
1733int LSAPI_Flush_r( LSAPI_Request * pReq )
1734{
1735    int ret = 0;
1736    int n;
1737    if ( !pReq )
1738        return -1;
1739    n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
1740    if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf ))
1741        return 0;
1742    if ( pReq->m_fd == -1 )
1743    {
1744        pReq->m_pRespBufPos = pReq->m_pRespBuf;
1745        pReq->m_totalLen = 0;
1746        pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
1747        return -1;
1748    }
1749    if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
1750    {
1751        LSAPI_FinalizeRespHeaders_r( pReq );
1752    }
1753    if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
1754    {
1755        Flush_RespBuf_r( pReq );
1756    }
1757
1758    n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
1759    if ( n > 0 )
1760    {
1761
1762        ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite,
1763                  n, pReq->m_totalLen );
1764        if ( ret < pReq->m_totalLen )
1765        {
1766            lsapi_close( pReq->m_fd );
1767            pReq->m_fd = -1;
1768            ret = -1;
1769        }
1770        pReq->m_totalLen = 0;
1771        pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
1772    }
1773    return ret;
1774}
1775
1776
1777ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
1778{
1779    struct lsapi_packet_header header;
1780    const char * pEnd;
1781    const char * p;
1782    ssize_t packetLen;
1783    ssize_t totalLen;
1784    int ret;
1785    struct iovec iov[2];
1786    struct iovec *pIov;
1787
1788    if ( !pReq )
1789        return -1;
1790    if (( pReq->m_fd == -1 )||(pReq->m_fd == pReq->m_fdListen ))
1791        return write( 2, pBuf, len );
1792    if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
1793    {
1794        LSAPI_Flush_r( pReq );
1795    }
1796
1797    p       = pBuf;
1798    pEnd    = pBuf + len;
1799
1800    while( ( packetLen = pEnd - p ) > 0 )
1801    {
1802        if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen)
1803        {
1804            packetLen = LSAPI_MAX_DATA_PACKET_LEN;
1805        }
1806
1807        lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM,
1808                            packetLen + LSAPI_PACKET_HEADER_LEN );
1809        totalLen = packetLen + LSAPI_PACKET_HEADER_LEN;
1810
1811        iov[0].iov_base = (void *)&header;
1812        iov[0].iov_len  = LSAPI_PACKET_HEADER_LEN;
1813
1814        iov[1].iov_base = (void *)p;
1815        iov[1].iov_len  = packetLen;
1816        p += packetLen;
1817        pIov = iov;
1818        ret = lsapi_writev( pReq->m_fd, &pIov,
1819                  2, totalLen );
1820        if ( ret < totalLen )
1821        {
1822            lsapi_close( pReq->m_fd );
1823            pReq->m_fd = -1;
1824            ret = -1;
1825        }
1826    }
1827    return p - pBuf;
1828}
1829
1830static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
1831{
1832    int i;
1833    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
1834    {
1835        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
1836        {
1837            if ( strcmp( name, CGI_HEADERS[i] ) == 0 )
1838                return pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
1839        }
1840    }
1841    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
1842    {
1843        const char *p;
1844        char *pKey;
1845        char *pKeyEnd;
1846        int  keyLen;
1847        struct lsapi_header_offset * pCur, *pEnd;
1848        pCur = pReq->m_pUnknownHeader;
1849        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
1850        while( pCur < pEnd )
1851        {
1852            pKey = pReq->m_pHttpHeader + pCur->nameOff;
1853            keyLen = pCur->nameLen;
1854            pKeyEnd = pKey + keyLen;
1855            p = &name[5];
1856
1857            while(( pKey < pKeyEnd )&&( *p ))
1858            {
1859                char ch = toupper( *pKey );
1860                if ((ch != *p )||(( *p == '_' )&&( ch != '-')))
1861                    break;
1862                ++p; ++pKey;
1863            }
1864            if (( pKey == pKeyEnd )&& (!*p ))
1865                return pReq->m_pHttpHeader + pCur->valueOff;
1866            ++pCur;
1867        }
1868    }
1869    return NULL;
1870}
1871
1872
1873char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
1874{
1875    struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList;
1876    struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
1877    if ( !pReq || !name )
1878        return NULL;
1879    if ( strncmp( name, "HTTP_", 5 ) == 0 )
1880    {
1881        return GetHeaderVar( pReq, name );
1882    }
1883    while( pBegin < pEnd )
1884    {
1885        if ( strcmp( name, pBegin->pKey ) == 0 )
1886            return pBegin->pValue;
1887        ++pBegin;
1888    }
1889    return NULL;
1890}
1891
1892struct _headerInfo
1893{
1894    const char * _name;
1895    int          _nameLen;
1896    const char * _value;
1897    int          _valueLen;
1898};
1899
1900int compareValueLocation(const void * v1, const void *v2 )
1901{
1902    return ((const struct _headerInfo *)v1)->_value -
1903           ((const struct _headerInfo *)v2)->_value;
1904}
1905
1906int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq,
1907            LSAPI_CB_EnvHandler fn, void * arg )
1908{
1909    int i;
1910    int len = 0;
1911    char * pValue;
1912    int ret;
1913    int count = 0;
1914    struct _headerInfo headers[512];
1915    if ( !pReq || !fn )
1916        return -1;
1917
1918    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
1919    {
1920        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
1921        {
1922            len = pReq->m_pHeaderIndex->m_headerLen[i];
1923            pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
1924            *(pValue + len ) = 0;
1925            headers[count]._name = HTTP_HEADERS[i];
1926            headers[count]._nameLen = HTTP_HEADER_LEN[i];
1927            headers[count]._value = pValue;
1928            headers[count]._valueLen = len;
1929            ++count;
1930
1931            //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i],
1932            //            pValue, len, arg );
1933            //if ( ret <= 0 )
1934            //    return ret;
1935        }
1936    }
1937    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
1938    {
1939        char *pKey;
1940        int  keyLen;
1941        struct lsapi_header_offset * pCur, *pEnd;
1942        pCur = pReq->m_pUnknownHeader;
1943        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
1944        while( pCur < pEnd )
1945        {
1946            pKey = pReq->m_pHttpHeader + pCur->nameOff;
1947            keyLen = pCur->nameLen;
1948            *(pKey + keyLen ) = 0;
1949
1950            pValue = pReq->m_pHttpHeader + pCur->valueOff;
1951            *(pValue + pCur->valueLen ) = 0;
1952            headers[count]._name = pKey;
1953            headers[count]._nameLen = keyLen;
1954            headers[count]._value = pValue;
1955            headers[count]._valueLen = pCur->valueLen;
1956            ++count;
1957            if ( count == 512 )
1958                break;
1959            //ret = (*fn)( pKey, keyLen,
1960            //            pValue, pCur->valueLen, arg );
1961            //if ( ret <= 0 )
1962            //    return ret;
1963            ++pCur;
1964        }
1965    }
1966    qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation );
1967    for( i = 0; i < count; ++i )
1968    {
1969        ret = (*fn)( headers[i]._name, headers[i]._nameLen,
1970                    headers[i]._value, headers[i]._valueLen, arg );
1971        if ( ret <= 0 )
1972            return ret;
1973    }
1974    return count;
1975
1976}
1977
1978
1979int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
1980            LSAPI_CB_EnvHandler fn, void * arg )
1981{
1982    int i;
1983    int len = 0;
1984    char * pValue;
1985    int ret;
1986    int count = 0;
1987    if ( !pReq || !fn )
1988        return -1;
1989    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
1990    {
1991        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
1992        {
1993            len = pReq->m_pHeaderIndex->m_headerLen[i];
1994            pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
1995            *(pValue + len ) = 0;
1996            ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
1997                        pValue, len, arg );
1998            ++count;
1999            if ( ret <= 0 )
2000                return ret;
2001        }
2002    }
2003    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
2004    {
2005        char achHeaderName[256];
2006        char *p;
2007        char *pKey;
2008        char *pKeyEnd ;
2009        int  keyLen;
2010        struct lsapi_header_offset * pCur, *pEnd;
2011        pCur = pReq->m_pUnknownHeader;
2012        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
2013        while( pCur < pEnd )
2014        {
2015            pKey = pReq->m_pHttpHeader + pCur->nameOff;
2016            keyLen = pCur->nameLen;
2017            if ( keyLen > 250 )
2018                keyLen = 250;
2019            pKeyEnd = pKey + keyLen;
2020            memcpy( achHeaderName, "HTTP_", 5 );
2021            p = &achHeaderName[5];
2022
2023            while( pKey < pKeyEnd )
2024            {
2025                char ch = *pKey++;
2026                if ( ch == '-' )
2027                    *p++ = '_';
2028                else
2029                    *p++ = toupper( ch );
2030            }
2031            *p = 0;
2032            keyLen += 5;
2033
2034            pValue = pReq->m_pHttpHeader + pCur->valueOff;
2035            *(pValue + pCur->valueLen ) = 0;
2036            ret = (*fn)( achHeaderName, keyLen,
2037                        pValue, pCur->valueLen, arg );
2038            if ( ret <= 0 )
2039                return ret;
2040            ++pCur;
2041        }
2042    }
2043    return count + pReq->m_pHeader->m_cntUnknownHeaders;
2044
2045}
2046
2047static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
2048            int n, LSAPI_CB_EnvHandler fn, void * arg )
2049{
2050    struct LSAPI_key_value_pair * pEnd = pEnv + n;
2051    int ret;
2052    if ( !pEnv || !fn )
2053        return -1;
2054    while( pEnv < pEnd )
2055    {
2056        ret = (*fn)( pEnv->pKey, pEnv->keyLen,
2057                    pEnv->pValue, pEnv->valLen, arg );
2058        if ( ret <= 0 )
2059            return ret;
2060        ++pEnv;
2061    }
2062    return n;
2063}
2064
2065
2066
2067int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
2068            LSAPI_CB_EnvHandler fn, void * arg )
2069{
2070    if ( !pReq || !fn )
2071        return -1;
2072    if ( pReq->m_pHeader->m_cntEnv > 0 )
2073    {
2074        return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
2075                    fn, arg );
2076    }
2077    return 0;
2078}
2079
2080
2081
2082int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
2083            LSAPI_CB_EnvHandler fn, void * arg )
2084{
2085    if ( !pReq || !fn )
2086        return -1;
2087    if ( pReq->m_pHeader->m_cntSpecialEnv > 0 )
2088    {
2089        return EnvForeach( pReq->m_pSpecialEnvList,
2090                pReq->m_pHeader->m_cntSpecialEnv,
2091                    fn, arg );
2092    }
2093    return 0;
2094
2095}
2096
2097
2098
2099int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
2100{
2101    if ( !pReq || !pReq->m_pIovec )
2102        return -1;
2103    if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) )
2104        return 0;
2105    pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER;
2106    if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf )
2107    {
2108        pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf;
2109        pReq->m_pIovecCur->iov_len  = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
2110        pReq->m_totalLen += pReq->m_pIovecCur->iov_len;
2111        ++pReq->m_pIovecCur;
2112    }
2113
2114    pReq->m_pIovec->iov_len  = sizeof( struct lsapi_resp_header)
2115            + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short );
2116    pReq->m_totalLen += pReq->m_pIovec->iov_len;
2117
2118    lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader,
2119                    LSAPI_RESP_HEADER, pReq->m_totalLen  );
2120    pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader;
2121    pReq->m_pIovecToWrite = pReq->m_pIovec;
2122    return 0;
2123}
2124
2125
2126int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
2127                              const char * pHeaderValue )
2128{
2129    int nameLen, valLen, len;
2130    if ( !pReq || !pHeaderName || !pHeaderValue )
2131        return -1;
2132    if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
2133        return -1;
2134    if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
2135        return -1;
2136    nameLen = strlen( pHeaderName );
2137    valLen = strlen( pHeaderValue );
2138    if ( nameLen == 0 )
2139        return -1;
2140    while( nameLen > 0 )
2141    {
2142        char ch = *(pHeaderName + nameLen - 1 );
2143        if (( ch == '\n' )||( ch == '\r' ))
2144            --nameLen;
2145        else
2146            break;
2147    }
2148    if ( nameLen <= 0 )
2149        return 0;
2150    while( valLen > 0 )
2151    {
2152        char ch = *(pHeaderValue + valLen - 1 );
2153        if (( ch == '\n' )||( ch == '\r' ))
2154            --valLen;
2155        else
2156            break;
2157    }
2158    len = nameLen + valLen + 1;
2159    if ( len > LSAPI_RESP_HTTP_HEADER_MAX )
2160        return -1;
2161
2162    if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
2163    {
2164        int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
2165        newlen -= newlen % 4096;
2166        if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2167            return -1;
2168    }
2169    memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen );
2170    pReq->m_pRespHeaderBufPos += nameLen;
2171    *pReq->m_pRespHeaderBufPos++ = ':';
2172    memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen );
2173    pReq->m_pRespHeaderBufPos += valLen;
2174    *pReq->m_pRespHeaderBufPos++ = 0;
2175    ++len;  /* add one byte padding for \0 */
2176    pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
2177    ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
2178    return 0;
2179}
2180
2181
2182
2183int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len )
2184{
2185    if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX )
2186        return -1;
2187    if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
2188        return -1;
2189    if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
2190        return -1;
2191    while( len > 0 )
2192    {
2193        char ch = *(pBuf + len - 1 );
2194        if (( ch == '\n' )||( ch == '\r' ))
2195            --len;
2196        else
2197            break;
2198    }
2199    if ( len <= 0 )
2200        return 0;
2201    if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
2202    {
2203        int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
2204        newlen -= newlen % 4096;
2205        if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2206            return -1;
2207    }
2208    memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
2209    pReq->m_pRespHeaderBufPos += len;
2210    *pReq->m_pRespHeaderBufPos++ = 0;
2211    ++len;  /* add one byte padding for \0 */
2212    pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
2213    ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
2214    return 0;
2215}
2216
2217
2218int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
2219{
2220    int ret;
2221    int fd;
2222    int flag = 1;
2223    int addr_len;
2224
2225    switch( pServerAddr->sa_family )
2226    {
2227    case AF_INET:
2228        addr_len = 16;
2229        break;
2230    case AF_INET6:
2231        addr_len = sizeof( struct sockaddr_in6 );
2232        break;
2233    case AF_UNIX:
2234        addr_len = sizeof( struct sockaddr_un );
2235        unlink( ((struct sockaddr_un *)pServerAddr)->sun_path );
2236        break;
2237    default:
2238        return -1;
2239    }
2240
2241    fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 );
2242    if ( fd == -1 )
2243        return -1;
2244
2245    fcntl( fd, F_SETFD, FD_CLOEXEC );
2246
2247    if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
2248                (char *)( &flag ), sizeof(flag)) == 0)
2249    {
2250        ret = bind( fd, pServerAddr, addr_len );
2251        if ( !ret )
2252        {
2253            ret = listen( fd, backlog );
2254            if ( !ret )
2255                return fd;
2256        }
2257    }
2258
2259    ret = errno;
2260    close(fd);
2261    errno = ret;
2262    return -1;
2263
2264}
2265
2266int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
2267{
2268    char achAddr[256];
2269    char * p = achAddr;
2270    char * pEnd;
2271    struct addrinfo *res, hints;
2272    int  doAddrInfo = 0;
2273    int port;
2274
2275    if ( !pBind )
2276        return -1;
2277
2278    while( isspace( *pBind ) )
2279        ++pBind;
2280
2281    strncpy( achAddr, pBind, 256 );
2282
2283    switch( *p )
2284    {
2285    case '/':
2286        pAddr->sa_family = AF_UNIX;
2287        strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p,
2288                sizeof(((struct sockaddr_un *)pAddr)->sun_path) );
2289        return 0;
2290
2291    case '[':
2292        pAddr->sa_family = AF_INET6;
2293        ++p;
2294        pEnd = strchr( p, ']' );
2295        if ( !pEnd )
2296            return -1;
2297        *pEnd++ = 0;
2298
2299        if ( *p == '*' )
2300        {
2301            strcpy( achAddr, "::" );
2302            p = achAddr;
2303        }
2304        doAddrInfo = 1;
2305        break;
2306
2307    default:
2308        pAddr->sa_family = AF_INET;
2309        pEnd = strchr( p, ':' );
2310        if ( !pEnd )
2311            return -1;
2312        *pEnd++ = 0;
2313
2314        doAddrInfo = 0;
2315        if ( *p == '*' )
2316        {
2317            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
2318        }
2319        else if (!strcasecmp( p, "localhost" ) )
2320            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
2321        else
2322        {
2323            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
2324            if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST)
2325            {
2326                doAddrInfo = 1;
2327            }
2328        }
2329        break;
2330    }
2331    if ( *pEnd == ':' )
2332        ++pEnd;
2333
2334    port = atoi( pEnd );
2335    if (( port <= 0 )||( port > 65535 ))
2336        return -1;
2337    if ( doAddrInfo )
2338    {
2339
2340        memset(&hints, 0, sizeof(hints));
2341
2342        hints.ai_family   = pAddr->sa_family;
2343        hints.ai_socktype = SOCK_STREAM;
2344        hints.ai_protocol = IPPROTO_TCP;
2345
2346        if ( getaddrinfo(p, NULL, &hints, &res) )
2347        {
2348            return -1;
2349        }
2350
2351        memcpy(pAddr, res->ai_addr, res->ai_addrlen);
2352        freeaddrinfo(res);
2353    }
2354
2355    if ( pAddr->sa_family == AF_INET )
2356        ((struct sockaddr_in *)pAddr)->sin_port = htons( port );
2357    else
2358        ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
2359    return 0;
2360
2361}
2362
2363int LSAPI_CreateListenSock( const char * pBind, int backlog )
2364{
2365    char serverAddr[128];
2366    int ret;
2367    int fd = -1;
2368    ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr );
2369    if ( !ret )
2370    {
2371        fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog );
2372    }
2373    return fd;
2374}
2375
2376static fn_select_t g_fnSelect = select;
2377
2378typedef struct _lsapi_child_status
2379{
2380    int     m_pid;
2381    long    m_tmStart;
2382
2383    volatile short   m_iKillSent;
2384    volatile short   m_inProcess;
2385    volatile int     m_iReqCounter;
2386
2387    volatile long    m_tmWaitBegin;
2388    volatile long    m_tmReqBegin;
2389    volatile long    m_tmLastCheckPoint;
2390}
2391lsapi_child_status;
2392
2393static lsapi_child_status * s_pChildStatus = NULL;
2394
2395typedef struct _lsapi_prefork_server
2396{
2397    int m_fd;
2398    int m_iMaxChildren;
2399    int m_iExtraChildren;
2400    int m_iCurChildren;
2401    int m_iMaxIdleChildren;
2402    int m_iServerMaxIdle;
2403    int m_iChildrenMaxIdleTime;
2404    int m_iMaxReqProcessTime;
2405    int m_iAvoidFork;
2406
2407    lsapi_child_status * m_pChildrenStatus;
2408    lsapi_child_status * m_pChildrenStatusCur;
2409    lsapi_child_status * m_pChildrenStatusEnd;
2410
2411}lsapi_prefork_server;
2412
2413static lsapi_prefork_server * g_prefork_server = NULL;
2414
2415int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
2416{
2417    int pid;
2418    if ( g_prefork_server )
2419        return 0;
2420    if ( max_children <= 1 )
2421        return -1;
2422    if ( max_children >= 10000)
2423        max_children = 10000;
2424
2425
2426    g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) );
2427    if ( !g_prefork_server )
2428        return -1;
2429    memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) );
2430
2431    if ( fp != NULL )
2432        g_fnSelect = fp;
2433
2434    s_ppid = getppid();
2435    pid = getpid();
2436    setpgid( pid, pid );
2437    g_prefork_server->m_iAvoidFork = avoidFork;
2438    g_prefork_server->m_iMaxChildren = max_children;
2439
2440    g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ;
2441    g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3);
2442    if ( g_prefork_server->m_iMaxIdleChildren == 0 )
2443        g_prefork_server->m_iMaxIdleChildren = 1;
2444    g_prefork_server->m_iChildrenMaxIdleTime = 300;
2445    g_prefork_server->m_iMaxReqProcessTime = 3600;
2446    return 0;
2447}
2448
2449void LSAPI_Set_Server_fd( int fd )
2450{
2451    if( g_prefork_server )
2452        g_prefork_server->m_fd = fd;
2453}
2454
2455
2456static int lsapi_accept( int fdListen )
2457{
2458    int         fd;
2459    int         nodelay = 1;
2460    socklen_t   len;
2461    char        achPeer[128];
2462
2463    len = sizeof( achPeer );
2464    fd = accept( fdListen, (struct sockaddr *)&achPeer, &len );
2465    if ( fd != -1 )
2466    {
2467        if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
2468        {
2469            setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
2470                    (char *)&nodelay, sizeof(nodelay));
2471        }
2472
2473        //OPTIMIZATION
2474        //if ( s_accept_notify )
2475        //    notify_req_received( fd );
2476    }
2477    return fd;
2478
2479}
2480
2481
2482
2483
2484static int s_req_processed = 0;
2485static int s_max_reqs = 10000;
2486static int s_max_idle_secs = 300;
2487
2488static int s_stop;
2489
2490static void lsapi_cleanup(int signal)
2491{
2492    s_stop = signal;
2493}
2494
2495static lsapi_child_status * find_child_status( int pid )
2496{
2497    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
2498    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd;
2499    while( pStatus < pEnd )
2500    {
2501        if ( pStatus->m_pid == pid )
2502        {
2503            if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur )
2504                g_prefork_server->m_pChildrenStatusCur = pStatus + 1;
2505            return pStatus;
2506        }
2507        ++pStatus;
2508    }
2509    return NULL;
2510}
2511
2512
2513
2514static void lsapi_sigchild( int signal )
2515{
2516    int status, pid;
2517    lsapi_child_status * child_status;
2518    while( 1 )
2519    {
2520        pid = waitpid( -1, &status, WNOHANG|WUNTRACED );
2521        if ( pid <= 0 )
2522        {
2523            break;
2524        }
2525        if ( WIFSIGNALED( status ))
2526        {
2527            int sig_num = WTERMSIG( status );
2528            int dump = WCOREDUMP( status );
2529            fprintf( stderr, "Child process with pid: %d was killed by signal: %d, core dump: %d\n", pid, sig_num, dump );
2530        }
2531        if ( pid == s_pid_dump_debug_info )
2532        {
2533            pid = 0;
2534            continue;
2535        }
2536        child_status = find_child_status( pid );
2537        if ( child_status )
2538        {
2539            child_status->m_pid = 0;
2540            --g_prefork_server->m_iCurChildren;
2541
2542        }
2543    }
2544    while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus )
2545            &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 ))
2546        --g_prefork_server->m_pChildrenStatusCur;
2547
2548}
2549
2550static int lsapi_init_children_status()
2551{
2552    int size = 4096;
2553
2554    char * pBuf;
2555    size = (g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren ) * sizeof( lsapi_child_status ) * 2;
2556    size = (size + 4095 ) / 4096 * 4096;
2557    pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
2558        MAP_ANON | MAP_SHARED, -1, 0 );
2559    if ( pBuf == MAP_FAILED )
2560    {
2561        perror( "Anonymous mmap() failed" );
2562        return -1;
2563    }
2564    memset( pBuf, 0, size );
2565    g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;
2566    g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf;
2567    g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + size / sizeof( lsapi_child_status );
2568    return 0;
2569}
2570
2571static void dump_debug_info( lsapi_child_status * pStatus, long tmCur )
2572{
2573    char achCmd[1024];
2574    if ( s_pid_dump_debug_info )
2575    {
2576        if ( kill( s_pid_dump_debug_info, 0 ) == 0 )
2577            return;
2578    }
2579    s_pid_dump_debug_info = fork();
2580
2581    fprintf( stderr, "[%s] Possible runaway process, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld\n",
2582                ctime(&tmCur), getpid(), pStatus->m_pid, pStatus->m_iReqCounter,
2583                tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart );
2584    snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" -ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2", pStatus->m_pid, pStatus->m_pid );
2585    if ( system( achCmd ) == -1 )
2586        perror( "system()" );
2587    exit( 0 );
2588}
2589
2590static void lsapi_check_child_status( long tmCur )
2591{
2592    int idle = 0;
2593    int tobekilled;
2594    int dying = 0;
2595    int count = 0;
2596    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
2597    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur;
2598    while( pStatus < pEnd )
2599    {
2600        tobekilled = 0;
2601        if ( pStatus->m_pid != 0 )
2602        {
2603            ++count;
2604            if ( !pStatus->m_inProcess )
2605            {
2606
2607                if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)||
2608                    ( idle > g_prefork_server->m_iMaxIdleChildren ))
2609                {
2610                    ++pStatus->m_iKillSent;
2611                    //tobekilled = SIGUSR1;
2612                }
2613                else
2614                {
2615                    if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 ))
2616                    {
2617                        ++pStatus->m_iKillSent;
2618                        //tobekilled = SIGUSR1;
2619                    }
2620                }
2621                if ( !tobekilled )
2622                    ++idle;
2623            }
2624            else
2625            {
2626                if ( tmCur - pStatus->m_tmReqBegin >
2627                        g_prefork_server->m_iMaxReqProcessTime )
2628                {
2629                    if (( ( pStatus->m_iKillSent % 5 ) == 0 )&&( s_dump_debug_info ))
2630                        dump_debug_info( pStatus, tmCur );
2631                    if ( pStatus->m_iKillSent > 5 )
2632                    {
2633                        tobekilled = SIGKILL;
2634                        fprintf( stderr, "Force killing runaway process PID: %d with SIGKILL\n", pStatus->m_pid );
2635                    }
2636                    else
2637                    {
2638                        tobekilled = SIGTERM;
2639                        fprintf( stderr, "Killing runaway process PID: %d with SIGTERM\n", pStatus->m_pid );
2640                    }
2641                }
2642            }
2643            if ( tobekilled )
2644            {
2645                if (( kill( pStatus->m_pid, tobekilled ) == -1 )&&( errno == ESRCH ))
2646                {
2647                    pStatus->m_pid = 0;
2648                    --count;
2649                }
2650                else
2651                {
2652                    ++pStatus->m_iKillSent;
2653                    ++dying;
2654                }
2655            }
2656        }
2657        ++pStatus;
2658    }
2659    if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 )
2660    {
2661        fprintf( stderr, "Children tracking is wrong: PID: %d, Cur Childen: %d, count: %d, idle: %d, dying: %d\n", getpid(),
2662                g_prefork_server->m_iCurChildren, count, idle, dying );
2663
2664    }
2665}
2666
2667static int lsapi_all_children_must_die()
2668{
2669    int maxWait;
2670    int sec =0;
2671    g_prefork_server->m_iMaxReqProcessTime = 10;
2672    g_prefork_server->m_iMaxIdleChildren = -1;
2673    maxWait = 15;
2674
2675    while( g_prefork_server->m_iCurChildren && (sec < maxWait) )
2676    {
2677        lsapi_check_child_status(time(NULL));
2678        sleep( 1 );
2679        sec++;
2680    }
2681    if ( g_prefork_server->m_iCurChildren != 0 )
2682        kill( -getpgrp(), SIGKILL );
2683    return 0;
2684}
2685
2686
2687
2688static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq )
2689{
2690    struct sigaction act, old_term, old_quit, old_int,
2691                    old_usr1, old_child;
2692    lsapi_child_status * child_status;
2693    int             wait_secs = 0;
2694    int             ret = 0;
2695    int             pid;
2696    time_t          lastTime = 0;
2697    time_t          curTime = 0;
2698    fd_set          readfds;
2699    struct timeval  timeout;
2700
2701    sigset_t mask;
2702    sigset_t orig_mask;
2703
2704    lsapi_init_children_status();
2705
2706    setsid();
2707
2708    act.sa_flags = 0;
2709    act.sa_handler = lsapi_sigchild;
2710    if( sigaction( SIGCHLD, &act, &old_child ) )
2711    {
2712        perror( "Can't set signal handler for SIGCHILD" );
2713        return -1;
2714    }
2715
2716    /* Set up handler to kill children upon exit */
2717    act.sa_flags = 0;
2718    act.sa_handler = lsapi_cleanup;
2719    if( sigaction( SIGTERM, &act, &old_term ) ||
2720        sigaction( SIGINT,  &act, &old_int  ) ||
2721        sigaction( SIGUSR1, &act, &old_usr1 ) ||
2722        sigaction( SIGQUIT, &act, &old_quit ))
2723    {
2724        perror( "Can't set signals" );
2725        return -1;
2726    }
2727    s_stop = 0;
2728    while( !s_stop )
2729    {
2730        curTime = time( NULL );
2731        if (curTime != lastTime )
2732        {
2733            lastTime = curTime;
2734            if (s_ppid && (getppid() != s_ppid ))
2735                break;
2736            lsapi_check_child_status(curTime );
2737            if (pServer->m_iServerMaxIdle)
2738            {
2739                if ( pServer->m_iCurChildren <= 0 )
2740                {
2741                    ++wait_secs;
2742                    if ( wait_secs > pServer->m_iServerMaxIdle )
2743                        return -1;
2744                }
2745                else
2746                    wait_secs = 0;
2747            }
2748        }
2749
2750        if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) )
2751        {
2752            fprintf( stderr, "Reached max children process limit: %d, extra: %d, current: %d, please increase LSAPI_CHILDREN.\n",
2753                                pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren );
2754            usleep( 100000 );
2755            continue;
2756        }
2757
2758        FD_ZERO( &readfds );
2759        FD_SET( pServer->m_fd, &readfds );
2760        timeout.tv_sec = 1; timeout.tv_usec = 0;
2761        if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 )
2762        {
2763            /*
2764            if ( pServer->m_iCurChildren >= 0 )
2765            {
2766                usleep( 10 );
2767                FD_ZERO( &readfds );
2768                FD_SET( pServer->m_fd, &readfds );
2769                timeout.tv_sec = 0; timeout.tv_usec = 0;
2770                if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 )
2771                    continue;
2772            }*/
2773        }
2774        else if ( ret == -1 )
2775        {
2776            if ( errno == EINTR )
2777                continue;
2778            /* perror( "select()" ); */
2779            break;
2780        }
2781        else
2782        {
2783            continue;
2784        }
2785
2786        pReq->m_fd = lsapi_accept( pServer->m_fd );
2787        if ( pReq->m_fd != -1 )
2788        {
2789            child_status = find_child_status( 0 );
2790            if ( child_status )
2791                memset( child_status, 0, sizeof( *child_status ) );
2792
2793            sigemptyset( &mask );
2794            sigaddset( &mask, SIGCHLD );
2795
2796            if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 )
2797            {
2798                perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" );
2799            }
2800
2801            pid = fork();
2802
2803            if ( !pid )
2804            {
2805                if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
2806                    perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" );
2807                g_prefork_server = NULL;
2808                s_ppid = getppid();
2809                s_req_processed = 0;
2810                s_pChildStatus = child_status;
2811                lsapi_set_nblock( pReq->m_fd, 0 );
2812                if ( pReq->m_fdListen != -1 )
2813                {
2814                    close( pReq->m_fdListen );
2815                    pReq->m_fdListen = -1;
2816                }
2817                /* don't catch our signals */
2818                sigaction( SIGCHLD, &old_child, 0 );
2819                sigaction( SIGTERM, &old_term, 0 );
2820                sigaction( SIGQUIT, &old_quit, 0 );
2821                sigaction( SIGINT,  &old_int,  0 );
2822                sigaction( SIGUSR1, &old_usr1, 0 );
2823                //init_conn_key( pReq->m_fd );
2824                lsapi_notify_pid( pReq->m_fd );
2825                s_notified_pid = 1;
2826                //if ( s_accept_notify )
2827                //    return notify_req_received( pReq->m_fd );
2828                return 0;
2829            }
2830            else if ( pid == -1 )
2831            {
2832                perror( "fork() failed, please increase process limit" );
2833            }
2834            else
2835            {
2836                ++pServer->m_iCurChildren;
2837                if ( child_status )
2838                {
2839                    child_status->m_pid = pid;
2840                    child_status->m_tmWaitBegin = curTime;
2841                    child_status->m_tmStart = curTime;
2842                }
2843            }
2844            close( pReq->m_fd );
2845            pReq->m_fd = -1;
2846
2847            if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
2848                perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" );
2849
2850        }
2851        else
2852        {
2853            if (( errno == EINTR )||( errno == EAGAIN))
2854                continue;
2855            perror( "accept() failed" );
2856            return -1;
2857        }
2858    }
2859    sigaction( SIGUSR1, &old_usr1, 0 );
2860    //kill( -getpgrp(), SIGUSR1 );
2861    //lsapi_all_children_must_die();  /* Sorry, children ;-) */
2862    return -1;
2863
2864}
2865
2866void lsapi_error( const char * pMessage, int err_no )
2867{
2868    fprintf( stderr, "%d: %s, errno: %d (%s)\n", getpid(), pMessage, err_no, strerror( err_no ) );
2869}
2870
2871int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
2872{
2873    int             fd;
2874    int             ret;
2875    int             wait_secs;
2876    fd_set          readfds;
2877    struct timeval  timeout;
2878
2879    LSAPI_Finish_r( pReq );
2880
2881
2882    if ( g_prefork_server )
2883    {
2884        if ( g_prefork_server->m_fd != -1 )
2885            if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
2886                return -1;
2887    }
2888    if ( s_req_processed >= s_max_reqs )
2889        return -1;
2890
2891    if ( s_pChildStatus )
2892    {
2893        s_pChildStatus->m_tmWaitBegin = time( NULL );
2894    }
2895
2896
2897    while( g_running )
2898    {
2899        if ( pReq->m_fd != -1 )
2900        {
2901            fd = pReq->m_fd;
2902        }
2903        else if ( pReq->m_fdListen != -1 )
2904            fd = pReq->m_fdListen;
2905        else
2906        {
2907            break;
2908        }
2909        wait_secs = 0;
2910        while( 1 )
2911        {
2912            if ( !g_running )
2913                return -1;
2914            if ((s_req_processed)&&( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
2915                return -1;
2916            FD_ZERO( &readfds );
2917            FD_SET( fd, &readfds );
2918            timeout.tv_sec = 1;
2919            timeout.tv_usec = 0;
2920            ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout);
2921            if ( ret == 0 )
2922            {
2923                if ( s_pChildStatus )
2924                {
2925                    s_pChildStatus->m_inProcess = 0;
2926                }
2927                ++wait_secs;
2928                if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
2929                    return -1;
2930                if ( s_ppid &&( getppid() != s_ppid))
2931                    return -1;
2932            }
2933            else if ( ret == -1 )
2934            {
2935                if ( errno == EINTR )
2936                    continue;
2937                else
2938                    return -1;
2939            }
2940            else if ( ret >= 1 )
2941            {
2942                if (s_req_processed && ( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
2943                    return -1;
2944                if ( fd == pReq->m_fdListen )
2945                {
2946                    pReq->m_fd = lsapi_accept( pReq->m_fdListen );
2947                    if ( pReq->m_fd != -1 )
2948                    {
2949                        fd = pReq->m_fd;
2950                        lsapi_set_nblock( fd, 0 );
2951                        //init_conn_key( pReq->m_fd );
2952                        if ( !s_keepListener )
2953                        {
2954                            close( pReq->m_fdListen );
2955                            pReq->m_fdListen = -1;
2956                        }
2957                        if ( s_accept_notify )
2958                            if ( notify_req_received( pReq->m_fd ) == -1 )
2959                                return -1;
2960                    }
2961                    else
2962                    {
2963                        if (( errno == EINTR )||( errno == EAGAIN))
2964                            continue;
2965                        lsapi_error( "lsapi_accept() error", errno );
2966                        return -1;
2967                    }
2968                }
2969                else
2970                    break;
2971            }
2972        }
2973
2974        if ( !readReq( pReq ) )
2975        {
2976            if ( s_pChildStatus )
2977            {
2978                s_pChildStatus->m_iKillSent = 0;
2979                s_pChildStatus->m_inProcess = 1;
2980                ++s_pChildStatus->m_iReqCounter;
2981                s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL);
2982            }
2983            ++s_req_processed;
2984            return 0;
2985        }
2986        lsapi_close( pReq->m_fd );
2987        pReq->m_fd = -1;
2988        LSAPI_Reset_r( pReq );
2989    }
2990    return -1;
2991
2992}
2993
2994void LSAPI_Set_Max_Reqs( int reqs )
2995{   s_max_reqs = reqs;          }
2996
2997void LSAPI_Set_Max_Idle( int secs )
2998{   s_max_idle_secs = secs;     }
2999
3000void LSAPI_Set_Max_Children( int maxChildren )
3001{
3002    if ( g_prefork_server )
3003        g_prefork_server->m_iMaxChildren = maxChildren;
3004}
3005
3006void LSAPI_Set_Extra_Children( int extraChildren )
3007{
3008    if (( g_prefork_server )&&( extraChildren >= 0 ))
3009        g_prefork_server->m_iExtraChildren = extraChildren;
3010}
3011
3012void LSAPI_Set_Max_Process_Time( int secs )
3013{
3014    if (( g_prefork_server )&&( secs > 0 ))
3015        g_prefork_server->m_iMaxReqProcessTime = secs;
3016}
3017
3018
3019void LSAPI_Set_Max_Idle_Children( int maxIdleChld )
3020{
3021    if (( g_prefork_server )&&( maxIdleChld > 0 ))
3022        g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
3023}
3024
3025void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle )
3026{
3027    if ( g_prefork_server )
3028        g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
3029}
3030
3031void LSAPI_Set_Slow_Req_Msecs( int msecs )
3032{
3033    s_slow_req_msecs = msecs;
3034}
3035
3036int  LSAPI_Get_Slow_Req_Msecs()
3037{
3038    return s_slow_req_msecs;
3039}
3040
3041
3042void LSAPI_No_Check_ppid()
3043{
3044    s_ppid = 0;
3045}
3046
3047#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3048#include <crt_externs.h>
3049#else
3050extern char ** environ;
3051#endif
3052static void unset_lsapi_envs()
3053{
3054    char **env;
3055#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3056    env = *_NSGetEnviron();
3057#else
3058    env = environ;
3059#endif
3060    while( env != NULL && *env != NULL )
3061    {
3062        if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 )
3063            || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid)))
3064        {
3065            char ** del = env;
3066            do
3067                *del = del[1];
3068            while( *del++ );
3069        }
3070        else
3071            ++env;
3072    }
3073}
3074
3075static int lsapi_initSuEXEC()
3076{
3077    int i;
3078    struct passwd * pw;
3079    s_defaultUid = 0;
3080    s_defaultGid = 0;
3081    if ( s_uid == 0 )
3082    {
3083        const char * p = getenv( "LSAPI_DEFAULT_UID" );
3084        if ( p )
3085        {
3086            i = atoi( p );
3087            if ( i > 0 )
3088                s_defaultUid = i;
3089        }
3090        p = getenv( "LSAPI_DEFAULT_GID" );
3091        if ( p )
3092        {
3093            i = atoi( p );
3094            if ( i > 0 )
3095                s_defaultGid = i;
3096        }
3097        p = getenv( "LSAPI_SECRET" );
3098        if (( !p )||( readSecret(p) == -1 ))
3099                return -1;
3100        if ( g_prefork_server )
3101        {
3102            if ( g_prefork_server->m_iMaxChildren < 100 )
3103                g_prefork_server->m_iMaxChildren = 100;
3104            if ( g_prefork_server->m_iExtraChildren < 1000 )
3105                g_prefork_server->m_iExtraChildren = 1000;
3106        }
3107    }
3108    if ( !s_defaultUid || !s_defaultGid )
3109    {
3110        pw = getpwnam( "nobody" );
3111        if ( !s_defaultUid )
3112            s_defaultUid = pw->pw_uid;
3113        if ( !s_defaultGid )
3114            s_defaultGid = pw->pw_gid;
3115    }
3116    return 0;
3117}
3118
3119
3120int LSAPI_Init_Env_Parameters( fn_select_t fp )
3121{
3122    const char *p;
3123    int n;
3124    int avoidFork = 0;
3125    p = getenv( "PHP_LSAPI_MAX_REQUESTS" );
3126    if ( !p )
3127        p = getenv( "LSAPI_MAX_REQS" );
3128    if ( p )
3129    {
3130        n = atoi( p );
3131        if ( n > 0 )
3132            LSAPI_Set_Max_Reqs( n );
3133    }
3134
3135    p = getenv( "LSAPI_AVOID_FORK" );
3136    if ( p )
3137    {
3138        avoidFork = atoi( p );
3139    }
3140
3141    p = getenv( "LSAPI_ACCEPT_NOTIFY" );
3142    if ( p )
3143    {
3144        s_accept_notify = atoi( p );
3145    }
3146
3147    p = getenv( "LSAPI_SLOW_REQ_MSECS" );
3148    if ( p )
3149    {
3150        n = atoi( p );
3151        LSAPI_Set_Slow_Req_Msecs( n );
3152    }
3153
3154#if defined( RLIMIT_CORE )
3155    p = getenv( "LSAPI_ALLOW_CORE_DUMP" );
3156    if ( !p )
3157    {
3158        struct rlimit limit = { 0, 0 };
3159        setrlimit( RLIMIT_CORE, &limit );
3160    }
3161    else
3162        s_enable_core_dump = 1;
3163
3164#endif
3165
3166    p = getenv( "LSAPI_MAX_IDLE" );
3167    if ( p )
3168    {
3169        n = atoi( p );
3170        LSAPI_Set_Max_Idle( n );
3171    }
3172
3173    p = getenv( "LSAPI_KEEP_LISTEN" );
3174    if ( p )
3175    {
3176        n = atoi( p );
3177        s_keepListener = n;
3178    }
3179
3180
3181    if ( LSAPI_Is_Listen() )
3182    {
3183        n = 0;
3184        p = getenv( "PHP_LSAPI_CHILDREN" );
3185        if ( !p )
3186            p = getenv( "LSAPI_CHILDREN" );
3187        if ( p )
3188            n = atoi( p );
3189        if ( n > 1 )
3190        {
3191            LSAPI_Init_Prefork_Server( n, fp, avoidFork );
3192            LSAPI_Set_Server_fd( g_req.m_fdListen );
3193        }
3194
3195        p = getenv( "LSAPI_EXTRA_CHILDREN" );
3196        if ( p )
3197            LSAPI_Set_Extra_Children( atoi( p ) );
3198
3199        p = getenv( "LSAPI_MAX_IDLE_CHILDREN" );
3200        if ( p )
3201            LSAPI_Set_Max_Idle_Children( atoi( p ) );
3202
3203        p = getenv( "LSAPI_PGRP_MAX_IDLE" );
3204        if ( p )
3205        {
3206            LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) );
3207        }
3208
3209        p = getenv( "LSAPI_MAX_PROCESS_TIME" );
3210        if ( p )
3211            LSAPI_Set_Max_Process_Time( atoi( p ) );
3212
3213        if ( getenv( "LSAPI_PPID_NO_CHECK" ) )
3214        {
3215            LSAPI_No_Check_ppid();
3216        }
3217
3218        p = getenv( "LSAPI_DUMP_DEBUG_INFO" );
3219        if ( p )
3220            s_dump_debug_info = atoi( p );
3221
3222        if ( lsapi_initSuEXEC() == -1 )
3223            return -1;
3224#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
3225        lsapi_initLVE();
3226#endif
3227    }
3228    unset_lsapi_envs();
3229    return 0;
3230}
3231
3232
3233int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders,
3234                         const char * pBody, int bodyLen )
3235{
3236    LSAPI_SetRespStatus_r( pReq, code );
3237    if ( pRespHeaders )
3238    {
3239        while( *pRespHeaders )
3240        {
3241            LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) );
3242            ++pRespHeaders;
3243        }
3244    }
3245    if ( pBody &&( bodyLen > 0 ))
3246    {
3247        LSAPI_Write_r( pReq, pBody, bodyLen );
3248    }
3249    LSAPI_Finish_r( pReq );
3250    return 0;
3251}
3252
3253
3254static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]);
3255
3256/*
3257 * Note: this code is harmless on little-endian machines.
3258 */
3259static void byteReverse(unsigned char *buf, unsigned longs)
3260{
3261    uint32 t;
3262    do {
3263        t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
3264            ((unsigned) buf[1] << 8 | buf[0]);
3265        *(uint32 *) buf = t;
3266        buf += 4;
3267    } while (--longs);
3268}
3269
3270/*
3271 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
3272 * initialization constants.
3273 */
3274void lsapi_MD5Init(struct lsapi_MD5Context *ctx)
3275{
3276    ctx->buf[0] = 0x67452301;
3277    ctx->buf[1] = 0xefcdab89;
3278    ctx->buf[2] = 0x98badcfe;
3279    ctx->buf[3] = 0x10325476;
3280
3281    ctx->bits[0] = 0;
3282    ctx->bits[1] = 0;
3283}
3284
3285/*
3286 * Update context to reflect the concatenation of another buffer full
3287 * of bytes.
3288 */
3289void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len)
3290{
3291    register uint32 t;
3292
3293    /* Update bitcount */
3294
3295    t = ctx->bits[0];
3296    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
3297        ctx->bits[1]++;                /* Carry from low to high */
3298    ctx->bits[1] += len >> 29;
3299
3300    t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
3301
3302    /* Handle any leading odd-sized chunks */
3303
3304    if (t) {
3305        unsigned char *p = (unsigned char *) ctx->in + t;
3306
3307        t = 64 - t;
3308        if (len < t) {
3309            memmove(p, buf, len);
3310            return;
3311        }
3312        memmove(p, buf, t);
3313        byteReverse(ctx->in, 16);
3314        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3315        buf += t;
3316        len -= t;
3317    }
3318    /* Process data in 64-byte chunks */
3319
3320    while (len >= 64) {
3321        memmove(ctx->in, buf, 64);
3322        byteReverse(ctx->in, 16);
3323        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3324        buf += 64;
3325        len -= 64;
3326    }
3327
3328    /* Handle any remaining bytes of data. */
3329
3330    memmove(ctx->in, buf, len);
3331}
3332
3333/*
3334 * Final wrapup - pad to 64-byte boundary with the bit pattern
3335 * 1 0* (64-bit count of bits processed, MSB-first)
3336 */
3337void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx)
3338{
3339    unsigned int count;
3340    unsigned char *p;
3341
3342    /* Compute number of bytes mod 64 */
3343    count = (ctx->bits[0] >> 3) & 0x3F;
3344
3345    /* Set the first char of padding to 0x80.  This is safe since there is
3346       always at least one byte free */
3347    p = ctx->in + count;
3348    *p++ = 0x80;
3349
3350    /* Bytes of padding needed to make 64 bytes */
3351    count = 64 - 1 - count;
3352
3353    /* Pad out to 56 mod 64 */
3354    if (count < 8) {
3355        /* Two lots of padding:  Pad the first block to 64 bytes */
3356        memset(p, 0, count);
3357        byteReverse(ctx->in, 16);
3358        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3359
3360        /* Now fill the next block with 56 bytes */
3361        memset(ctx->in, 0, 56);
3362    } else {
3363        /* Pad block to 56 bytes */
3364        memset(p, 0, count - 8);
3365    }
3366    byteReverse(ctx->in, 14);
3367
3368    /* Append length in bits and transform */
3369    ((uint32 *) ctx->in)[14] = ctx->bits[0];
3370    ((uint32 *) ctx->in)[15] = ctx->bits[1];
3371
3372    lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3373    byteReverse((unsigned char *) ctx->buf, 4);
3374    memmove(digest, ctx->buf, 16);
3375    memset(ctx, 0, sizeof(ctx));        /* In case it's sensitive */
3376}
3377
3378/* The four core functions - F1 is optimized somewhat */
3379
3380/* #define F1(x, y, z) (x & y | ~x & z) */
3381#define F1(x, y, z) (z ^ (x & (y ^ z)))
3382#define F2(x, y, z) F1(z, x, y)
3383#define F3(x, y, z) (x ^ y ^ z)
3384#define F4(x, y, z) (y ^ (x | ~z))
3385
3386/* This is the central step in the MD5 algorithm. */
3387#define MD5STEP(f, w, x, y, z, data, s) \
3388        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
3389
3390/*
3391 * The core of the MD5 algorithm, this alters an existing MD5 hash to
3392 * reflect the addition of 16 longwords of new data.  MD5Update blocks
3393 * the data and converts bytes into longwords for this routine.
3394 */
3395static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16])
3396{
3397    register uint32 a, b, c, d;
3398
3399    a = buf[0];
3400    b = buf[1];
3401    c = buf[2];
3402    d = buf[3];
3403
3404    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
3405    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
3406    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
3407    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
3408    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
3409    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
3410    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
3411    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
3412    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
3413    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
3414    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
3415    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
3416    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
3417    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
3418    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
3419    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
3420
3421    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
3422    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
3423    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
3424    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
3425    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
3426    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
3427    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
3428    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
3429    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
3430    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
3431    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
3432    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
3433    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
3434    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
3435    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
3436    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
3437
3438    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
3439    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
3440    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
3441    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
3442    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
3443    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
3444    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
3445    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
3446    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
3447    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
3448    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
3449    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
3450    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
3451    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
3452    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
3453    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
3454
3455    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
3456    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
3457    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
3458    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
3459    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
3460    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
3461    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
3462    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
3463    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
3464    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
3465    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
3466    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
3467    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
3468    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
3469    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
3470    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
3471
3472    buf[0] += a;
3473    buf[1] += b;
3474    buf[2] += c;
3475    buf[3] += d;
3476}
3477
3478