1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
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
1916    if ( !pReq || !fn )
1917        return -1;
1918
1919    if ( !pReq->m_pHeaderIndex )
1920        return 0;
1921
1922    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
1923    {
1924        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
1925        {
1926            len = pReq->m_pHeaderIndex->m_headerLen[i];
1927            pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
1928            *(pValue + len ) = 0;
1929            headers[count]._name = HTTP_HEADERS[i];
1930            headers[count]._nameLen = HTTP_HEADER_LEN[i];
1931            headers[count]._value = pValue;
1932            headers[count]._valueLen = len;
1933            ++count;
1934
1935            //ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i],
1936            //            pValue, len, arg );
1937            //if ( ret <= 0 )
1938            //    return ret;
1939        }
1940    }
1941    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
1942    {
1943        char *pKey;
1944        int  keyLen;
1945        struct lsapi_header_offset * pCur, *pEnd;
1946        pCur = pReq->m_pUnknownHeader;
1947        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
1948        while( pCur < pEnd )
1949        {
1950            pKey = pReq->m_pHttpHeader + pCur->nameOff;
1951            keyLen = pCur->nameLen;
1952            *(pKey + keyLen ) = 0;
1953
1954            pValue = pReq->m_pHttpHeader + pCur->valueOff;
1955            *(pValue + pCur->valueLen ) = 0;
1956            headers[count]._name = pKey;
1957            headers[count]._nameLen = keyLen;
1958            headers[count]._value = pValue;
1959            headers[count]._valueLen = pCur->valueLen;
1960            ++count;
1961            if ( count == 512 )
1962                break;
1963            //ret = (*fn)( pKey, keyLen,
1964            //            pValue, pCur->valueLen, arg );
1965            //if ( ret <= 0 )
1966            //    return ret;
1967            ++pCur;
1968        }
1969    }
1970    qsort( headers, count, sizeof( struct _headerInfo ), compareValueLocation );
1971    for( i = 0; i < count; ++i )
1972    {
1973        ret = (*fn)( headers[i]._name, headers[i]._nameLen,
1974                    headers[i]._value, headers[i]._valueLen, arg );
1975        if ( ret <= 0 )
1976            return ret;
1977    }
1978    return count;
1979
1980}
1981
1982
1983int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
1984            LSAPI_CB_EnvHandler fn, void * arg )
1985{
1986    int i;
1987    int len = 0;
1988    char * pValue;
1989    int ret;
1990    int count = 0;
1991    if ( !pReq || !fn )
1992        return -1;
1993    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
1994    {
1995        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
1996        {
1997            len = pReq->m_pHeaderIndex->m_headerLen[i];
1998            pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
1999            *(pValue + len ) = 0;
2000            ret = (*fn)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
2001                        pValue, len, arg );
2002            ++count;
2003            if ( ret <= 0 )
2004                return ret;
2005        }
2006    }
2007    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
2008    {
2009        char achHeaderName[256];
2010        char *p;
2011        char *pKey;
2012        char *pKeyEnd ;
2013        int  keyLen;
2014        struct lsapi_header_offset * pCur, *pEnd;
2015        pCur = pReq->m_pUnknownHeader;
2016        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
2017        while( pCur < pEnd )
2018        {
2019            pKey = pReq->m_pHttpHeader + pCur->nameOff;
2020            keyLen = pCur->nameLen;
2021            if ( keyLen > 250 )
2022                keyLen = 250;
2023            pKeyEnd = pKey + keyLen;
2024            memcpy( achHeaderName, "HTTP_", 5 );
2025            p = &achHeaderName[5];
2026
2027            while( pKey < pKeyEnd )
2028            {
2029                char ch = *pKey++;
2030                if ( ch == '-' )
2031                    *p++ = '_';
2032                else
2033                    *p++ = toupper( ch );
2034            }
2035            *p = 0;
2036            keyLen += 5;
2037
2038            pValue = pReq->m_pHttpHeader + pCur->valueOff;
2039            *(pValue + pCur->valueLen ) = 0;
2040            ret = (*fn)( achHeaderName, keyLen,
2041                        pValue, pCur->valueLen, arg );
2042            if ( ret <= 0 )
2043                return ret;
2044            ++pCur;
2045        }
2046    }
2047    return count + pReq->m_pHeader->m_cntUnknownHeaders;
2048
2049}
2050
2051static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
2052            int n, LSAPI_CB_EnvHandler fn, void * arg )
2053{
2054    struct LSAPI_key_value_pair * pEnd = pEnv + n;
2055    int ret;
2056    if ( !pEnv || !fn )
2057        return -1;
2058    while( pEnv < pEnd )
2059    {
2060        ret = (*fn)( pEnv->pKey, pEnv->keyLen,
2061                    pEnv->pValue, pEnv->valLen, arg );
2062        if ( ret <= 0 )
2063            return ret;
2064        ++pEnv;
2065    }
2066    return n;
2067}
2068
2069
2070
2071int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
2072            LSAPI_CB_EnvHandler fn, void * arg )
2073{
2074    if ( !pReq || !fn )
2075        return -1;
2076    if ( pReq->m_pHeader->m_cntEnv > 0 )
2077    {
2078        return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
2079                    fn, arg );
2080    }
2081    return 0;
2082}
2083
2084
2085
2086int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
2087            LSAPI_CB_EnvHandler fn, void * arg )
2088{
2089    if ( !pReq || !fn )
2090        return -1;
2091    if ( pReq->m_pHeader->m_cntSpecialEnv > 0 )
2092    {
2093        return EnvForeach( pReq->m_pSpecialEnvList,
2094                pReq->m_pHeader->m_cntSpecialEnv,
2095                    fn, arg );
2096    }
2097    return 0;
2098
2099}
2100
2101
2102
2103int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
2104{
2105    if ( !pReq || !pReq->m_pIovec )
2106        return -1;
2107    if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) )
2108        return 0;
2109    pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER;
2110    if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf )
2111    {
2112        pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf;
2113        pReq->m_pIovecCur->iov_len  = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
2114        pReq->m_totalLen += pReq->m_pIovecCur->iov_len;
2115        ++pReq->m_pIovecCur;
2116    }
2117
2118    pReq->m_pIovec->iov_len  = sizeof( struct lsapi_resp_header)
2119            + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short );
2120    pReq->m_totalLen += pReq->m_pIovec->iov_len;
2121
2122    lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader,
2123                    LSAPI_RESP_HEADER, pReq->m_totalLen  );
2124    pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader;
2125    pReq->m_pIovecToWrite = pReq->m_pIovec;
2126    return 0;
2127}
2128
2129
2130int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
2131                              const char * pHeaderValue )
2132{
2133    int nameLen, valLen, len;
2134    if ( !pReq || !pHeaderName || !pHeaderValue )
2135        return -1;
2136    if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
2137        return -1;
2138    if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
2139        return -1;
2140    nameLen = strlen( pHeaderName );
2141    valLen = strlen( pHeaderValue );
2142    if ( nameLen == 0 )
2143        return -1;
2144    while( nameLen > 0 )
2145    {
2146        char ch = *(pHeaderName + nameLen - 1 );
2147        if (( ch == '\n' )||( ch == '\r' ))
2148            --nameLen;
2149        else
2150            break;
2151    }
2152    if ( nameLen <= 0 )
2153        return 0;
2154    while( valLen > 0 )
2155    {
2156        char ch = *(pHeaderValue + valLen - 1 );
2157        if (( ch == '\n' )||( ch == '\r' ))
2158            --valLen;
2159        else
2160            break;
2161    }
2162    len = nameLen + valLen + 1;
2163    if ( len > LSAPI_RESP_HTTP_HEADER_MAX )
2164        return -1;
2165
2166    if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
2167    {
2168        int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
2169        newlen -= newlen % 4096;
2170        if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2171            return -1;
2172    }
2173    memmove( pReq->m_pRespHeaderBufPos, pHeaderName, nameLen );
2174    pReq->m_pRespHeaderBufPos += nameLen;
2175    *pReq->m_pRespHeaderBufPos++ = ':';
2176    memmove( pReq->m_pRespHeaderBufPos, pHeaderValue, valLen );
2177    pReq->m_pRespHeaderBufPos += valLen;
2178    *pReq->m_pRespHeaderBufPos++ = 0;
2179    ++len;  /* add one byte padding for \0 */
2180    pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
2181    ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
2182    return 0;
2183}
2184
2185
2186
2187int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len )
2188{
2189    if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX )
2190        return -1;
2191    if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
2192        return -1;
2193    if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS )
2194        return -1;
2195    while( len > 0 )
2196    {
2197        char ch = *(pBuf + len - 1 );
2198        if (( ch == '\n' )||( ch == '\r' ))
2199            --len;
2200        else
2201            break;
2202    }
2203    if ( len <= 0 )
2204        return 0;
2205    if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
2206    {
2207        int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
2208        newlen -= newlen % 4096;
2209        if ( allocateRespHeaderBuf( pReq, newlen ) == -1 )
2210            return -1;
2211    }
2212    memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
2213    pReq->m_pRespHeaderBufPos += len;
2214    *pReq->m_pRespHeaderBufPos++ = 0;
2215    ++len;  /* add one byte padding for \0 */
2216    pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
2217    ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
2218    return 0;
2219}
2220
2221
2222int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
2223{
2224    int ret;
2225    int fd;
2226    int flag = 1;
2227    int addr_len;
2228
2229    switch( pServerAddr->sa_family )
2230    {
2231    case AF_INET:
2232        addr_len = 16;
2233        break;
2234    case AF_INET6:
2235        addr_len = sizeof( struct sockaddr_in6 );
2236        break;
2237    case AF_UNIX:
2238        addr_len = sizeof( struct sockaddr_un );
2239        unlink( ((struct sockaddr_un *)pServerAddr)->sun_path );
2240        break;
2241    default:
2242        return -1;
2243    }
2244
2245    fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 );
2246    if ( fd == -1 )
2247        return -1;
2248
2249    fcntl( fd, F_SETFD, FD_CLOEXEC );
2250
2251    if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
2252                (char *)( &flag ), sizeof(flag)) == 0)
2253    {
2254        ret = bind( fd, pServerAddr, addr_len );
2255        if ( !ret )
2256        {
2257            ret = listen( fd, backlog );
2258            if ( !ret )
2259                return fd;
2260        }
2261    }
2262
2263    ret = errno;
2264    close(fd);
2265    errno = ret;
2266    return -1;
2267
2268}
2269
2270int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
2271{
2272    char achAddr[256];
2273    char * p = achAddr;
2274    char * pEnd;
2275    struct addrinfo *res, hints;
2276    int  doAddrInfo = 0;
2277    int port;
2278
2279    if ( !pBind )
2280        return -1;
2281
2282    while( isspace( *pBind ) )
2283        ++pBind;
2284
2285    strncpy( achAddr, pBind, 256 );
2286
2287    switch( *p )
2288    {
2289    case '/':
2290        pAddr->sa_family = AF_UNIX;
2291        strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p,
2292                sizeof(((struct sockaddr_un *)pAddr)->sun_path) );
2293        return 0;
2294
2295    case '[':
2296        pAddr->sa_family = AF_INET6;
2297        ++p;
2298        pEnd = strchr( p, ']' );
2299        if ( !pEnd )
2300            return -1;
2301        *pEnd++ = 0;
2302
2303        if ( *p == '*' )
2304        {
2305            strcpy( achAddr, "::" );
2306            p = achAddr;
2307        }
2308        doAddrInfo = 1;
2309        break;
2310
2311    default:
2312        pAddr->sa_family = AF_INET;
2313        pEnd = strchr( p, ':' );
2314        if ( !pEnd )
2315            return -1;
2316        *pEnd++ = 0;
2317
2318        doAddrInfo = 0;
2319        if ( *p == '*' )
2320        {
2321            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
2322        }
2323        else if (!strcasecmp( p, "localhost" ) )
2324            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
2325        else
2326        {
2327            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
2328            if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST)
2329            {
2330                doAddrInfo = 1;
2331            }
2332        }
2333        break;
2334    }
2335    if ( *pEnd == ':' )
2336        ++pEnd;
2337
2338    port = atoi( pEnd );
2339    if (( port <= 0 )||( port > 65535 ))
2340        return -1;
2341    if ( doAddrInfo )
2342    {
2343
2344        memset(&hints, 0, sizeof(hints));
2345
2346        hints.ai_family   = pAddr->sa_family;
2347        hints.ai_socktype = SOCK_STREAM;
2348        hints.ai_protocol = IPPROTO_TCP;
2349
2350        if ( getaddrinfo(p, NULL, &hints, &res) )
2351        {
2352            return -1;
2353        }
2354
2355        memcpy(pAddr, res->ai_addr, res->ai_addrlen);
2356        freeaddrinfo(res);
2357    }
2358
2359    if ( pAddr->sa_family == AF_INET )
2360        ((struct sockaddr_in *)pAddr)->sin_port = htons( port );
2361    else
2362        ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
2363    return 0;
2364
2365}
2366
2367int LSAPI_CreateListenSock( const char * pBind, int backlog )
2368{
2369    char serverAddr[128];
2370    int ret;
2371    int fd = -1;
2372    ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr );
2373    if ( !ret )
2374    {
2375        fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog );
2376    }
2377    return fd;
2378}
2379
2380static fn_select_t g_fnSelect = select;
2381
2382typedef struct _lsapi_child_status
2383{
2384    int     m_pid;
2385    long    m_tmStart;
2386
2387    volatile short   m_iKillSent;
2388    volatile short   m_inProcess;
2389    volatile int     m_iReqCounter;
2390
2391    volatile long    m_tmWaitBegin;
2392    volatile long    m_tmReqBegin;
2393    volatile long    m_tmLastCheckPoint;
2394}
2395lsapi_child_status;
2396
2397static lsapi_child_status * s_pChildStatus = NULL;
2398
2399typedef struct _lsapi_prefork_server
2400{
2401    int m_fd;
2402    int m_iMaxChildren;
2403    int m_iExtraChildren;
2404    int m_iCurChildren;
2405    int m_iMaxIdleChildren;
2406    int m_iServerMaxIdle;
2407    int m_iChildrenMaxIdleTime;
2408    int m_iMaxReqProcessTime;
2409    int m_iAvoidFork;
2410
2411    lsapi_child_status * m_pChildrenStatus;
2412    lsapi_child_status * m_pChildrenStatusCur;
2413    lsapi_child_status * m_pChildrenStatusEnd;
2414
2415}lsapi_prefork_server;
2416
2417static lsapi_prefork_server * g_prefork_server = NULL;
2418
2419int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
2420{
2421    int pid;
2422    if ( g_prefork_server )
2423        return 0;
2424    if ( max_children <= 1 )
2425        return -1;
2426    if ( max_children >= 10000)
2427        max_children = 10000;
2428
2429
2430    g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) );
2431    if ( !g_prefork_server )
2432        return -1;
2433    memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) );
2434
2435    if ( fp != NULL )
2436        g_fnSelect = fp;
2437
2438    s_ppid = getppid();
2439    pid = getpid();
2440    setpgid( pid, pid );
2441    g_prefork_server->m_iAvoidFork = avoidFork;
2442    g_prefork_server->m_iMaxChildren = max_children;
2443
2444    g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ;
2445    g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3);
2446    if ( g_prefork_server->m_iMaxIdleChildren == 0 )
2447        g_prefork_server->m_iMaxIdleChildren = 1;
2448    g_prefork_server->m_iChildrenMaxIdleTime = 300;
2449    g_prefork_server->m_iMaxReqProcessTime = 3600;
2450    return 0;
2451}
2452
2453void LSAPI_Set_Server_fd( int fd )
2454{
2455    if( g_prefork_server )
2456        g_prefork_server->m_fd = fd;
2457}
2458
2459
2460static int lsapi_accept( int fdListen )
2461{
2462    int         fd;
2463    int         nodelay = 1;
2464    socklen_t   len;
2465    char        achPeer[128];
2466
2467    len = sizeof( achPeer );
2468    fd = accept( fdListen, (struct sockaddr *)&achPeer, &len );
2469    if ( fd != -1 )
2470    {
2471        if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
2472        {
2473            setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
2474                    (char *)&nodelay, sizeof(nodelay));
2475        }
2476
2477        //OPTIMIZATION
2478        //if ( s_accept_notify )
2479        //    notify_req_received( fd );
2480    }
2481    return fd;
2482
2483}
2484
2485
2486
2487
2488static int s_req_processed = 0;
2489static int s_max_reqs = 10000;
2490static int s_max_idle_secs = 300;
2491
2492static int s_stop;
2493
2494static void lsapi_cleanup(int signal)
2495{
2496    s_stop = signal;
2497}
2498
2499static lsapi_child_status * find_child_status( int pid )
2500{
2501    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
2502    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusEnd;
2503    while( pStatus < pEnd )
2504    {
2505        if ( pStatus->m_pid == pid )
2506        {
2507            if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur )
2508                g_prefork_server->m_pChildrenStatusCur = pStatus + 1;
2509            return pStatus;
2510        }
2511        ++pStatus;
2512    }
2513    return NULL;
2514}
2515
2516
2517
2518static void lsapi_sigchild( int signal )
2519{
2520    int status, pid;
2521    lsapi_child_status * child_status;
2522    while( 1 )
2523    {
2524        pid = waitpid( -1, &status, WNOHANG|WUNTRACED );
2525        if ( pid <= 0 )
2526        {
2527            break;
2528        }
2529        if ( WIFSIGNALED( status ))
2530        {
2531            int sig_num = WTERMSIG( status );
2532            int dump = WCOREDUMP( status );
2533            fprintf( stderr, "Child process with pid: %d was killed by signal: %d, core dump: %d\n", pid, sig_num, dump );
2534        }
2535        if ( pid == s_pid_dump_debug_info )
2536        {
2537            pid = 0;
2538            continue;
2539        }
2540        child_status = find_child_status( pid );
2541        if ( child_status )
2542        {
2543            child_status->m_pid = 0;
2544            --g_prefork_server->m_iCurChildren;
2545
2546        }
2547    }
2548    while(( g_prefork_server->m_pChildrenStatusCur > g_prefork_server->m_pChildrenStatus )
2549            &&( g_prefork_server->m_pChildrenStatusCur[-1].m_pid == 0 ))
2550        --g_prefork_server->m_pChildrenStatusCur;
2551
2552}
2553
2554static int lsapi_init_children_status()
2555{
2556    int size = 4096;
2557
2558    char * pBuf;
2559    size = (g_prefork_server->m_iMaxChildren + g_prefork_server->m_iExtraChildren ) * sizeof( lsapi_child_status ) * 2;
2560    size = (size + 4095 ) / 4096 * 4096;
2561    pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
2562        MAP_ANON | MAP_SHARED, -1, 0 );
2563    if ( pBuf == MAP_FAILED )
2564    {
2565        perror( "Anonymous mmap() failed" );
2566        return -1;
2567    }
2568    memset( pBuf, 0, size );
2569    g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;
2570    g_prefork_server->m_pChildrenStatusCur = (lsapi_child_status *)pBuf;
2571    g_prefork_server->m_pChildrenStatusEnd = (lsapi_child_status *)pBuf + size / sizeof( lsapi_child_status );
2572    return 0;
2573}
2574
2575static void dump_debug_info( lsapi_child_status * pStatus, long tmCur )
2576{
2577    char achCmd[1024];
2578    if ( s_pid_dump_debug_info )
2579    {
2580        if ( kill( s_pid_dump_debug_info, 0 ) == 0 )
2581            return;
2582    }
2583    s_pid_dump_debug_info = fork();
2584
2585    fprintf( stderr, "[%s] Possible runaway process, PPID: %d, PID: %d, reqCount: %d, process time: %ld, checkpoint time: %ld, start time: %ld\n",
2586                ctime(&tmCur), getpid(), pStatus->m_pid, pStatus->m_iReqCounter,
2587                tmCur - pStatus->m_tmReqBegin, tmCur - pStatus->m_tmLastCheckPoint, tmCur - pStatus->m_tmStart );
2588    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 );
2589    if ( system( achCmd ) == -1 )
2590        perror( "system()" );
2591    exit( 0 );
2592}
2593
2594static void lsapi_check_child_status( long tmCur )
2595{
2596    int idle = 0;
2597    int tobekilled;
2598    int dying = 0;
2599    int count = 0;
2600    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
2601    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatusCur;
2602    while( pStatus < pEnd )
2603    {
2604        tobekilled = 0;
2605        if ( pStatus->m_pid != 0 )
2606        {
2607            ++count;
2608            if ( !pStatus->m_inProcess )
2609            {
2610
2611                if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)||
2612                    ( idle > g_prefork_server->m_iMaxIdleChildren ))
2613                {
2614                    ++pStatus->m_iKillSent;
2615                    //tobekilled = SIGUSR1;
2616                }
2617                else
2618                {
2619                    if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 ))
2620                    {
2621                        ++pStatus->m_iKillSent;
2622                        //tobekilled = SIGUSR1;
2623                    }
2624                }
2625                if ( !tobekilled )
2626                    ++idle;
2627            }
2628            else
2629            {
2630                if ( tmCur - pStatus->m_tmReqBegin >
2631                        g_prefork_server->m_iMaxReqProcessTime )
2632                {
2633                    if (( ( pStatus->m_iKillSent % 5 ) == 0 )&&( s_dump_debug_info ))
2634                        dump_debug_info( pStatus, tmCur );
2635                    if ( pStatus->m_iKillSent > 5 )
2636                    {
2637                        tobekilled = SIGKILL;
2638                        fprintf( stderr, "Force killing runaway process PID: %d with SIGKILL\n", pStatus->m_pid );
2639                    }
2640                    else
2641                    {
2642                        tobekilled = SIGTERM;
2643                        fprintf( stderr, "Killing runaway process PID: %d with SIGTERM\n", pStatus->m_pid );
2644                    }
2645                }
2646            }
2647            if ( tobekilled )
2648            {
2649                if (( kill( pStatus->m_pid, tobekilled ) == -1 )&&( errno == ESRCH ))
2650                {
2651                    pStatus->m_pid = 0;
2652                    --count;
2653                }
2654                else
2655                {
2656                    ++pStatus->m_iKillSent;
2657                    ++dying;
2658                }
2659            }
2660        }
2661        ++pStatus;
2662    }
2663    if ( abs( g_prefork_server->m_iCurChildren - count ) > 1 )
2664    {
2665        fprintf( stderr, "Children tracking is wrong: PID: %d, Cur Children: %d, count: %d, idle: %d, dying: %d\n", getpid(),
2666                g_prefork_server->m_iCurChildren, count, idle, dying );
2667
2668    }
2669}
2670
2671static int lsapi_all_children_must_die()
2672{
2673    int maxWait;
2674    int sec =0;
2675    g_prefork_server->m_iMaxReqProcessTime = 10;
2676    g_prefork_server->m_iMaxIdleChildren = -1;
2677    maxWait = 15;
2678
2679    while( g_prefork_server->m_iCurChildren && (sec < maxWait) )
2680    {
2681        lsapi_check_child_status(time(NULL));
2682        sleep( 1 );
2683        sec++;
2684    }
2685    if ( g_prefork_server->m_iCurChildren != 0 )
2686        kill( -getpgrp(), SIGKILL );
2687    return 0;
2688}
2689
2690
2691
2692static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq )
2693{
2694    struct sigaction act, old_term, old_quit, old_int,
2695                    old_usr1, old_child;
2696    lsapi_child_status * child_status;
2697    int             wait_secs = 0;
2698    int             ret = 0;
2699    int             pid;
2700    time_t          lastTime = 0;
2701    time_t          curTime = 0;
2702    fd_set          readfds;
2703    struct timeval  timeout;
2704
2705    sigset_t mask;
2706    sigset_t orig_mask;
2707
2708    lsapi_init_children_status();
2709
2710    setsid();
2711
2712    act.sa_flags = 0;
2713    act.sa_handler = lsapi_sigchild;
2714    if( sigaction( SIGCHLD, &act, &old_child ) )
2715    {
2716        perror( "Can't set signal handler for SIGCHILD" );
2717        return -1;
2718    }
2719
2720    /* Set up handler to kill children upon exit */
2721    act.sa_flags = 0;
2722    act.sa_handler = lsapi_cleanup;
2723    if( sigaction( SIGTERM, &act, &old_term ) ||
2724        sigaction( SIGINT,  &act, &old_int  ) ||
2725        sigaction( SIGUSR1, &act, &old_usr1 ) ||
2726        sigaction( SIGQUIT, &act, &old_quit ))
2727    {
2728        perror( "Can't set signals" );
2729        return -1;
2730    }
2731    s_stop = 0;
2732    while( !s_stop )
2733    {
2734        curTime = time( NULL );
2735        if (curTime != lastTime )
2736        {
2737            lastTime = curTime;
2738            if (s_ppid && (getppid() != s_ppid ))
2739                break;
2740            lsapi_check_child_status(curTime );
2741            if (pServer->m_iServerMaxIdle)
2742            {
2743                if ( pServer->m_iCurChildren <= 0 )
2744                {
2745                    ++wait_secs;
2746                    if ( wait_secs > pServer->m_iServerMaxIdle )
2747                        return -1;
2748                }
2749                else
2750                    wait_secs = 0;
2751            }
2752        }
2753
2754        if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) )
2755        {
2756            fprintf( stderr, "Reached max children process limit: %d, extra: %d, current: %d, please increase LSAPI_CHILDREN.\n",
2757                                pServer->m_iMaxChildren, pServer->m_iExtraChildren, pServer->m_iCurChildren );
2758            usleep( 100000 );
2759            continue;
2760        }
2761
2762        FD_ZERO( &readfds );
2763        FD_SET( pServer->m_fd, &readfds );
2764        timeout.tv_sec = 1; timeout.tv_usec = 0;
2765        if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 )
2766        {
2767            /*
2768            if ( pServer->m_iCurChildren >= 0 )
2769            {
2770                usleep( 10 );
2771                FD_ZERO( &readfds );
2772                FD_SET( pServer->m_fd, &readfds );
2773                timeout.tv_sec = 0; timeout.tv_usec = 0;
2774                if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 )
2775                    continue;
2776            }*/
2777        }
2778        else if ( ret == -1 )
2779        {
2780            if ( errno == EINTR )
2781                continue;
2782            /* perror( "select()" ); */
2783            break;
2784        }
2785        else
2786        {
2787            continue;
2788        }
2789
2790        pReq->m_fd = lsapi_accept( pServer->m_fd );
2791        if ( pReq->m_fd != -1 )
2792        {
2793            child_status = find_child_status( 0 );
2794            if ( child_status )
2795                memset( child_status, 0, sizeof( *child_status ) );
2796
2797            sigemptyset( &mask );
2798            sigaddset( &mask, SIGCHLD );
2799
2800            if ( sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0 )
2801            {
2802                perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" );
2803            }
2804
2805            pid = fork();
2806
2807            if ( !pid )
2808            {
2809                if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
2810                    perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" );
2811                g_prefork_server = NULL;
2812                s_ppid = getppid();
2813                s_req_processed = 0;
2814                s_pChildStatus = child_status;
2815                lsapi_set_nblock( pReq->m_fd, 0 );
2816                if ( pReq->m_fdListen != -1 )
2817                {
2818                    close( pReq->m_fdListen );
2819                    pReq->m_fdListen = -1;
2820                }
2821                /* don't catch our signals */
2822                sigaction( SIGCHLD, &old_child, 0 );
2823                sigaction( SIGTERM, &old_term, 0 );
2824                sigaction( SIGQUIT, &old_quit, 0 );
2825                sigaction( SIGINT,  &old_int,  0 );
2826                sigaction( SIGUSR1, &old_usr1, 0 );
2827                //init_conn_key( pReq->m_fd );
2828                lsapi_notify_pid( pReq->m_fd );
2829                s_notified_pid = 1;
2830                //if ( s_accept_notify )
2831                //    return notify_req_received( pReq->m_fd );
2832                return 0;
2833            }
2834            else if ( pid == -1 )
2835            {
2836                perror( "fork() failed, please increase process limit" );
2837            }
2838            else
2839            {
2840                ++pServer->m_iCurChildren;
2841                if ( child_status )
2842                {
2843                    child_status->m_pid = pid;
2844                    child_status->m_tmWaitBegin = curTime;
2845                    child_status->m_tmStart = curTime;
2846                }
2847            }
2848            close( pReq->m_fd );
2849            pReq->m_fd = -1;
2850
2851            if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
2852                perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK" );
2853
2854        }
2855        else
2856        {
2857            if (( errno == EINTR )||( errno == EAGAIN))
2858                continue;
2859            perror( "accept() failed" );
2860            return -1;
2861        }
2862    }
2863    sigaction( SIGUSR1, &old_usr1, 0 );
2864    //kill( -getpgrp(), SIGUSR1 );
2865    //lsapi_all_children_must_die();  /* Sorry, children ;-) */
2866    return -1;
2867
2868}
2869
2870void lsapi_error( const char * pMessage, int err_no )
2871{
2872    fprintf( stderr, "%d: %s, errno: %d (%s)\n", getpid(), pMessage, err_no, strerror( err_no ) );
2873}
2874
2875int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
2876{
2877    int             fd;
2878    int             ret;
2879    int             wait_secs;
2880    fd_set          readfds;
2881    struct timeval  timeout;
2882
2883    LSAPI_Finish_r( pReq );
2884
2885
2886    if ( g_prefork_server )
2887    {
2888        if ( g_prefork_server->m_fd != -1 )
2889            if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
2890                return -1;
2891    }
2892    if ( s_req_processed >= s_max_reqs )
2893        return -1;
2894
2895    if ( s_pChildStatus )
2896    {
2897        s_pChildStatus->m_tmWaitBegin = time( NULL );
2898    }
2899
2900
2901    while( g_running )
2902    {
2903        if ( pReq->m_fd != -1 )
2904        {
2905            fd = pReq->m_fd;
2906        }
2907        else if ( pReq->m_fdListen != -1 )
2908            fd = pReq->m_fdListen;
2909        else
2910        {
2911            break;
2912        }
2913        wait_secs = 0;
2914        while( 1 )
2915        {
2916            if ( !g_running )
2917                return -1;
2918            if ((s_req_processed)&&( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
2919                return -1;
2920            FD_ZERO( &readfds );
2921            FD_SET( fd, &readfds );
2922            timeout.tv_sec = 1;
2923            timeout.tv_usec = 0;
2924            ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout);
2925            if ( ret == 0 )
2926            {
2927                if ( s_pChildStatus )
2928                {
2929                    s_pChildStatus->m_inProcess = 0;
2930                }
2931                ++wait_secs;
2932                if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
2933                    return -1;
2934                if ( s_ppid &&( getppid() != s_ppid))
2935                    return -1;
2936            }
2937            else if ( ret == -1 )
2938            {
2939                if ( errno == EINTR )
2940                    continue;
2941                else
2942                    return -1;
2943            }
2944            else if ( ret >= 1 )
2945            {
2946                if (s_req_processed && ( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
2947                    return -1;
2948                if ( fd == pReq->m_fdListen )
2949                {
2950                    pReq->m_fd = lsapi_accept( pReq->m_fdListen );
2951                    if ( pReq->m_fd != -1 )
2952                    {
2953                        fd = pReq->m_fd;
2954                        lsapi_set_nblock( fd, 0 );
2955                        //init_conn_key( pReq->m_fd );
2956                        if ( !s_keepListener )
2957                        {
2958                            close( pReq->m_fdListen );
2959                            pReq->m_fdListen = -1;
2960                        }
2961                        if ( s_accept_notify )
2962                            if ( notify_req_received( pReq->m_fd ) == -1 )
2963                                return -1;
2964                    }
2965                    else
2966                    {
2967                        if (( errno == EINTR )||( errno == EAGAIN))
2968                            continue;
2969                        lsapi_error( "lsapi_accept() error", errno );
2970                        return -1;
2971                    }
2972                }
2973                else
2974                    break;
2975            }
2976        }
2977
2978        if ( !readReq( pReq ) )
2979        {
2980            if ( s_pChildStatus )
2981            {
2982                s_pChildStatus->m_iKillSent = 0;
2983                s_pChildStatus->m_inProcess = 1;
2984                ++s_pChildStatus->m_iReqCounter;
2985                s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL);
2986            }
2987            ++s_req_processed;
2988            return 0;
2989        }
2990        lsapi_close( pReq->m_fd );
2991        pReq->m_fd = -1;
2992        LSAPI_Reset_r( pReq );
2993    }
2994    return -1;
2995
2996}
2997
2998void LSAPI_Set_Max_Reqs( int reqs )
2999{   s_max_reqs = reqs;          }
3000
3001void LSAPI_Set_Max_Idle( int secs )
3002{   s_max_idle_secs = secs;     }
3003
3004void LSAPI_Set_Max_Children( int maxChildren )
3005{
3006    if ( g_prefork_server )
3007        g_prefork_server->m_iMaxChildren = maxChildren;
3008}
3009
3010void LSAPI_Set_Extra_Children( int extraChildren )
3011{
3012    if (( g_prefork_server )&&( extraChildren >= 0 ))
3013        g_prefork_server->m_iExtraChildren = extraChildren;
3014}
3015
3016void LSAPI_Set_Max_Process_Time( int secs )
3017{
3018    if (( g_prefork_server )&&( secs > 0 ))
3019        g_prefork_server->m_iMaxReqProcessTime = secs;
3020}
3021
3022
3023void LSAPI_Set_Max_Idle_Children( int maxIdleChld )
3024{
3025    if (( g_prefork_server )&&( maxIdleChld > 0 ))
3026        g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
3027}
3028
3029void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle )
3030{
3031    if ( g_prefork_server )
3032        g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
3033}
3034
3035void LSAPI_Set_Slow_Req_Msecs( int msecs )
3036{
3037    s_slow_req_msecs = msecs;
3038}
3039
3040int  LSAPI_Get_Slow_Req_Msecs()
3041{
3042    return s_slow_req_msecs;
3043}
3044
3045
3046void LSAPI_No_Check_ppid()
3047{
3048    s_ppid = 0;
3049}
3050
3051#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3052#include <crt_externs.h>
3053#else
3054extern char ** environ;
3055#endif
3056static void unset_lsapi_envs()
3057{
3058    char **env;
3059#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
3060    env = *_NSGetEnviron();
3061#else
3062    env = environ;
3063#endif
3064    while( env != NULL && *env != NULL )
3065    {
3066        if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 )
3067            || (!strncmp( *env, "PHPRC=", 6 )&&(!s_uid)))
3068        {
3069            char ** del = env;
3070            do
3071                *del = del[1];
3072            while( *del++ );
3073        }
3074        else
3075            ++env;
3076    }
3077}
3078
3079static int lsapi_initSuEXEC()
3080{
3081    int i;
3082    struct passwd * pw;
3083    s_defaultUid = 0;
3084    s_defaultGid = 0;
3085    if ( s_uid == 0 )
3086    {
3087        const char * p = getenv( "LSAPI_DEFAULT_UID" );
3088        if ( p )
3089        {
3090            i = atoi( p );
3091            if ( i > 0 )
3092                s_defaultUid = i;
3093        }
3094        p = getenv( "LSAPI_DEFAULT_GID" );
3095        if ( p )
3096        {
3097            i = atoi( p );
3098            if ( i > 0 )
3099                s_defaultGid = i;
3100        }
3101        p = getenv( "LSAPI_SECRET" );
3102        if (( !p )||( readSecret(p) == -1 ))
3103                return -1;
3104        if ( g_prefork_server )
3105        {
3106            if ( g_prefork_server->m_iMaxChildren < 100 )
3107                g_prefork_server->m_iMaxChildren = 100;
3108            if ( g_prefork_server->m_iExtraChildren < 1000 )
3109                g_prefork_server->m_iExtraChildren = 1000;
3110        }
3111    }
3112    if ( !s_defaultUid || !s_defaultGid )
3113    {
3114        pw = getpwnam( "nobody" );
3115        if ( !s_defaultUid )
3116            s_defaultUid = pw->pw_uid;
3117        if ( !s_defaultGid )
3118            s_defaultGid = pw->pw_gid;
3119    }
3120    return 0;
3121}
3122
3123
3124int LSAPI_Init_Env_Parameters( fn_select_t fp )
3125{
3126    const char *p;
3127    int n;
3128    int avoidFork = 0;
3129    p = getenv( "PHP_LSAPI_MAX_REQUESTS" );
3130    if ( !p )
3131        p = getenv( "LSAPI_MAX_REQS" );
3132    if ( p )
3133    {
3134        n = atoi( p );
3135        if ( n > 0 )
3136            LSAPI_Set_Max_Reqs( n );
3137    }
3138
3139    p = getenv( "LSAPI_AVOID_FORK" );
3140    if ( p )
3141    {
3142        avoidFork = atoi( p );
3143    }
3144
3145    p = getenv( "LSAPI_ACCEPT_NOTIFY" );
3146    if ( p )
3147    {
3148        s_accept_notify = atoi( p );
3149    }
3150
3151    p = getenv( "LSAPI_SLOW_REQ_MSECS" );
3152    if ( p )
3153    {
3154        n = atoi( p );
3155        LSAPI_Set_Slow_Req_Msecs( n );
3156    }
3157
3158#if defined( RLIMIT_CORE )
3159    p = getenv( "LSAPI_ALLOW_CORE_DUMP" );
3160    if ( !p )
3161    {
3162        struct rlimit limit = { 0, 0 };
3163        setrlimit( RLIMIT_CORE, &limit );
3164    }
3165    else
3166        s_enable_core_dump = 1;
3167
3168#endif
3169
3170    p = getenv( "LSAPI_MAX_IDLE" );
3171    if ( p )
3172    {
3173        n = atoi( p );
3174        LSAPI_Set_Max_Idle( n );
3175    }
3176
3177    p = getenv( "LSAPI_KEEP_LISTEN" );
3178    if ( p )
3179    {
3180        n = atoi( p );
3181        s_keepListener = n;
3182    }
3183
3184
3185    if ( LSAPI_Is_Listen() )
3186    {
3187        n = 0;
3188        p = getenv( "PHP_LSAPI_CHILDREN" );
3189        if ( !p )
3190            p = getenv( "LSAPI_CHILDREN" );
3191        if ( p )
3192            n = atoi( p );
3193        if ( n > 1 )
3194        {
3195            LSAPI_Init_Prefork_Server( n, fp, avoidFork );
3196            LSAPI_Set_Server_fd( g_req.m_fdListen );
3197        }
3198
3199        p = getenv( "LSAPI_EXTRA_CHILDREN" );
3200        if ( p )
3201            LSAPI_Set_Extra_Children( atoi( p ) );
3202
3203        p = getenv( "LSAPI_MAX_IDLE_CHILDREN" );
3204        if ( p )
3205            LSAPI_Set_Max_Idle_Children( atoi( p ) );
3206
3207        p = getenv( "LSAPI_PGRP_MAX_IDLE" );
3208        if ( p )
3209        {
3210            LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) );
3211        }
3212
3213        p = getenv( "LSAPI_MAX_PROCESS_TIME" );
3214        if ( p )
3215            LSAPI_Set_Max_Process_Time( atoi( p ) );
3216
3217        if ( getenv( "LSAPI_PPID_NO_CHECK" ) )
3218        {
3219            LSAPI_No_Check_ppid();
3220        }
3221
3222        p = getenv( "LSAPI_DUMP_DEBUG_INFO" );
3223        if ( p )
3224            s_dump_debug_info = atoi( p );
3225
3226        if ( lsapi_initSuEXEC() == -1 )
3227            return -1;
3228#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
3229        lsapi_initLVE();
3230#endif
3231    }
3232    unset_lsapi_envs();
3233    return 0;
3234}
3235
3236
3237int LSAPI_ErrResponse_r( LSAPI_Request * pReq, int code, const char ** pRespHeaders,
3238                         const char * pBody, int bodyLen )
3239{
3240    LSAPI_SetRespStatus_r( pReq, code );
3241    if ( pRespHeaders )
3242    {
3243        while( *pRespHeaders )
3244        {
3245            LSAPI_AppendRespHeader_r( pReq, *pRespHeaders, strlen( *pRespHeaders ) );
3246            ++pRespHeaders;
3247        }
3248    }
3249    if ( pBody &&( bodyLen > 0 ))
3250    {
3251        LSAPI_Write_r( pReq, pBody, bodyLen );
3252    }
3253    LSAPI_Finish_r( pReq );
3254    return 0;
3255}
3256
3257
3258static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16]);
3259
3260/*
3261 * Note: this code is harmless on little-endian machines.
3262 */
3263static void byteReverse(unsigned char *buf, unsigned longs)
3264{
3265    uint32 t;
3266    do {
3267        t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
3268            ((unsigned) buf[1] << 8 | buf[0]);
3269        *(uint32 *) buf = t;
3270        buf += 4;
3271    } while (--longs);
3272}
3273
3274/*
3275 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
3276 * initialization constants.
3277 */
3278void lsapi_MD5Init(struct lsapi_MD5Context *ctx)
3279{
3280    ctx->buf[0] = 0x67452301;
3281    ctx->buf[1] = 0xefcdab89;
3282    ctx->buf[2] = 0x98badcfe;
3283    ctx->buf[3] = 0x10325476;
3284
3285    ctx->bits[0] = 0;
3286    ctx->bits[1] = 0;
3287}
3288
3289/*
3290 * Update context to reflect the concatenation of another buffer full
3291 * of bytes.
3292 */
3293void lsapi_MD5Update(struct lsapi_MD5Context *ctx, unsigned char const *buf, unsigned len)
3294{
3295    register uint32 t;
3296
3297    /* Update bitcount */
3298
3299    t = ctx->bits[0];
3300    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
3301        ctx->bits[1]++;                /* Carry from low to high */
3302    ctx->bits[1] += len >> 29;
3303
3304    t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
3305
3306    /* Handle any leading odd-sized chunks */
3307
3308    if (t) {
3309        unsigned char *p = (unsigned char *) ctx->in + t;
3310
3311        t = 64 - t;
3312        if (len < t) {
3313            memmove(p, buf, len);
3314            return;
3315        }
3316        memmove(p, buf, t);
3317        byteReverse(ctx->in, 16);
3318        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3319        buf += t;
3320        len -= t;
3321    }
3322    /* Process data in 64-byte chunks */
3323
3324    while (len >= 64) {
3325        memmove(ctx->in, buf, 64);
3326        byteReverse(ctx->in, 16);
3327        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3328        buf += 64;
3329        len -= 64;
3330    }
3331
3332    /* Handle any remaining bytes of data. */
3333
3334    memmove(ctx->in, buf, len);
3335}
3336
3337/*
3338 * Final wrapup - pad to 64-byte boundary with the bit pattern
3339 * 1 0* (64-bit count of bits processed, MSB-first)
3340 */
3341void lsapi_MD5Final(unsigned char digest[16], struct lsapi_MD5Context *ctx)
3342{
3343    unsigned int count;
3344    unsigned char *p;
3345
3346    /* Compute number of bytes mod 64 */
3347    count = (ctx->bits[0] >> 3) & 0x3F;
3348
3349    /* Set the first char of padding to 0x80.  This is safe since there is
3350       always at least one byte free */
3351    p = ctx->in + count;
3352    *p++ = 0x80;
3353
3354    /* Bytes of padding needed to make 64 bytes */
3355    count = 64 - 1 - count;
3356
3357    /* Pad out to 56 mod 64 */
3358    if (count < 8) {
3359        /* Two lots of padding:  Pad the first block to 64 bytes */
3360        memset(p, 0, count);
3361        byteReverse(ctx->in, 16);
3362        lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3363
3364        /* Now fill the next block with 56 bytes */
3365        memset(ctx->in, 0, 56);
3366    } else {
3367        /* Pad block to 56 bytes */
3368        memset(p, 0, count - 8);
3369    }
3370    byteReverse(ctx->in, 14);
3371
3372    /* Append length in bits and transform */
3373    ((uint32 *) ctx->in)[14] = ctx->bits[0];
3374    ((uint32 *) ctx->in)[15] = ctx->bits[1];
3375
3376    lsapi_MD5Transform(ctx->buf, (uint32 *) ctx->in);
3377    byteReverse((unsigned char *) ctx->buf, 4);
3378    memmove(digest, ctx->buf, 16);
3379    memset(ctx, 0, sizeof(ctx));        /* In case it's sensitive */
3380}
3381
3382/* The four core functions - F1 is optimized somewhat */
3383
3384/* #define F1(x, y, z) (x & y | ~x & z) */
3385#define F1(x, y, z) (z ^ (x & (y ^ z)))
3386#define F2(x, y, z) F1(z, x, y)
3387#define F3(x, y, z) (x ^ y ^ z)
3388#define F4(x, y, z) (y ^ (x | ~z))
3389
3390/* This is the central step in the MD5 algorithm. */
3391#define MD5STEP(f, w, x, y, z, data, s) \
3392        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
3393
3394/*
3395 * The core of the MD5 algorithm, this alters an existing MD5 hash to
3396 * reflect the addition of 16 longwords of new data.  MD5Update blocks
3397 * the data and converts bytes into longwords for this routine.
3398 */
3399static void lsapi_MD5Transform(uint32 buf[4], uint32 const in[16])
3400{
3401    register uint32 a, b, c, d;
3402
3403    a = buf[0];
3404    b = buf[1];
3405    c = buf[2];
3406    d = buf[3];
3407
3408    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
3409    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
3410    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
3411    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
3412    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
3413    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
3414    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
3415    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
3416    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
3417    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
3418    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
3419    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
3420    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
3421    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
3422    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
3423    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
3424
3425    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
3426    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
3427    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
3428    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
3429    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
3430    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
3431    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
3432    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
3433    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
3434    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
3435    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
3436    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
3437    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
3438    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
3439    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
3440    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
3441
3442    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
3443    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
3444    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
3445    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
3446    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
3447    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
3448    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
3449    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
3450    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
3451    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
3452    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
3453    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
3454    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
3455    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
3456    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
3457    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
3458
3459    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
3460    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
3461    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
3462    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
3463    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
3464    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
3465    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
3466    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
3467    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
3468    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
3469    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
3470    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
3471    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
3472    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
3473    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
3474    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
3475
3476    buf[0] += a;
3477    buf[1] += b;
3478    buf[2] += c;
3479    buf[3] += d;
3480}
3481
3482