#include "comm/forward.h"
#include "comm_err_t.h"
#include "MasterXaction.h"
+#include "SBuf.h"
/* CommCalls implement AsyncCall interface for comm_* callbacks.
* The classes cover two call dialer kinds:
public:
char *buf;
size_t size;
+ SBuf *buf2; // alternative buffer for use when buf is unset
};
// close parameters
typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
reader = JobCallback(33, 5, Dialer, this, ConnStateData::clientReadRequest);
- comm_read(clientConnection, in.buf.rawSpace(in.buf.spaceSize()), in.buf.spaceSize()-1, reader);
+ comm_read(clientConnection, in.buf, reader);
}
void
fd_note(clientConnection->fd, "Idle client: Waiting for next request");
/**
- * Set the timeout BEFORE calling clientReadRequest().
+ * Set the timeout BEFORE calling readSomeData().
*/
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
kb_incr(&(statCounter.client_http.kbytes_in), io.size);
// may comm_close or setReplyToError
- if (!handleReadData(io.buf, io.size))
+ if (!handleReadData(io.buf2))
return;
} else if (io.size == 0) {
* \retval true we did not call comm_close or setReplyToError
*/
bool
-ConnStateData::handleReadData(char *buf, size_t size)
+ConnStateData::handleReadData(SBuf *buf)
{
- // XXX: make this a no-op when buf given is the MemBlob free space.
- assert(buf == in.buf.rawSpace(1));
- assert(size <= in.buf.spaceSize());
- in.buf.append(buf, size);
+ assert(buf == &in.buf); // XXX: make this abort the transaction if this fails
// if we are reading a body, stuff data into the body pipe
if (bodyPipe != NULL)
// fake a CONNECT request to force connState to tunnel
static char ip[MAX_IPSTRLEN];
- static char reqStr[MAX_IPSTRLEN + 80];
connState->clientConnection->local.toUrl(ip, sizeof(ip));
- snprintf(reqStr, sizeof(reqStr), "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", ip, ip);
- bool ret = connState->handleReadData(reqStr, strlen(reqStr));
+ SBuf reqStr;
+ reqStr.append("CONNECT ").append(ip).append(" HTTP/1.1\r\nHost: ").append(ip).append("\r\n\r\n");
+ bool ret = connState->handleReadData(&reqStr);
if (ret)
ret = connState->clientParseRequests();
-
- if (!ret) {
+ else {
debugs(33, 2, HERE << "Failed to start fake CONNECT request for ssl bumped connection: " << connState->clientConnection);
connState->clientConnection->close();
}
virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer);
virtual void noteBodyConsumerAborted(BodyPipe::Pointer);
- bool handleReadData(char *buf, size_t size);
+ bool handleReadData(SBuf *buf);
bool handleRequestBodyData();
/**
++ statCounter.syscalls.sock.reads;
errno = 0;
int retval;
- retval = FD_READ_METHOD(fd, ccb->buf, ccb->size);
- debugs(5, 3, "comm_read_try: FD " << fd << ", size " << ccb->size << ", retval " << retval << ", errno " << errno);
+ if (ccb->buf) {
+ retval = FD_READ_METHOD(fd, ccb->buf, ccb->size);
+ debugs(5, 3, "char FD " << fd << ", size " << ccb->size << ", retval " << retval << ", errno " << errno);
+ } else {
+ assert(ccb->buf2 != NULL);
+ SBuf::size_type sz = ccb->buf2->spaceSize();
+ char *buf = ccb->buf2->rawSpace(sz);
+ retval = FD_READ_METHOD(fd, buf, sz-1); // blocking synchronous read(2)
+ if (retval > 0) {
+ ccb->buf2->append(buf, retval);
+ }
+ debugs(5, 3, "SBuf FD " << fd << ", size " << sz << ", retval " << retval << ", errno " << errno);
+ }
if (retval < 0 && !ignoreErrno(errno)) {
debugs(5, 3, "comm_read_try: scheduling COMM_ERROR");
Comm::SetSelect(conn->fd, COMM_SELECT_READ, commHandleRead, ccb, 0);
}
+/**
+ * Queue a read. handler/handler_data are called when the read
+ * completes, on error, or on file descriptor close.
+ */
+void
+comm_read(const Comm::ConnectionPointer &conn, SBuf &buf, AsyncCall::Pointer &callback)
+{
+ debugs(5, 5, "comm_read, queueing read for " << conn << "; asynCall " << callback);
+
+ /* Make sure we are open and not closing */
+ assert(Comm::IsConnOpen(conn));
+ assert(!fd_table[conn->fd].closing());
+ Comm::IoCallback *ccb = COMMIO_FD_READCB(conn->fd);
+
+ // Make sure we are either not reading or just passively monitoring.
+ // Active/passive conflicts are OK and simply cancel passive monitoring.
+ if (ccb->active()) {
+ // if the assertion below fails, we have an active comm_read conflict
+ assert(fd_table[conn->fd].halfClosedReader != NULL);
+ commStopHalfClosedMonitor(conn->fd);
+ assert(!ccb->active());
+ }
+ ccb->conn = conn;
+ ccb->buf2 = &buf;
+
+ /* Queue the read */
+ ccb->setCallback(Comm::IOCB_READ, callback, NULL, NULL, buf.spaceSize());
+ Comm::SetSelect(conn->fd, COMM_SELECT_READ, commHandleRead, ccb, 0);
+}
+
/**
* Empty the read buffers
*
int comm_has_pending_read_callback(int fd);
bool comm_monitors_read(int fd);
-//void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, IOCB *handler, void *data);
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback);
+void comm_read(const Comm::ConnectionPointer &conn, SBuf &buf, AsyncCall::Pointer &callback);
void comm_read_cancel(int fd, IOCB *callback, void *data);
void comm_read_cancel(int fd, AsyncCall::Pointer &callback);
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from);
Comm::IoCallback::reset()
{
conn = NULL;
+ buf2 = NULL; // we do not own this buffer.
if (freefunc) {
freefunc(buf);
buf = NULL;
assert(active());
/* free data */
- if (freefunc) {
+ if (freefunc && buf) {
freefunc(buf);
buf = NULL;
freefunc = NULL;
Params ¶ms = GetCommParams<Params>(callback);
if (conn != NULL) params.fd = conn->fd; // for legacy write handlers...
params.conn = conn;
+ params.buf2 = buf2;
params.buf = buf;
params.size = offset;
params.flag = code;
#include "base/AsyncCall.h"
#include "comm/forward.h"
#include "comm_err_t.h"
+#include "SBuf.h"
#include "typedefs.h"
namespace Comm
iocb_type type;
Comm::ConnectionPointer conn;
AsyncCall::Pointer callback;
+
+ /// Buffer to store read(2) into when set.
+ // This is a pointer to the Jobs buffer rather than an SBuf using
+ // the same store since we cannot know when or how the Job will
+ // alter its SBuf while we are reading.
+ SBuf *buf2;
+
+ // Legacy c-string buffers used when buf2 is unset.
char *buf;
FREE *freefunc;
int size;
void ConnStateData::expectNoForwarding() STUB
void ConnStateData::noteMoreBodySpaceAvailable(BodyPipe::Pointer) STUB
void ConnStateData::noteBodyConsumerAborted(BodyPipe::Pointer) STUB
-bool ConnStateData::handleReadData(char *buf, size_t size) STUB_RETVAL(false)
+bool ConnStateData::handleReadData(SBuf *buf) STUB_RETVAL(false)
bool ConnStateData::handleRequestBodyData() STUB_RETVAL(false)
void ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth) STUB
void ConnStateData::unpinConnection() STUB