/* * The contents of this file are subject to the AOLserver Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://aolserver.com/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is AOLserver Code and related documentation * distributed by AOL. * * The Initial Developer of the Original Code is America Online, * Inc. Portions created by AOL are Copyright (C) 1999 America Online, * Inc. All Rights Reserved. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License (the "GPL"), in which case the * provisions of GPL are applicable instead of those above. If you wish * to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the * License, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the License or the GPL. */ /* * limits.c -- * * Routines to manage resource limits. */ static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/limits.c,v 1.10 2005/03/28 00:06:44 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; #include "nsd.h" /* * Static functions defined in this file. */ static int LimitsResult(Tcl_Interp *interp, Limits *limitsPtr); static int AppendLimit(Tcl_Interp *interp, char *limit, unsigned int val); static int GetLimits(Tcl_Interp *interp, Tcl_Obj *objPtr, Limits **limitsPtrPtr, int create); static Limits *FindLimits(char *limits, int create); /* * Static variables defined in this file. */ static int limid; static Limits *defLimitsPtr; static Tcl_HashTable limtable; /* *---------------------------------------------------------------------- * * NsInitLimits -- * * Initialize request limits. * * Results: * None. * * Side effects: * Will create the default limits. * *---------------------------------------------------------------------- */ void NsInitLimits(void) { limid = Ns_UrlSpecificAlloc(); Tcl_InitHashTable(&limtable, TCL_STRING_KEYS); defLimitsPtr = FindLimits("default", 1); } /* *---------------------------------------------------------------------- * *NsTclLimitsObjCmd -- * * Implements ns_limits command to create and query request limit * structures. * * Results: * Standard Tcl result. * * Side effects: * May create a new limit structure. * *---------------------------------------------------------------------- */ int NsTclLimitsObjCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj **objv) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; Limits *limitsPtr, saveLimits; char *limits, *pattern; int i, val; static CONST char *opts[] = { "get", "set", "list", "register", NULL }; enum { LGetIdx, LSetIdx, LListIdx, LRegisterIdx } opt; static CONST char *cfgs[] = { "-maxrun", "-maxwait", "-maxupload", "-timeout", NULL }; enum { LCRunIdx, LCWaitIdx, LCUploadIdx, LCTimeoutIdx } cfg; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, (int *) &opt) != TCL_OK) { return TCL_ERROR; } switch (opt) { case LListIdx: if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } if (objc == 2) { pattern = NULL; } else { pattern = Tcl_GetString(objv[2]); } hPtr = Tcl_FirstHashEntry(&limtable, &search); while (hPtr != NULL) { limits = Tcl_GetHashKey(&limtable, hPtr); if (pattern == NULL || Tcl_StringMatch(limits, pattern)) { Tcl_AppendElement(interp, limits); } hPtr = Tcl_NextHashEntry(&search); } break; case LGetIdx: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "limit"); return TCL_ERROR; } if (GetLimits(interp, objv[2], &limitsPtr, 0) != TCL_OK || LimitsResult(interp, limitsPtr) != TCL_OK) { return TCL_ERROR; } break; case LSetIdx: if (objc < 3 || (((objc - 3) % 2) != 0)) { Tcl_WrongNumArgs(interp, 2, objv, "limit ?opt val opt val...?"); return TCL_ERROR; } (void) GetLimits(interp, objv[2], &limitsPtr, 1); saveLimits = *limitsPtr; for (i = 3; i < objc; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], cfgs, "cfg", 0, (int *) &cfg) != TCL_OK || Tcl_GetIntFromObj(interp, objv[i+1], &val) != TCL_OK) { *limitsPtr = saveLimits; return TCL_ERROR; } switch (cfg) { case LCRunIdx: limitsPtr->maxrun = val; break; case LCWaitIdx: limitsPtr->maxwait = val; break; case LCUploadIdx: limitsPtr->maxupload = val; break; case LCTimeoutIdx: limitsPtr->timeout = val; break; } } if (LimitsResult(interp, limitsPtr) != TCL_OK) { return TCL_ERROR; } break; case LRegisterIdx: if (objc != 6) { Tcl_WrongNumArgs(interp, 2, objv, "limit server method url"); return TCL_ERROR; } if (GetLimits(interp, objv[2], &limitsPtr, 0) != TCL_OK) { return TCL_ERROR; } Ns_UrlSpecificSet(Tcl_GetString(objv[3]), Tcl_GetString(objv[4]), Tcl_GetString(objv[5]), limid, limitsPtr, 0, NULL); break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * NsGetRequestLimits -- * * Return the limits structure for a given request. * * Results: * Pointer to limits. * * Side effects: * May return the default limits if no more specific limits * have been created. * *---------------------------------------------------------------------- */ Limits * NsGetRequestLimits(char *server, char *method, char *url) { Limits *limitsPtr; limitsPtr = Ns_UrlSpecificGet(server, method, url, limid); return (limitsPtr ? limitsPtr : defLimitsPtr); } /* *---------------------------------------------------------------------- * * FindLimits -- * * Return the limits by name. * * Results: * Pointer to Limits or NULL if no such limits and create is zero. * * Side effects: * If create is not zero, will create new default limits. * *---------------------------------------------------------------------- */ static Limits * FindLimits(char *limits, int create) { Limits *limitsPtr; Tcl_HashEntry *hPtr; int new; if (!create) { hPtr = Tcl_FindHashEntry(&limtable, limits); } else { hPtr = Tcl_CreateHashEntry(&limtable, limits, &new); if (new) { limitsPtr = ns_malloc(sizeof(Limits)); limitsPtr->name = Tcl_GetHashKey(&limtable, hPtr); Ns_MutexInit(&limitsPtr->lock); limitsPtr->nrunning = limitsPtr->nwaiting = 0; limitsPtr->ntimeout = limitsPtr->ndropped = limitsPtr->noverflow = 0; limitsPtr->maxrun = limitsPtr->maxwait = 100; limitsPtr->maxupload = 10 * 1024 * 1000; /* NB: 10meg limit. */ limitsPtr->timeout = 60; Tcl_SetHashValue(hPtr, limitsPtr); } } return (hPtr ? Tcl_GetHashValue(hPtr) : NULL); } /* *---------------------------------------------------------------------- * * GetLimits -- * * Utility routing to find Limits by Tcl_Obj for Tcl. * * Results: * Standard Tcl result. * * Side effects: * Will update limitsPtrPtr with pointer to Limits or leave * an error message in given interp if no limits found and * create is zero. * *---------------------------------------------------------------------- */ static int GetLimits(Tcl_Interp *interp, Tcl_Obj *objPtr, Limits **limitsPtrPtr, int create) { char *limits = Tcl_GetString(objPtr); Limits *limitsPtr; limitsPtr = FindLimits(limits, create); if (limitsPtr == NULL) { Tcl_AppendResult(interp, "no such limits: ", limits, NULL); return TCL_ERROR; } *limitsPtrPtr = limitsPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * LimitsResult -- * * Return a list of info about a given limits. * * Results: * TCL_ERROR if list could not be appended, TCL_OK otherwise. * * Side effects: * Will leave list in given interp result. * *---------------------------------------------------------------------- */ static int LimitsResult(Tcl_Interp *interp, Limits *limitsPtr) { if (!AppendLimit(interp, "nrunning", limitsPtr->nrunning) || !AppendLimit(interp, "nwaiting", limitsPtr->nwaiting) || !AppendLimit(interp, "ntimeout", limitsPtr->ntimeout) || !AppendLimit(interp, "ndropped", limitsPtr->ndropped) || !AppendLimit(interp, "noverflow", limitsPtr->noverflow) || !AppendLimit(interp, "maxwait", limitsPtr->maxwait) || !AppendLimit(interp, "maxupload", limitsPtr->maxupload) || !AppendLimit(interp, "timeout", limitsPtr->timeout) || !AppendLimit(interp, "maxrun", limitsPtr->maxrun)) { return TCL_ERROR; } return TCL_OK; } static int AppendLimit(Tcl_Interp *interp, char *limit, unsigned int val) { Tcl_Obj *result = Tcl_GetObjResult(interp); if (Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(limit, -1)) != TCL_OK || Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj((int) val)) != TCL_OK) { return 0; } return 1; }