Update of /cvsroot/aolserver/aolserver/nsd In directory sfp-cvsdas-1.v30.ch3.sourceforge.com:/tmp/cvs-serv9603 Modified Files: Makefile conn.c connio.c driver.c queue.c tclcmds.c tclrequest.c tclsock.c Added Files: tclstore.c Log Message: Added read and write filters, fixed bugs with pre-queue filters and que-wait callbacks, added ns_tls, ns_cls, and ns_quewait commands. --- NEW FILE: tclstore.c --- /* * 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. */ /* * tclstore.c -- * * Thread and connection local storage Tcl commands. */ static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/tclstore.c,v 1.1 2009/12/08 04:12:20 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; #include "nsd.h" /* * Static functions defined in this file. */ static int StoreObjCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj **objv, int tls); /* *---------------------------------------------------------------------- * * NsTclTlsObjCmd, NsTclClsObjCmd -- * * Implements ns_tls and ns_cls as obj commands. * * Results: * Tcl result. * * Side effects: * See docs. * *---------------------------------------------------------------------- */ int NsTclTlsObjCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj **objv, Ns_Conn *conn) { return StoreObjCmd(data, interp, objc, objv, 1); } int NsTclClsObjCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj **objv, Ns_Conn *conn) { return StoreObjCmd(data, interp, objc, objv, 0); } static int StoreObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv, int tls) { static CONST char *opts[] = { "alloc", "get", "set", NULL }; enum { AllocIdx, GetIdx, SetIdx } _nsmayalias opt; Ns_Conn *conn; char *val; int id; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, (int *) &opt) != TCL_OK) { return TCL_ERROR; } if (opt == AllocIdx) { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } if (tls) { Ns_TlsAlloc((Ns_Tls *) &id, ns_free); } else { Ns_ClsAlloc((Ns_Cls *) &id, ns_free); } Tcl_SetObjResult(interp, Tcl_NewIntObj(id)); } else { if (!tls && NsTclGetConn((NsInterp *) arg, &conn) != TCL_OK) { return TCL_ERROR; } if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "index"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &id) != TCL_OK) { return TCL_ERROR; } if (id < 1 || id >= (tls ? NS_THREAD_MAXTLS : NS_CONN_MAXCLS)) { Tcl_AppendResult(interp, "invalid id: ", Tcl_GetString(objv[2]), NULL); return TCL_ERROR; } if (tls) { val = Ns_TlsGet((Ns_Tls *) &id); } else { val = Ns_ClsGet((Ns_Cls *) &id, conn); } if (opt == GetIdx) { Tcl_SetResult(interp, val, TCL_VOLATILE); } else { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "index value"); return TCL_ERROR; } if (val) { ns_free(val); } val = ns_strdup(Tcl_GetString(objv[3])); if (tls) { Ns_TlsSet((Ns_Tls *) &id, (void **) val); } else { Ns_ClsSet((Ns_Cls *) &id, conn, (void **) val); } } } return TCL_OK; } Index: Makefile =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/Makefile,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -d -r1.52 -r1.53 *** Makefile 27 Jun 2006 16:35:55 -0000 1.52 --- Makefile 8 Dec 2009 04:12:19 -0000 1.53 *************** *** 48,52 **** tclhttp.o tclimg.o tclinit.o tcljob.o tclloop.o tclmisc.o \ tclobj.o tclrequest.o tclresp.o tclsched.o tclset.o tclshare.o \ ! tclsock.o tclthread.o tclvar.o tclxkeylist.o url.o \ urlencode.o urlopen.o urlspace.o uuencode.o stamp.o --- 48,52 ---- tclhttp.o tclimg.o tclinit.o tcljob.o tclloop.o tclmisc.o \ tclobj.o tclrequest.o tclresp.o tclsched.o tclset.o tclshare.o \ ! tclsock.o tclstore.o tclthread.o tclvar.o tclxkeylist.o url.o \ urlencode.o urlopen.o urlspace.o uuencode.o stamp.o Index: conn.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/conn.c,v retrieving revision 1.49 retrieving revision 1.50 diff -C2 -d -r1.49 -r1.50 *** conn.c 29 Sep 2007 20:08:52 -0000 1.49 --- conn.c 8 Dec 2009 04:12:19 -0000 1.50 *************** *** 144,148 **** * Ns_ConnContentLength -- * ! * Get the content length from the client * * Results: --- 144,150 ---- * Ns_ConnContentLength -- * ! * Get the content length to be sent from the client. ! * Note the data may not have been all received if ! * called in a "read" filter callback. * * Results: *************** *** 165,168 **** --- 167,197 ---- *---------------------------------------------------------------------- * + * Ns_ConnContentAvail -- + * + * Get the content currently available from the client. + * This will generally be all content unless it's called + * during a read filter callback during upload. + * + * Results: + * An integer content length, or 0 if none sent + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_ConnContentAvail(Ns_Conn *conn) + { + Conn *connPtr = (Conn *) conn; + + return connPtr->avail; + } + + + /* + *---------------------------------------------------------------------- + * * Ns_ConnContent -- * *************** *** 1007,1012 **** static CONST char *opts[] = { ! "authpassword", "authuser", "channel", "close", "content", "contentlength", ! "contentsentlength", "contentchannel", "copy", "driver", "encoding", "files", "fileoffset", "filelength", "fileheaders", "flags", "form", --- 1036,1041 ---- static CONST char *opts[] = { ! "authpassword", "authuser", "channel", "close", ! "contentavail", "content", "contentlength", "contentsentlength", "contentchannel", "copy", "driver", "encoding", "files", "fileoffset", "filelength", "fileheaders", "flags", "form", *************** *** 1015,1022 **** "query", "request", "server", "sock", "start", "status", "url", "urlc", "urlencoding", "urlv", "version", ! "write_encoded", NULL }; enum { ! CAuthPasswordIdx, CAuthUserIdx, CChannelIdx, CCloseIdx, CContentIdx, CContentLengthIdx, CContentSentLenIdx, CContentChannelIdx, CCopyIdx, CDriverIdx, CEncodingIdx, CFilesIdx, CFileOffIdx, CFileLenIdx, --- 1044,1051 ---- "query", "request", "server", "sock", "start", "status", "url", "urlc", "urlencoding", "urlv", "version", ! "write_encoded", "interp", NULL }; enum { ! CAuthPasswordIdx, CAuthUserIdx, CChannelIdx, CCloseIdx, CAvailIdx, CContentIdx, CContentLengthIdx, CContentSentLenIdx, CContentChannelIdx, CCopyIdx, CDriverIdx, CEncodingIdx, CFilesIdx, CFileOffIdx, CFileLenIdx, *************** *** 1026,1030 **** CProtocolIdx, CQueryIdx, CRequestIdx, CServerIdx, CSockIdx, CStartIdx, CStatusIdx, CUrlIdx, CUrlcIdx, CUrlEncodingIdx, ! CUrlvIdx, CVersionIdx, CWriteEncodedIdx } opt; --- 1055,1059 ---- CProtocolIdx, CQueryIdx, CRequestIdx, CServerIdx, CSockIdx, CStartIdx, CStatusIdx, CUrlIdx, CUrlcIdx, CUrlEncodingIdx, ! CUrlvIdx, CVersionIdx, CWriteEncodedIdx, CInterpIdx } opt; *************** *** 1078,1081 **** --- 1107,1114 ---- break; + case CAvailIdx: + Tcl_SetIntObj(result, connPtr->avail); + break; + case CContentChannelIdx: fd = Ns_ConnContentFd(conn); *************** *** 1357,1360 **** --- 1390,1397 ---- } break; + + case CInterpIdx: + Tcl_SetLongObj(result, (long) interp); + break; } Index: connio.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/connio.c,v retrieving revision 1.27 retrieving revision 1.28 diff -C2 -d -r1.27 -r1.28 *** connio.c 19 Apr 2006 17:48:43 -0000 1.27 --- connio.c 8 Dec 2009 04:12:19 -0000 1.28 *************** *** 375,378 **** --- 375,382 ---- nwrote = n; } + if (nwrote >= 0 + && NsRunFilters((Ns_Conn *) connPtr, NS_FILTER_WRITE) != NS_OK) { + nwrote = -1; + } return nwrote; } Index: driver.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/driver.c,v retrieving revision 1.58 retrieving revision 1.59 diff -C2 -d -r1.58 -r1.59 *** driver.c 29 Jan 2009 20:54:24 -0000 1.58 --- driver.c 8 Dec 2009 04:12:19 -0000 1.59 *************** *** 44,47 **** --- 44,48 ---- enum { + SOCK_ACCEPT, /* Socket has just been accepted. */ SOCK_READWAIT, /* Waiting for request or content from client. */ SOCK_PREQUE, /* Ready to invoke pre-queue filters. */ *************** *** 49,53 **** --- 50,56 ---- SOCK_RUNWAIT, /* Ready to run when allowed by connection limits. */ SOCK_RUNNING, /* Running in a connection queue. */ + SOCK_CLOSEREQ, /* Close request in a read or pre-queue filter. */ SOCK_CLOSEWAIT, /* Graceful close wait draining remaining bytes .*/ + SOCK_CLOSED, /* Socket has been closed. */ SOCK_DROPPED, /* Client dropped connection. */ SOCK_TIMEOUT, /* Request timeout waiting to be queued. */ *************** *** 57,60 **** --- 60,64 ---- char *states[] = { + "accept", "readwait", "preque", *************** *** 62,66 **** --- 66,72 ---- "runwait", "running", + "closereq", "closewait", + "closed", "dropped", "timeout", *************** *** 89,92 **** --- 95,100 ---- E_RRANGE, E_CRANGE, + E_FILTER, + E_QUEWAIT, } ReadErr; *************** *** 155,164 **** static void FreeConn(Conn *connPtr); static int RunQueWaits(PollData *pdataPtr, Ns_Time *nowPtr, Sock *sockPtr); static void ThreadName(Driver *drvPtr, char *name); static void SockWait(Sock *sockPtr, Ns_Time *nowPtr, int timeout, Sock **listPtrPtr); static void AppendConn(Driver *drvPtr, Conn *connPtr); #define SockPush(s, sp) ((s)->nextPtr = *(sp), *(sp) = (s)) ! static void LogReadError(Sock *sockPtr, ReadErr err); /* --- 163,174 ---- static void FreeConn(Conn *connPtr); static int RunQueWaits(PollData *pdataPtr, Ns_Time *nowPtr, Sock *sockPtr); + static int RunFilters(Conn *connPtr, int why); static void ThreadName(Driver *drvPtr, char *name); + static void SockState(Sock *sockPtr, int state); static void SockWait(Sock *sockPtr, Ns_Time *nowPtr, int timeout, Sock **listPtrPtr); static void AppendConn(Driver *drvPtr, Conn *connPtr); #define SockPush(s, sp) ((s)->nextPtr = *(sp), *(sp) = (s)) ! static void LogReadError(Conn *connPtr, ReadErr err); /* *************** *** 171,174 **** --- 181,185 ---- static Tcl_HashTable hosts; /* Host header to server table. */ static ServerMap *defMapPtr;/* Default server when not found in table. */ + static Ns_Tls drvtls; *************** *** 194,197 **** --- 205,209 ---- Ns_MutexSetName(&connlock, "ns:conns"); Tcl_InitHashTable(&hosts, TCL_STRING_KEYS); + Ns_TlsAlloc(&drvtls, NULL); } *************** *** 539,543 **** * * Results: ! * None. * * Side effects: --- 551,555 ---- * * Results: ! * NS_OK if registered, NS_ERROR otherwise. * * Side effects: *************** *** 550,554 **** */ ! void Ns_QueueWait(Ns_Conn *conn, SOCKET sock, Ns_QueueWaitProc *proc, void *arg, int when, Ns_Time *timePtr) --- 562,566 ---- */ ! int Ns_QueueWait(Ns_Conn *conn, SOCKET sock, Ns_QueueWaitProc *proc, void *arg, int when, Ns_Time *timePtr) *************** *** 556,560 **** --- 568,578 ---- Conn *connPtr = (Conn *) conn; QueWait *queWaitPtr; + Driver *drvPtr; + drvPtr = Ns_TlsGet(&drvtls); + if (connPtr->sockPtr == NULL || connPtr->sockPtr->drvPtr != Ns_TlsGet(&drvtls)) { + LogReadError(connPtr, E_QUEWAIT); + return NS_ERROR; + } queWaitPtr = ns_malloc(sizeof(QueWait)); queWaitPtr->proc = proc; *************** *** 571,574 **** --- 589,593 ---- connPtr->queWaitPtr = queWaitPtr; queWaitPtr->timeout = *timePtr; + return NS_OK; } *************** *** 830,833 **** --- 849,862 ---- /* + * Defer the close if not requested from a connection thread + * which could happen in a read or pre-queue callback. + */ + + if (sockPtr->state != SOCK_RUNNING) { + SockState(sockPtr, SOCK_CLOSEREQ); + return; + } + + /* * If keepalive is requested and enabled, set the read wait * state. Otherwise, set close wait which simply drains any *************** *** 837,843 **** if (keep && drvPtr->keepwait > 0 && (*drvPtr->proc)(DriverKeep, sock, NULL, 0) == 0) { ! sockPtr->state = SOCK_READWAIT; } else { ! sockPtr->state = SOCK_CLOSEWAIT; } Ns_MutexLock(&drvPtr->lock); --- 866,872 ---- if (keep && drvPtr->keepwait > 0 && (*drvPtr->proc)(DriverKeep, sock, NULL, 0) == 0) { ! SockState(sockPtr, SOCK_READWAIT); } else { ! SockState(sockPtr, SOCK_CLOSEWAIT); } Ns_MutexLock(&drvPtr->lock); *************** *** 921,924 **** --- 950,954 ---- Sock *queSockPtr = NULL; /* Sock's ready to queue. */ + Ns_TlsSet(&drvtls, drvPtr); ThreadName(drvPtr, "driver"); *************** *** 1046,1050 **** if ((sockPtr = connPtr->sockPtr) != NULL) { connPtr->sockPtr = NULL; ! sockPtr->state = SOCK_CLOSEWAIT; SockPush(sockPtr, &closePtr); } --- 1076,1080 ---- if ((sockPtr = connPtr->sockPtr) != NULL) { connPtr->sockPtr = NULL; ! SockState(sockPtr, SOCK_CLOSEWAIT); SockPush(sockPtr, &closePtr); } *************** *** 1185,1189 **** /* ! * Process sockets ready to run, starting with pre-queue callbacks. */ --- 1215,1219 ---- /* ! * Process sockets ready to run. */ *************** *** 1191,1217 **** preqSockPtr = sockPtr->nextPtr; sockPtr->connPtr->times.ready = now; ! if (sockPtr->state != SOCK_PREQUE || ! NsRunFilters((Ns_Conn *) sockPtr->connPtr, ! NS_FILTER_PRE_QUEUE) != NS_OK) { SockClose(sockPtr); } else if (sockPtr->connPtr->queWaitPtr != NULL) { ! /* NB: Sock timeout ignored during que wait. */ ! sockPtr->state = SOCK_QUEWAIT; ! SockPush(sockPtr, &waitPtr); } else { ! SockPush(sockPtr, &queSockPtr); } } /* ! * Add Sock's now ready to the queue. */ while ((sockPtr = queSockPtr) != NULL) { queSockPtr = sockPtr->nextPtr; ! connPtr = sockPtr->connPtr; ! sockPtr->timeout = connPtr->times.queue = now; ! Ns_IncrTime(&sockPtr->timeout, connPtr->limitsPtr->timeout, 0); ! AppendConn(drvPtr, connPtr); } --- 1221,1263 ---- preqSockPtr = sockPtr->nextPtr; sockPtr->connPtr->times.ready = now; ! /* ! * Invoke any pre-queue filters ! */ ! ! if (sockPtr->state == SOCK_PREQUE ! && !RunFilters(sockPtr->connPtr, NS_FILTER_PRE_QUEUE)) { ! if (sockPtr->state != SOCK_CLOSEREQ) { ! SockState(sockPtr, SOCK_ERROR); ! } ! } ! if (sockPtr->state != SOCK_PREQUE) { ! /* NB: Should be one of SOCK_ERROR or SOCK_CLOSEREQ. */ SockClose(sockPtr); } else if (sockPtr->connPtr->queWaitPtr != NULL) { ! /* NB: Sock timeout ignored during que wait. */ ! SockState(sockPtr, SOCK_QUEWAIT); ! SockPush(sockPtr, &waitPtr); } else { ! SockPush(sockPtr, &queSockPtr); } } /* ! * Add Sock's now ready to queue, freeing any connection ! * interp which may have been allocated for que-wait callbacks ! * and/or pre-queue filters. */ while ((sockPtr = queSockPtr) != NULL) { queSockPtr = sockPtr->nextPtr; ! connPtr = sockPtr->connPtr; ! NsFreeConnInterp(connPtr); ! if (sockPtr->state == SOCK_ERROR) { ! SockClose(sockPtr); ! } else { ! sockPtr->timeout = connPtr->times.queue = now; ! Ns_IncrTime(&sockPtr->timeout, connPtr->limitsPtr->timeout, 0); ! AppendConn(drvPtr, connPtr); ! } } *************** *** 1231,1235 **** if (PollIn(&pdata, sockPtr->pidx)) { ++drvPtr->stats.dropped; ! sockPtr->state = SOCK_DROPPED; goto dropped; } --- 1277,1281 ---- if (PollIn(&pdata, sockPtr->pidx)) { ++drvPtr->stats.dropped; ! SockState(sockPtr, SOCK_DROPPED); goto dropped; } *************** *** 1237,1252 **** if (limitsPtr->nrunning < limitsPtr->maxrun) { ++limitsPtr->nrunning; ! sockPtr->state = SOCK_RUNNING; } else if (Ns_DiffTime(&sockPtr->timeout, &now, NULL) <= 0) { ++limitsPtr->ntimeout; ++drvPtr->stats.timeout; ! sockPtr->state = SOCK_TIMEOUT; } else if (limitsPtr->nwaiting < limitsPtr->maxwait) { ++limitsPtr->nwaiting; ! sockPtr->state = SOCK_RUNWAIT; } else { ++limitsPtr->noverflow; ++drvPtr->stats.overflow; ! sockPtr->state = SOCK_OVERFLOW; } dropped: --- 1283,1298 ---- if (limitsPtr->nrunning < limitsPtr->maxrun) { ++limitsPtr->nrunning; ! SockState(sockPtr, SOCK_RUNNING); } else if (Ns_DiffTime(&sockPtr->timeout, &now, NULL) <= 0) { ++limitsPtr->ntimeout; ++drvPtr->stats.timeout; ! SockState(sockPtr, SOCK_TIMEOUT); } else if (limitsPtr->nwaiting < limitsPtr->maxwait) { ++limitsPtr->nwaiting; ! SockState(sockPtr, SOCK_RUNWAIT); } else { ++limitsPtr->noverflow; ++drvPtr->stats.overflow; ! SockState(sockPtr, SOCK_OVERFLOW); } dropped: *************** *** 1420,1423 **** --- 1466,1496 ---- *---------------------------------------------------------------------- * + * SockState -- + * + * Set the socket state. + * + * Results: + * None. + * + * Side effects: + * Updates sockPtr->state. + * + *---------------------------------------------------------------------- + */ + + static void + SockState(Sock *sockPtr, int state) + { + if (sockPtr->drvPtr->flags & DRIVER_DEBUG) { + Ns_Log(Notice, "%s[%d]: %s -> %s\n", sockPtr->drvPtr->name, + sockPtr->sock, states[sockPtr->state], states[state]); + } + sockPtr->state = state; + } + + + /* + *---------------------------------------------------------------------- + * * SockWait -- * *************** *** 1505,1509 **** sockPtr->id = drvPtr->nextid++; sockPtr->drvPtr = drvPtr; ! sockPtr->state = SOCK_READWAIT; sockPtr->arg = NULL; sockPtr->connPtr = NULL; --- 1578,1583 ---- sockPtr->id = drvPtr->nextid++; sockPtr->drvPtr = drvPtr; ! sockPtr->state = SOCK_ACCEPT; ! SockState(sockPtr, SOCK_READWAIT); sockPtr->arg = NULL; sockPtr->connPtr = NULL; *************** *** 1563,1566 **** --- 1637,1641 ---- if (sockPtr->connPtr != NULL) { + NsFreeConnInterp(sockPtr->connPtr); FreeConn(sockPtr->connPtr); sockPtr->connPtr = NULL; *************** *** 1569,1572 **** --- 1644,1648 ---- (void) (*drvPtr->proc)(DriverClose, (Ns_Sock *) sockPtr, NULL, 0); ns_sockclose(sockPtr->sock); + SockState(sockPtr, SOCK_CLOSED); sockPtr->sock = INVALID_SOCKET; drvPtr->stats.reads += sockPtr->nreads; *************** *** 1633,1637 **** ReadErr err; ! //errno = 0; ++sockPtr->nreads; if ((connPtr->flags & NS_CONN_READHDRS)) { --- 1709,1716 ---- ReadErr err; ! /* ! * Read any waiting request+headers and/or content. ! */ ! ++sockPtr->nreads; if ((connPtr->flags & NS_CONN_READHDRS)) { *************** *** 1642,1667 **** /* ! * Mark the connection ready if all input received, truncating any ! * extra \r\n and rewinding the input. */ ! if (!err ! && (connPtr->flags & NS_CONN_READHDRS) ! && connPtr->avail >= (size_t) connPtr->contentLength) { ! connPtr->avail = connPtr->contentLength; ! if (!(connPtr->flags & NS_CONN_FILECONTENT)) { ! connPtr->content[connPtr->avail] = '\0'; ! } else if (ftruncate(connPtr->tfd, connPtr->avail) != 0) { ! err = E_FDTRUNC; ! } else if (lseek(connPtr->tfd, (off_t) 0, SEEK_SET) != 0) { ! err = E_FDSEEK; ! } ! if (!err) { ! sockPtr->state = SOCK_PREQUE; } } if (err) { ! LogReadError(sockPtr, err); ! sockPtr->state = SOCK_ERROR; } } --- 1721,1754 ---- /* ! * If the request+headers have been received, check that all content ! * has been received (truncating any extra \r\n and rewinding ! * file-based content) and/or invoke read filter callbacks. */ ! if (!err && (connPtr->flags & NS_CONN_READHDRS)) { ! if (!RunFilters(connPtr, NS_FILTER_READ)) { ! err = E_FILTER; ! } else if (connPtr->avail >= (size_t) connPtr->contentLength) { ! connPtr->avail = connPtr->contentLength; ! if (!(connPtr->flags & NS_CONN_FILECONTENT)) { ! connPtr->content[connPtr->avail] = '\0'; ! } else { ! if (ftruncate(connPtr->tfd, connPtr->avail) != 0) { ! err = E_FDTRUNC; ! } else if (lseek(connPtr->tfd, (off_t) 0, SEEK_SET) != 0) { ! err = E_FDSEEK; ! } ! } ! if (!err) { ! SockState(sockPtr, SOCK_PREQUE); ! } } } + if (err) { ! if (sockPtr->state != SOCK_CLOSEREQ) { ! SockState(sockPtr, SOCK_ERROR); ! } ! LogReadError(connPtr, err); } } *************** *** 2132,2137 **** AllocConn(Driver *drvPtr, Ns_Time *nowPtr, Sock *sockPtr) { - Conn *connPtr; static unsigned int nextid = 0; int id; --- 2219,2224 ---- AllocConn(Driver *drvPtr, Ns_Time *nowPtr, Sock *sockPtr) { static unsigned int nextid = 0; + Conn *connPtr; int id; *************** *** 2156,2159 **** --- 2243,2247 ---- connPtr->tfd = -1; connPtr->headers = Ns_SetCreate(NULL); + connPtr->outputheaders = Ns_SetCreate(NULL); Tcl_InitHashTable(&connPtr->files, TCL_STRING_KEYS); connPtr->drvPtr = drvPtr; *************** *** 2165,2168 **** --- 2253,2257 ---- connPtr->times.accept = sockPtr->acceptTime; connPtr->sockPtr = sockPtr; + return connPtr; } *************** *** 2201,2204 **** --- 2290,2299 ---- */ + if (connPtr->type != NULL) { + Ns_ConnSetType(conn, NULL); + } + if (connPtr->query != NULL) { + Ns_ConnClearQuery(conn); + } if (conn->request != NULL) { Ns_FreeRequest(conn->request); *************** *** 2214,2217 **** --- 2309,2313 ---- } Ns_SetFree(connPtr->headers); + Ns_SetFree(connPtr->outputheaders); /* *************** *** 2221,2224 **** --- 2317,2321 ---- */ + Ns_DStringTrunc(&connPtr->obuf, 0); Ns_DStringTrunc(&connPtr->ibuf, 0); zlen = (size_t) ((char *) &connPtr->ibuf - (char *) connPtr); *************** *** 2235,2238 **** --- 2332,2361 ---- *---------------------------------------------------------------------- * + * RunPreQueues -- + * + * Execute any pre-queue callbacks, freeing any allocated interp. + * + * Results: + * 1 if ok, 0 otherwise. + * + * Side effects: + * Depends on callbacks, if any. + * + *---------------------------------------------------------------------- + */ + + static int + RunFilters(Conn *connPtr, int why) + { + int status; + + status = NsRunFilters((Ns_Conn *) connPtr, why); + return (status == NS_OK ? 1 : 0); + } + + + /* + *---------------------------------------------------------------------- + * * ReaderThread -- * *************** *** 2281,2287 **** /* ! * Return the connection to the driver thread. */ Ns_MutexLock(&drvPtr->lock); sockPtr->nextPtr = drvPtr->runSockPtr; --- 2404,2413 ---- /* ! * Return the connection to the driver thread, freeing ! * any connection interp which may have been allocated ! * by read filter callbacks. */ + NsFreeConnInterp(sockPtr->connPtr); Ns_MutexLock(&drvPtr->lock); sockPtr->nextPtr = drvPtr->runSockPtr; *************** *** 2341,2346 **** static void ! LogReadError(Sock *sockPtr, ReadErr err) { char *msg, *fmt; --- 2467,2473 ---- static void ! LogReadError(Conn *connPtr, ReadErr err) { + Sock *sockPtr = connPtr->sockPtr; char *msg, *fmt; *************** *** 2394,2397 **** --- 2521,2530 ---- msg = "max content exceeded"; break; + case E_FILTER: + msg = "filter error or abort result"; + break; + case E_QUEWAIT: + msg = "attempt to register quewait outside driver thread"; + break; default: msg = "unknown error"; *************** *** 2408,2411 **** break; } ! Ns_Log(Error, fmt, sockPtr->connPtr->id, msg, strerror(errno)); } --- 2541,2544 ---- break; } ! Ns_Log(Error, fmt, connPtr->id, msg, strerror(errno)); } Index: queue.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/queue.c,v retrieving revision 1.46 retrieving revision 1.47 diff -C2 -d -r1.46 -r1.47 *** queue.c 27 Dec 2008 00:36:38 -0000 1.46 --- queue.c 8 Dec 2009 04:12:19 -0000 1.47 *************** *** 38,41 **** --- 38,42 ---- #include "nsd.h" + #include <math.h> /* *************** *** 558,571 **** ConnRun(Conn *connPtr) { Ns_Conn *conn = (Ns_Conn *) connPtr; NsServer *servPtr = connPtr->servPtr; ! int i, status; ! Tcl_Encoding encoding = NULL; /* ! * Initialize the connection encodings and headers. */ - connPtr->outputheaders = Ns_SetCreate(NULL); encoding = NsGetInputEncoding(connPtr); if (encoding == NULL) { --- 559,571 ---- ConnRun(Conn *connPtr) { + Tcl_Encoding encoding = NULL; Ns_Conn *conn = (Ns_Conn *) connPtr; NsServer *servPtr = connPtr->servPtr; ! int i, status; /* ! * Initialize the connection encodings. */ encoding = NsGetInputEncoding(connPtr); if (encoding == NULL) { *************** *** 575,582 **** } } ! Ns_ConnSetUrlEncoding(conn, encoding); ! if (servPtr->opts.hdrcase != Preserve) { for (i = 0; i < Ns_SetSize(connPtr->headers); ++i) { ! if (servPtr->opts.hdrcase == ToLower) { Ns_StrToLower(Ns_SetKey(connPtr->headers, i)); } else { --- 575,582 ---- } } ! Ns_ConnSetUrlEncoding((Ns_Conn *) connPtr, encoding); ! if (connPtr->servPtr->opts.hdrcase != Preserve) { for (i = 0; i < Ns_SetSize(connPtr->headers); ++i) { ! if (connPtr->servPtr->opts.hdrcase == ToLower) { Ns_StrToLower(Ns_SetKey(connPtr->headers, i)); } else { *************** *** 645,659 **** NsRunCleanups(conn); NsFreeConnInterp(connPtr); - if (connPtr->type != NULL) { - Ns_ConnSetType(conn, NULL); - } - if (connPtr->query != NULL) { - Ns_ConnClearQuery(conn); - } - if (connPtr->outputheaders != NULL) { - Ns_SetFree(connPtr->outputheaders); - connPtr->outputheaders = NULL; - } - Ns_DStringTrunc(&connPtr->obuf, 0); } --- 645,648 ---- Index: tclcmds.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/tclcmds.c,v retrieving revision 1.56 retrieving revision 1.57 diff -C2 -d -r1.56 -r1.57 *** tclcmds.c 26 Jun 2006 00:28:02 -0000 1.56 --- tclcmds.c 8 Dec 2009 04:12:19 -0000 1.57 *************** *** 74,77 **** --- 74,78 ---- NsTclChanObjCmd, NsTclChmodObjCmd, + NsTclClsObjCmd, NsTclCondObjCmd, NsTclConnObjCmd, *************** *** 127,130 **** --- 128,132 ---- NsTclPoolsObjCmd, NsTclPurgeFilesObjCmd, + NsTclQueWaitObjCmd, NsTclRWLockObjCmd, NsTclRandObjCmd, *************** *** 171,174 **** --- 173,177 ---- NsTclThreadObjCmd, NsTclTimeObjCmd, + NsTclTlsObjCmd, NsTclTmpNamObjCmd, NsTclTruncateObjCmd, *************** *** 294,297 **** --- 297,301 ---- {"ns_checkurl", NULL, NsTclRequestAuthorizeObjCmd}, {"ns_chmod", NULL, NsTclChmodObjCmd}, + {"ns_cls", NULL, NsTclClsObjCmd}, {"ns_cond", NULL, NsTclCondObjCmd}, {"ns_config", NsTclConfigCmd, NULL}, *************** *** 350,353 **** --- 354,358 ---- {"ns_purgefiles", NULL, NsTclPurgeFilesObjCmd}, {"ns_puts", NULL, NsTclAdpPutsObjCmd}, + {"ns_quewait", NULL, NsTclQueWaitObjCmd}, {"ns_quotehtml", NsTclQuoteHtmlCmd, NULL}, {"ns_rand", NULL, NsTclRandObjCmd}, *************** *** 401,404 **** --- 406,410 ---- {"ns_thread", NULL, NsTclThreadObjCmd}, {"ns_time", NULL, NsTclTimeObjCmd}, + {"ns_tls", NULL, NsTclTlsObjCmd}, {"ns_tmpnam", NULL, NsTclTmpNamObjCmd}, {"ns_truncate", NULL, NsTclTruncateObjCmd}, Index: tclrequest.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/tclrequest.c,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** tclrequest.c 23 Aug 2005 22:05:04 -0000 1.13 --- tclrequest.c 8 Dec 2009 04:12:19 -0000 1.14 *************** *** 258,265 **** int when, i; static CONST char *wopt[] = { ! "prequeue", "preauth", "postauth", "trace", NULL }; enum { ! PQIdx, PRIdx, POIdx, TRIdx, } widx; --- 258,265 ---- int when, i; static CONST char *wopt[] = { ! "read", "write", "prequeue", "preauth", "postauth", "trace", NULL }; enum { ! ReadIdx, WriteIdx, PreQueueIdx, PreAuthIdx, PostAuthIdx, TraceIdx, } widx; *************** *** 282,295 **** } switch (widx) { ! case PQIdx: when |= NS_FILTER_PRE_QUEUE; break; ! case PRIdx: when |= NS_FILTER_PRE_AUTH; break; ! case POIdx: when |= NS_FILTER_POST_AUTH; break; ! case TRIdx: when |= NS_FILTER_TRACE; break; --- 282,301 ---- } switch (widx) { ! case ReadIdx: ! when |= NS_FILTER_READ; ! break; ! case WriteIdx: ! when |= NS_FILTER_WRITE; ! break; ! case PreQueueIdx: when |= NS_FILTER_PRE_QUEUE; break; ! case PreAuthIdx: when |= NS_FILTER_PRE_AUTH; break; ! case PostAuthIdx: when |= NS_FILTER_POST_AUTH; break; ! case TraceIdx: when |= NS_FILTER_TRACE; break; *************** *** 505,508 **** --- 511,523 ---- } switch (why) { + case NS_FILTER_READ: + Tcl_DStringAppendElement(&script, "read"); + break; + case NS_FILTER_WRITE: + Tcl_DStringAppendElement(&script, "write"); + break; + case NS_FILTER_PRE_QUEUE: + Tcl_DStringAppendElement(&script, "prequeue"); + break; case NS_FILTER_PRE_AUTH: Tcl_DStringAppendElement(&script, "preauth"); Index: tclsock.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/tclsock.c,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -d -r1.24 -r1.25 *** tclsock.c 2 Aug 2005 22:11:58 -0000 1.24 --- tclsock.c 8 Dec 2009 04:12:19 -0000 1.25 *************** *** 28,32 **** */ - /* * tclsock.c -- --- 28,31 ---- *************** *** 73,76 **** --- 72,76 ---- Tcl_Obj *CONST objv[]); static Ns_SockProc SockListenCallback; + static Ns_QueueWaitProc WaitCallback; void *************** *** 86,89 **** --- 86,164 ---- *---------------------------------------------------------------------- * + * NsTclQueWaitObjCmd -- + * + * Implement the ns_quewait command to register a Tcl script + * Ns_QueueWait callback. Unlike the general ns_sockcallback, + * the script will execute later in the same, connection-bound + * interp which calls ns_quewait. Thus the interface is + * closer to Tcl's standard "fileevent" command. + * + * Results: + * Tcl result. + * + * Side effects: + * Depends on callbacks. + * + *---------------------------------------------------------------------- + */ + + int + NsTclQueWaitObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) + { + TclSockCallback *cbPtr; + Ns_Conn *conn; + Tcl_Channel chan; + SOCKET sock; + int when; + Ns_Time timeout; + static CONST char *opt[] = { + "readable", "writable", NULL + }; + enum { + ReadIdx, WriteIdx + } idx; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 1, objv, "sockId event timeout script"); + return TCL_ERROR; + } + if (NsTclGetConn((NsInterp *) arg, &conn) != TCL_OK) { + return TCL_ERROR; + } + chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); + if (chan == NULL) { + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], opt, "event", 0, + (int *) &idx) != TCL_OK) { + return TCL_ERROR; + } + switch (idx) { + case ReadIdx: + when = NS_SOCK_READ; + break; + case WriteIdx: + when = NS_SOCK_WRITE; + break; + } + if (Ns_TclGetOpenFd(interp, Tcl_GetString(objv[1]), + (idx == WriteIdx) ? 1 :0, (int *) &sock) != TCL_OK) { + return TCL_ERROR; + } + if (Ns_TclGetTimeFromObj(interp, objv[3], &timeout) != TCL_OK) { + return TCL_ERROR; + } + if (Ns_QueueWait(conn, sock, WaitCallback, objv[4], when, &timeout) != NS_OK) { + Tcl_SetResult(interp, "could not register sock wait", TCL_STATIC); + return TCL_ERROR; + } + Tcl_IncrRefCount(objv[4]); + return TCL_OK; + } + + + /* + *---------------------------------------------------------------------- + * * NsTclGetHostObjCmd, NsTclGetAddrObjCmd -- * *************** *** 1135,1138 **** --- 1210,1268 ---- *---------------------------------------------------------------------- * + * WaitCallback -- + * + * This is the C wrapper Ns_QueueWait callback registered in + * ns_quewait. + * + * Results: + * None. + * + * Side effects: + * Will run Tcl script. + * + *---------------------------------------------------------------------- + */ + + static void + WaitCallback(Ns_Conn *conn, SOCKET sock, void *arg, int why) + { + Tcl_Interp *interp = Ns_GetConnInterp(conn); + Tcl_Obj *objPtr = arg; + Tcl_DString ds; + char *s; + int len; + + Tcl_DStringInit(&ds); + s = Tcl_GetStringFromObj(objPtr, &len); + Tcl_DStringAppend(&ds, s, len); + + /* + * NB: While the C interface allows for a single callback + * to be registered (NS_SOCK_READ | NS_SOCK_WRITE), the + * ns_quewait command enforces only readable or writable + * at a time. + */ + + if (why == 0) { + s = "timeout"; + } else if (why & NS_SOCK_READ) { + s = "readable"; + } else if (why & NS_SOCK_WRITE) { + s = "writable"; + } else if (why & NS_SOCK_DROP) { + s = "dropped"; + } + Tcl_DStringAppendElement(&ds, s); + if (Tcl_EvalEx(interp, ds.string, ds.length, 0) != TCL_OK) { + Ns_TclLogError(interp); + } + Tcl_DStringFree(&ds); + Tcl_DecrRefCount(objPtr); + } + + + /* + *---------------------------------------------------------------------- + * * SockListenCallback -- * |