/*
 * The http_max_server_clients function computes the maximum number of
 * current clients that the current process can safely.  This number
 * is the minimum of:
 *
 *     quota   	limit				Observed usage
 *     bytlm    (bytcnt-500) / 4000		2200 bytes/thread.
 *     fillm	(filcnt) / 2			1 file/thread.
 *     biolm	(biolm-4) / 2			1 I/O / thread.
 *     diolm	(diolm-4) / 2			1 I/O / thread.
 *     astlm	(astcnt-3) / 2			1 ast / thread.
 *     pgfil	(pgcnt-3000) / 200		 <100 pages /thread
 *
 *     channelcnt  (channelcnt-30)/3 -
 *		ip_listen_threads 		<30 + 2 channels/thread
 *    
 * The is_sysgrp function checks if current process uic will implcitly
 * grants sysprv to the process (UIC group number less than sysgen parameter
 * SYSGRP.
 *
 * Revised: 2-sep-1995		write messages to log file rather than printf.
 * Revised: 24-OCT-1995		Use current quota instead of permanent for
 *				bytlm, file,  and page file.
 * Revised: 20-DEC-1995		Remove Lvalue references.
 * Revised:  2-APR-1996		Include SYSGEN channelcnt in limit calculation.
 * Revised: 5-APR-1996		Support http_client_limit_override.
 * Revised: 9-dec-1996		Include MST stack consumption in limit calc.
 * Revised: 2-APR-1997		Include http_local_ip_addresses.
 * Revised: 25-AUG-2000		Remove cache_size reference from pagefile
 *				calculation since cache already accounted for
 *				by value returned from LIB$GETJPI.
 * Revised: 25-AUG-2000		Make dummy write to stderr for work around
 *				C RTL bug (do here rather than main() so this
 *				patch can apply to all versions since 1997).
 */     

#include <stdlib.h>
#include <stdio.h>
#include <jpidef.h>
#include <syidef.h>
#ifdef VAXC
#ifndef __ALPHA
#pragma builtins
#endif
#endif
#include "message_service.h"

int http_local_ip_addresses;	/* number of listen threads */

#define LIMIT_MESSAGE2 "Process !AZ (!SL) limits server to !SL client threads.!/"
#define SLIMIT_MESSAGE2 "System !AZ (!SL) limits server to !SL client threads.!/"
#define A(v) (lval=v,&lval)

int tlog_putlog(int,char *,...);
int LIB$GETJPI(), LIB$GETSYI();

int http_max_server_clients ( int user_limit, int cache_size )
{
    int bytlm, fillm, biolm, diolm, astlm, pgfil, limit, test_limit;
    int channelcnt, lval, override, mst_threads, mst_stack;
    /*
     * Check for inhibit.
     */
    if ( getenv("http_client_limit_override") ) {
	tlog_putlog (0,"Warning, client limit checks will not be enforced!!!/");
	override = 1;
    } else override = 0;
    /*
     * Get the current quotas.
     */
    LIB$GETJPI ( A(JPI$_BYTCNT), 0, 0, &bytlm );
    LIB$GETJPI ( A(JPI$_BIOLM), 0, 0, &biolm );
    LIB$GETJPI ( A(JPI$_DIOLM), 0, 0, &diolm );
    LIB$GETJPI ( A(JPI$_FILCNT), 0, 0, &fillm );
    LIB$GETJPI ( A(JPI$_ASTCNT), 0, 0, &astlm );
    LIB$GETJPI ( A(JPI$_PAGFILCNT), 0, 0, &pgfil );
    LIB$GETSYI ( A(SYI$_CHANNELCNT), &channelcnt );
    /*
     * Reduce page file count by max usage forseen for MST
     */
    mst_usage_limits ( 32768, &mst_threads, &mst_stack );
    mst_stack = mst_stack/512;
    tlog_putlog ( 1, "Estimated max MST stack pages: !SL!/", mst_stack );
    /*
     * Restrict limit.
     */
    limit = user_limit;
    test_limit = (bytlm-500) / 4000;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog( 0,LIMIT_MESSAGE2, "bytlm", bytlm, test_limit );
    }

    test_limit = (fillm-4) / 2;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, LIMIT_MESSAGE2, "fillm", fillm, test_limit );
    }                                                             

    test_limit = (biolm-4) / 2;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, LIMIT_MESSAGE2, "biolm", biolm, test_limit );
    }

    test_limit = (diolm-4) / 2;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, LIMIT_MESSAGE2, "diolm", diolm, test_limit );
    }

    test_limit = (astlm-6) / 2;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, LIMIT_MESSAGE2, "astlm", astlm, test_limit );
    }

    test_limit = (pgfil-(3000 + mst_stack)) / 200;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, LIMIT_MESSAGE2, "pagefile quota", pgfil, test_limit );
    }

    test_limit = ((channelcnt-30) / 3) - http_local_ip_addresses;
    if ( test_limit < user_limit ) {
	if ( test_limit < limit && !override ) limit = test_limit;
	tlog_putlog(0, SLIMIT_MESSAGE2, "channelcnt parameter", channelcnt,
		test_limit );
    }
    /*
     * Write final client limit to stderr to force CRTL initialize of
     * FD 2.  This avoids a race condition that can cause server hangs
     * when the first write to stderr occurs under high load situations.
     */
    fprintf ( stderr, "Server client limit computed as %d\n", limit );

    return limit;
}
/**************************************************************************/
/* Return 1 if process uic is less than sysgen parameter. */
int is_sysgrp()
{
    int uic_grp, maxsysgrp, status, lval;

    status = LIB$GETJPI ( A(JPI$_GRP), 0, 0, &uic_grp );
    if ( (status&1) == 0 ) printf ( "Error in getjpi: %d\n", status );

    status = LIB$GETSYI ( A(SYI$_MAXSYSGROUP), &maxsysgrp );
    if ( (status&1) == 0 ) printf ( "Error in getsyi: %d\n", status );
    return (uic_grp <= maxsysgrp ) ? 1 : 0;
}
