/*
- * $Id: clientStream.cc,v 1.9 2004/11/07 23:29:50 hno Exp $
- *
* DEBUG: section 87 Client-side Stream routines.
* AUTHOR: Robert Collins
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with thisObject program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
-/*
+#include "squid.h"
+#include "client_side_request.h"
+#include "clientStream.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+
+/**
+ \defgroup ClientStreamInternal Client Streams Internals
+ \ingroup ClientStreamAPI
+ \par
* A client Stream is a uni directional pipe, with the usual non-blocking
* asynchronous approach present elsewhere in squid.
*
+ \par
* Each pipe node has a data push function, and a data request function.
* This limits flexability - the data flow is no longer assembled at each
- * step.
+ * step.
*
+ \par
* An alternative approach is to pass each node in the pipe the call-
- * back to use on each IO call. This allows the callbacks to be changed
- * very easily by a participating node, but requires more maintenance
- * in each node (store the call back to the msot recent IO request in
- * the nodes context.) Such an approach also prevents dynamically
+ * back to use on each IO call. This allows the callbacks to be changed
+ * very easily by a participating node, but requires more maintenance
+ * in each node (store the callback to the most recent IO request in
+ * the nodes context.) Such an approach also prevents dynamically
* changing the pipeline from outside without an additional interface
* method to extract the callback and context from the next node.
*
+ \par
* One important characteristic of the stream is that the readfunc
* on the terminating node, and the callback on the first node
* will be NULL, and never used.
- */
-
-#include "squid.h"
-#include "clientStream.h"
-#include "HttpReply.h"
-#include "HttpRequest.h"
-#include "client_side_request.h"
-
-CBDATA_TYPE(clientStreamNode);
-
-/*
- * TODO: rather than each node undeleting the next, have a clientStreamDelete
- * that walks the list
- */
-
-/*
- * clientStream quick notes:
*
+ \section QuickNotes Quick Notes
+ \par
* Each node including the HEAD of the clientStream has a cbdataReference
* held by the stream. Freeing the stream then removes that reference
- * and cbdataFrees every node.
- * Any node with other References, and all nodes downstream will only
+ * and cbdataFree()'s every node.
+ * Any node with other References, and all nodes downstream will only
* free when those references are released.
- * Stream nodes MAY hold references to the data member of the node.
+ * Stream nodes MAY hold references to the data member of the node.
*
- * Specifically - on creation no reference is made.
+ \par
+ * Specifically - on creation no reference is made.
* If you pass a data variable to a node, give it an initial reference.
* If the data member is non-null on FREE, cbdataFree WILL be called.
* This you must never call cbdataFree on your own context without
* explicitly setting the stream node data member to NULL and
* cbdataReferenceDone'ing it.
*
+ \par
* No data member may hold a reference to it's stream node.
* The stream guarantees that DETACH will be called before
* freeing the node, alowing data members to cleanup.
- *
+ *
+ \par
* If a node's data holds a reference to something that needs to
* free the stream a circular reference list will occur.
* This results no data being freed until that reference is removed.
* One way to accomplish thisObject is to explicitly remove the
* data from your own node before freeing the stream.
*
- * (i.e.
- * mycontext = thisObject->data;
- * thisObject->data = NULL;
- * clientStreamFree (thisObject->head);
- * mycontext = NULL;
- * return;
+ \code
+ mycontext = thisObject->data;
+ thisObject->data = NULL;
+ clientStreamFree (thisObject->head);
+ mycontext = NULL;
+ return;
+ \endcode
+ *
+ \todo rather than each node undeleting the next, have a clientStreamDelete that walks the list.
*/
+/// \ingroup ClientStreamInternal
+CBDATA_TYPE(clientStreamNode);
+
/* Local functions */
static FREE clientStreamFree;
+/// \ingroup ClientStreamInternal
clientStreamNode *
clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status,
ClientStreamData data)
return temp;
}
-/*
+/**
+ \ingroup ClientStreamInternal
* Initialise a client Stream.
* list is the stream
* func is the read function for the head
temp->readBuffer = tailBuffer;
}
-/*
+/**
+ \ingroup ClientStreamInternal
* Doesn't actually insert at head. Instead it inserts one *after*
* head. This is because HEAD is a special node, as is tail
* This function is not suitable for inserting the real HEAD.
assert(list->head);
clientStreamNode *temp = clientStreamNew(func, callback, detach, status, data);
temp->head = list;
- debug(87, 3)
- ("clientStreamInsertHead: Inserted node %p with data %p after head\n",
- temp, data.getRaw());
+ debugs(87, 3, "clientStreamInsertHead: Inserted node " << temp <<
+ " with data " << data.getRaw() << " after head");
if (list->head->next)
temp->readBuffer = ((clientStreamNode *)list->head->next->data)->readBuffer;
dlinkAddAfter(cbdataReference(temp), &temp->node, list->head, list);
}
-/*
- * Callback the next node the in chain with it's requested data
- */
+// API
void
-clientStreamCallback(clientStreamNode * thisObject, clientHttpRequest * http,
+clientStreamCallback(clientStreamNode * thisObject, ClientHttpRequest * http,
HttpReply * rep, StoreIOBuffer replyBuffer)
{
clientStreamNode *next;
assert(thisObject && http && thisObject->node.next);
next = thisObject->next();
- debug(87,
- 3) ("clientStreamCallback: Calling %p with cbdata %p from node %p\n",
- next->callback, next->data.getRaw(), thisObject);
+ debugs(87, 3, "clientStreamCallback: Calling " << next->callback << " with cbdata " <<
+ next->data.getRaw() << " from node " << thisObject);
next->callback(next, http, rep, replyBuffer);
}
-/*
+/**
+ \ingroup ClientStreamInternal
* Call the previous node in the chain to read some data
+ *
+ \param thisObject ??
+ \param http ??
+ \param readBuffer ??
*/
void
-clientStreamRead(clientStreamNode * thisObject, clientHttpRequest * http,
+clientStreamRead(clientStreamNode * thisObject, ClientHttpRequest * http,
StoreIOBuffer readBuffer)
{
/* place the parameters on the 'stack' */
assert(thisObject && http && thisObject->prev());
prev = thisObject->prev();
- debug(87, 3) ("clientStreamRead: Calling %p with cbdata %p from node %p\n",
- prev->readfunc, prev->data.getRaw(), thisObject);
+ debugs(87, 3, "clientStreamRead: Calling " << prev->readfunc <<
+ " with cbdata " << prev->data.getRaw() << " from node " << thisObject);
thisObject->readBuffer = readBuffer;
prev->readfunc(prev, http);
}
-/*
+/**
+ \ingroup ClientStreamInternal
* Detach from the stream - only allowed for terminal members
+ *
+ \param thisObject ??
+ \param http ??
*/
void
-clientStreamDetach(clientStreamNode * thisObject, clientHttpRequest * http)
+clientStreamDetach(clientStreamNode * thisObject, ClientHttpRequest * http)
{
clientStreamNode *temp = thisObject;
assert(thisObject->node.next == NULL);
- debug(87, 3) ("clientStreamDetach: Detaching node %p\n", thisObject);
+ debugs(87, 3, "clientStreamDetach: Detaching node " << thisObject);
/* And clean up thisObject node */
/* ESI TODO: push refcount class through to head */
clientStreamNode *prev = NULL;
*/
if (prev) {
- debug(87, 3) ("clientStreamDetach: Calling %p with cbdata %p\n",
- prev->detach, prev->data.getRaw());
+ debugs(87, 3, "clientStreamDetach: Calling " << prev->detach << " with cbdata " << prev->data.getRaw());
if (cbdataReferenceValid(prev))
prev->detach(prev, http);
}
}
-/*
+/**
+ \ingroup ClientStreamInternal
* Abort the stream - detach every node in the pipeline.
+ *
+ \param thisObject ??
+ \param http ??
*/
void
-clientStreamAbort(clientStreamNode * thisObject, clientHttpRequest * http)
+clientStreamAbort(clientStreamNode * thisObject, ClientHttpRequest * http)
{
dlink_list *list;
assert(thisObject != NULL);
assert(http != NULL);
list = thisObject->head;
- debug(87, 3) ("clientStreamAbort: Aborting stream with tail %p\n",
- list->tail);
+ debugs(87, 3, "clientStreamAbort: Aborting stream with tail " << list->tail);
if (list->tail) {
clientStreamDetach((clientStreamNode *)list->tail->data, http);
}
}
-/*
- * Call the upstream node to find it's status
+/**
+ \ingroup ClientStreamInternal
+ * Call the upstream node to find it's status
+ *
+ \param thisObject ??
+ \param http ??
*/
clientStream_status_t
-clientStreamStatus(clientStreamNode * thisObject, clientHttpRequest * http)
+clientStreamStatus(clientStreamNode * thisObject, ClientHttpRequest * http)
{
clientStreamNode *prev;
assert(thisObject && http && thisObject->node.prev);
}
/* Local function bodies */
+
void
clientStreamNode::removeFromStream()
{
head = NULL;
}
+/// \ingroup ClientStreamInternal
void
clientStreamFree(void *foo)
{
clientStreamNode *thisObject = (clientStreamNode *)foo;
- debug(87, 3) ("Freeing clientStreamNode %p\n", thisObject);
+ debugs(87, 3, "Freeing clientStreamNode " << thisObject);
thisObject->removeFromStream();
thisObject->data = NULL;