]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm/Read.cc
2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 05 Socket Functions */
13 #include "comm/IoCallback.h"
14 #include "comm/Loops.h"
15 #include "comm/Read.h"
16 #include "comm_internal.h"
17 #include "CommCalls.h"
21 #include "sbuf/SBuf.h"
22 #include "SquidConfig.h"
23 #include "StatCounters.h"
25 // Does comm check this fd for read readiness?
26 // Note that when comm is not monitoring, there can be a pending callback
27 // call, which may resume comm monitoring once fired.
29 Comm::MonitorsRead(int fd
)
31 assert(isOpen(fd
) && COMMIO_FD_READCB(fd
) != NULL
);
32 // Being active is usually the same as monitoring because we always
33 // start monitoring the FD when we configure Comm::IoCallback for I/O
34 // and we usually configure Comm::IoCallback for I/O when we starting
35 // monitoring a FD for reading.
36 return COMMIO_FD_READCB(fd
)->active();
40 Comm::Read(const Comm::ConnectionPointer
&conn
, AsyncCall::Pointer
&callback
)
42 // TODO: move comm_read_base() internals into here
43 // when comm_read() char* API is no longer needed
44 comm_read_base(conn
, NULL
, 0, callback
);
49 * If a buffer is given the callback is scheduled when the read
50 * completes, on error, or on file descriptor close.
52 * If no buffer (NULL) is given the callback is scheduled when
53 * the socket FD is ready for a read(2)/recv(2).
56 comm_read_base(const Comm::ConnectionPointer
&conn
, char *buf
, int size
, AsyncCall::Pointer
&callback
)
58 debugs(5, 5, "comm_read, queueing read for " << conn
<< "; asynCall " << callback
);
60 /* Make sure we are open and not closing */
61 assert(Comm::IsConnOpen(conn
));
62 assert(!fd_table
[conn
->fd
].closing());
63 Comm::IoCallback
*ccb
= COMMIO_FD_READCB(conn
->fd
);
65 // Make sure we are either not reading or just passively monitoring.
66 // Active/passive conflicts are OK and simply cancel passive monitoring.
68 // if the assertion below fails, we have an active comm_read conflict
69 assert(fd_table
[conn
->fd
].halfClosedReader
!= NULL
);
70 commStopHalfClosedMonitor(conn
->fd
);
71 assert(!ccb
->active());
76 ccb
->setCallback(Comm::IOCB_READ
, callback
, (char *)buf
, NULL
, size
);
77 Comm::SetSelect(conn
->fd
, COMM_SELECT_READ
, Comm::HandleRead
, ccb
, 0);
81 Comm::ReadNow(CommIoCbParams
¶ms
, SBuf
&buf
)
84 ++ statCounter
.syscalls
.sock
.reads
;
85 SBuf::size_type sz
= buf
.spaceSize();
86 if (params
.size
> 0 && params
.size
< sz
)
88 char *inbuf
= buf
.rawAppendStart(sz
);
90 const int retval
= FD_READ_METHOD(params
.conn
->fd
, inbuf
, sz
);
91 params
.xerrno
= errno
;
93 debugs(5, 3, params
.conn
<< ", size " << sz
<< ", retval " << retval
<< ", errno " << params
.xerrno
);
95 if (retval
> 0) { // data read most common case
96 buf
.rawAppendFinish(inbuf
, retval
);
97 fd_bytes(params
.conn
->fd
, retval
, FD_READ
);
98 params
.flag
= Comm::OK
;
101 } else if (retval
== 0) { // remote closure (somewhat less) common
102 // Note - read 0 == socket EOF, which is a valid read.
103 params
.flag
= Comm::ENDFILE
;
105 } else if (retval
< 0) { // connection errors are worst-case
106 debugs(5, 3, params
.conn
<< " Comm::COMM_ERROR: " << xstrerr(params
.xerrno
));
107 if (ignoreErrno(params
.xerrno
))
108 params
.flag
= Comm::INPROGRESS
;
110 params
.flag
= Comm::COMM_ERROR
;
117 * Handle an FD which is ready for read(2).
119 * If there is no provided buffer to fill call the callback.
121 * Otherwise attempt a read into the provided buffer.
122 * If the read attempt succeeds or fails, call the callback.
123 * Else, wait for another IO notification.
126 Comm::HandleRead(int fd
, void *data
)
128 Comm::IoCallback
*ccb
= (Comm::IoCallback
*) data
;
130 assert(data
== COMMIO_FD_READCB(fd
));
131 assert(ccb
->active());
133 // Without a buffer, just call back.
134 // The callee may ReadMore() to get the data.
136 ccb
->finish(Comm::OK
, 0);
140 /* For legacy callers : Attempt a read */
141 // Keep in sync with Comm::ReadNow()!
142 ++ statCounter
.syscalls
.sock
.reads
;
143 int xerrno
= errno
= 0;
144 int retval
= FD_READ_METHOD(fd
, ccb
->buf
, ccb
->size
);
146 debugs(5, 3, "FD " << fd
<< ", size " << ccb
->size
<< ", retval " << retval
<< ", errno " << xerrno
);
148 /* See if we read anything */
149 /* Note - read 0 == socket EOF, which is a valid read */
151 fd_bytes(fd
, retval
, FD_READ
);
152 ccb
->offset
= retval
;
153 ccb
->finish(Comm::OK
, 0);
155 } else if (retval
< 0 && !ignoreErrno(xerrno
)) {
156 debugs(5, 3, "comm_read_try: scheduling Comm::COMM_ERROR");
158 ccb
->finish(Comm::COMM_ERROR
, xerrno
);
162 /* Nope, register for some more IO */
163 Comm::SetSelect(fd
, COMM_SELECT_READ
, Comm::HandleRead
, data
, 0);
167 * Cancel a pending read. Assert that we have the right parameters,
168 * and that there are no pending read events!
170 * XXX: We do not assert that there are no pending read events and
171 * with async calls it becomes even more difficult.
172 * The whole interface should be reworked to do callback->cancel()
173 * instead of searching for places where the callback may be stored and
174 * updating the state of those places.
176 * AHC Don't call the comm handlers?
179 comm_read_cancel(int fd
, IOCB
*callback
, void *data
)
182 debugs(5, 4, "fails: FD " << fd
<< " closed");
186 Comm::IoCallback
*cb
= COMMIO_FD_READCB(fd
);
187 // TODO: is "active" == "monitors FD"?
189 debugs(5, 4, "fails: FD " << fd
<< " inactive");
193 typedef CommCbFunPtrCallT
<CommIoCbPtrFun
> Call
;
194 Call
*call
= dynamic_cast<Call
*>(cb
->callback
.getRaw());
196 debugs(5, 4, "fails: FD " << fd
<< " lacks callback");
200 call
->cancel("old comm_read_cancel");
202 typedef CommIoCbParams Params
;
203 const Params
¶ms
= GetCommParams
<Params
>(cb
->callback
);
205 /* Ok, we can be reasonably sure we won't lose any data here! */
206 assert(call
->dialer
.handler
== callback
);
207 assert(params
.data
== data
);
209 /* Delete the callback */
210 cb
->cancel("old comm_read_cancel");
212 /* And the IO event */
213 Comm::SetSelect(fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
217 Comm::ReadCancel(int fd
, AsyncCall::Pointer
&callback
)
219 callback
->cancel("comm_read_cancel");
222 debugs(5, 4, "fails: FD " << fd
<< " closed");
226 Comm::IoCallback
*cb
= COMMIO_FD_READCB(fd
);
229 debugs(5, 4, "fails: FD " << fd
<< " inactive");
233 AsyncCall::Pointer call
= cb
->callback
;
235 /* Ok, we can be reasonably sure we won't lose any data here! */
236 assert(call
== callback
);
238 /* Delete the callback */
239 cb
->cancel("comm_read_cancel");
241 /* And the IO event */
242 Comm::SetSelect(fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
246 Comm::MortalReadTimeout(const time_t startTime
, const time_t lifetimeLimit
)
248 if (lifetimeLimit
> 0) {
249 const time_t timeUsed
= (squid_curtime
> startTime
) ? (squid_curtime
- startTime
) : 0;
250 const time_t timeLeft
= (lifetimeLimit
> timeUsed
) ? (lifetimeLimit
- timeUsed
) : 0;
251 return min(::Config
.Timeout
.read
, timeLeft
);
253 return ::Config
.Timeout
.read
;