]>
Commit | Line | Data |
---|---|---|
7e66d5e2 | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 The Squid Software Foundation and contributors |
bbc27441 AJ |
3 | * |
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. | |
7e66d5e2 | 7 | */ |
bbc27441 AJ |
8 | |
9 | /* DEBUG: section 05 Socket Functions */ | |
10 | ||
7e66d5e2 AJ |
11 | #include "squid.h" |
12 | #include "comm.h" | |
7e66d5e2 AJ |
13 | #include "comm/IoCallback.h" |
14 | #include "comm/Loops.h" | |
15 | #include "comm/Read.h" | |
470b1598 A |
16 | #include "comm_internal.h" |
17 | #include "CommCalls.h" | |
7e66d5e2 AJ |
18 | #include "Debug.h" |
19 | #include "fd.h" | |
20 | #include "fde.h" | |
65e41a45 | 21 | #include "sbuf/SBuf.h" |
7e66d5e2 | 22 | #include "StatCounters.h" |
7e66d5e2 AJ |
23 | |
24 | // Does comm check this fd for read readiness? | |
25 | // Note that when comm is not monitoring, there can be a pending callback | |
26 | // call, which may resume comm monitoring once fired. | |
27 | bool | |
28 | Comm::MonitorsRead(int fd) | |
29 | { | |
670b31a6 | 30 | assert(isOpen(fd) && COMMIO_FD_READCB(fd) != NULL); |
7e66d5e2 AJ |
31 | // Being active is usually the same as monitoring because we always |
32 | // start monitoring the FD when we configure Comm::IoCallback for I/O | |
33 | // and we usually configure Comm::IoCallback for I/O when we starting | |
34 | // monitoring a FD for reading. | |
35 | return COMMIO_FD_READCB(fd)->active(); | |
36 | } | |
37 | ||
38 | void | |
39 | Comm::Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback) | |
40 | { | |
41 | // TODO: move comm_read_base() internals into here | |
42 | // when comm_read() char* API is no longer needed | |
43 | comm_read_base(conn, NULL, 0, callback); | |
44 | } | |
45 | ||
46 | /** | |
47 | * Queue a read. | |
48 | * If a buffer is given the callback is scheduled when the read | |
49 | * completes, on error, or on file descriptor close. | |
50 | * | |
51 | * If no buffer (NULL) is given the callback is scheduled when | |
52 | * the socket FD is ready for a read(2)/recv(2). | |
53 | */ | |
54 | void | |
55 | comm_read_base(const Comm::ConnectionPointer &conn, char *buf, int size, AsyncCall::Pointer &callback) | |
56 | { | |
57 | debugs(5, 5, "comm_read, queueing read for " << conn << "; asynCall " << callback); | |
58 | ||
59 | /* Make sure we are open and not closing */ | |
60 | assert(Comm::IsConnOpen(conn)); | |
61 | assert(!fd_table[conn->fd].closing()); | |
62 | Comm::IoCallback *ccb = COMMIO_FD_READCB(conn->fd); | |
63 | ||
64 | // Make sure we are either not reading or just passively monitoring. | |
65 | // Active/passive conflicts are OK and simply cancel passive monitoring. | |
66 | if (ccb->active()) { | |
67 | // if the assertion below fails, we have an active comm_read conflict | |
68 | assert(fd_table[conn->fd].halfClosedReader != NULL); | |
69 | commStopHalfClosedMonitor(conn->fd); | |
70 | assert(!ccb->active()); | |
71 | } | |
72 | ccb->conn = conn; | |
73 | ||
74 | /* Queue the read */ | |
75 | ccb->setCallback(Comm::IOCB_READ, callback, (char *)buf, NULL, size); | |
76 | Comm::SetSelect(conn->fd, COMM_SELECT_READ, Comm::HandleRead, ccb, 0); | |
77 | } | |
78 | ||
c8407295 | 79 | Comm::Flag |
7e66d5e2 AJ |
80 | Comm::ReadNow(CommIoCbParams ¶ms, SBuf &buf) |
81 | { | |
82 | /* Attempt a read */ | |
83 | ++ statCounter.syscalls.sock.reads; | |
983de17b AJ |
84 | SBuf::size_type sz = buf.spaceSize(); |
85 | if (params.size > 0 && params.size < sz) | |
86 | sz = params.size; | |
183b70d5 | 87 | char *inbuf = buf.rawSpace(sz); |
7e66d5e2 | 88 | errno = 0; |
183b70d5 | 89 | const int retval = FD_READ_METHOD(params.conn->fd, inbuf, sz); |
7e66d5e2 AJ |
90 | params.xerrno = errno; |
91 | ||
92 | debugs(5, 3, params.conn << ", size " << sz << ", retval " << retval << ", errno " << params.xerrno); | |
93 | ||
94 | if (retval > 0) { // data read most common case | |
183b70d5 | 95 | buf.append(inbuf, retval); |
7e66d5e2 | 96 | fd_bytes(params.conn->fd, retval, FD_READ); |
c8407295 | 97 | params.flag = Comm::OK; |
7e66d5e2 AJ |
98 | params.size = retval; |
99 | ||
100 | } else if (retval == 0) { // remote closure (somewhat less) common | |
101 | // Note - read 0 == socket EOF, which is a valid read. | |
c8407295 | 102 | params.flag = Comm::ENDFILE; |
7e66d5e2 AJ |
103 | |
104 | } else if (retval < 0) { // connection errors are worst-case | |
4ee57cbe | 105 | debugs(5, 3, params.conn << " Comm::COMM_ERROR: " << xstrerr(params.xerrno)); |
7e66d5e2 | 106 | if (ignoreErrno(params.xerrno)) |
c8407295 | 107 | params.flag = Comm::INPROGRESS; |
7e66d5e2 | 108 | else |
4ee57cbe | 109 | params.flag = Comm::COMM_ERROR; |
7e66d5e2 AJ |
110 | } |
111 | ||
112 | return params.flag; | |
113 | } | |
114 | ||
115 | /** | |
116 | * Handle an FD which is ready for read(2). | |
117 | * | |
118 | * If there is no provided buffer to fill call the callback. | |
119 | * | |
120 | * Otherwise attempt a read into the provided buffer. | |
121 | * If the read attempt succeeds or fails, call the callback. | |
122 | * Else, wait for another IO notification. | |
123 | */ | |
124 | void | |
125 | Comm::HandleRead(int fd, void *data) | |
126 | { | |
127 | Comm::IoCallback *ccb = (Comm::IoCallback *) data; | |
128 | ||
129 | assert(data == COMMIO_FD_READCB(fd)); | |
130 | assert(ccb->active()); | |
131 | ||
183b70d5 AJ |
132 | // Without a buffer, just call back. |
133 | // The callee may ReadMore() to get the data. | |
7e66d5e2 | 134 | if (!ccb->buf) { |
c8407295 | 135 | ccb->finish(Comm::OK, 0); |
7e66d5e2 AJ |
136 | return; |
137 | } | |
138 | ||
139 | /* For legacy callers : Attempt a read */ | |
140 | // Keep in sync with Comm::ReadNow()! | |
141 | ++ statCounter.syscalls.sock.reads; | |
5dc67d58 | 142 | int xerrno = errno = 0; |
7e66d5e2 | 143 | int retval = FD_READ_METHOD(fd, ccb->buf, ccb->size); |
5dc67d58 AD |
144 | xerrno = errno; |
145 | debugs(5, 3, "FD " << fd << ", size " << ccb->size << ", retval " << retval << ", errno " << xerrno); | |
7e66d5e2 AJ |
146 | |
147 | /* See if we read anything */ | |
148 | /* Note - read 0 == socket EOF, which is a valid read */ | |
149 | if (retval >= 0) { | |
150 | fd_bytes(fd, retval, FD_READ); | |
151 | ccb->offset = retval; | |
5dc67d58 | 152 | ccb->finish(Comm::OK, 0); |
7e66d5e2 | 153 | return; |
5dc67d58 | 154 | } else if (retval < 0 && !ignoreErrno(xerrno)) { |
4ee57cbe | 155 | debugs(5, 3, "comm_read_try: scheduling Comm::COMM_ERROR"); |
7e66d5e2 | 156 | ccb->offset = 0; |
5dc67d58 | 157 | ccb->finish(Comm::COMM_ERROR, xerrno); |
7e66d5e2 AJ |
158 | return; |
159 | }; | |
160 | ||
7e66d5e2 AJ |
161 | /* Nope, register for some more IO */ |
162 | Comm::SetSelect(fd, COMM_SELECT_READ, Comm::HandleRead, data, 0); | |
163 | } | |
164 | ||
165 | /** | |
166 | * Cancel a pending read. Assert that we have the right parameters, | |
167 | * and that there are no pending read events! | |
168 | * | |
169 | * XXX: We do not assert that there are no pending read events and | |
170 | * with async calls it becomes even more difficult. | |
171 | * The whole interface should be reworked to do callback->cancel() | |
172 | * instead of searching for places where the callback may be stored and | |
173 | * updating the state of those places. | |
174 | * | |
175 | * AHC Don't call the comm handlers? | |
176 | */ | |
177 | void | |
178 | comm_read_cancel(int fd, IOCB *callback, void *data) | |
179 | { | |
180 | if (!isOpen(fd)) { | |
181 | debugs(5, 4, "fails: FD " << fd << " closed"); | |
182 | return; | |
183 | } | |
184 | ||
185 | Comm::IoCallback *cb = COMMIO_FD_READCB(fd); | |
186 | // TODO: is "active" == "monitors FD"? | |
187 | if (!cb->active()) { | |
188 | debugs(5, 4, "fails: FD " << fd << " inactive"); | |
189 | return; | |
190 | } | |
191 | ||
192 | typedef CommCbFunPtrCallT<CommIoCbPtrFun> Call; | |
193 | Call *call = dynamic_cast<Call*>(cb->callback.getRaw()); | |
194 | if (!call) { | |
195 | debugs(5, 4, "fails: FD " << fd << " lacks callback"); | |
196 | return; | |
197 | } | |
198 | ||
199 | call->cancel("old comm_read_cancel"); | |
200 | ||
201 | typedef CommIoCbParams Params; | |
202 | const Params ¶ms = GetCommParams<Params>(cb->callback); | |
203 | ||
204 | /* Ok, we can be reasonably sure we won't lose any data here! */ | |
205 | assert(call->dialer.handler == callback); | |
206 | assert(params.data == data); | |
207 | ||
208 | /* Delete the callback */ | |
209 | cb->cancel("old comm_read_cancel"); | |
210 | ||
211 | /* And the IO event */ | |
212 | Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); | |
213 | } | |
214 | ||
215 | void | |
216 | Comm::ReadCancel(int fd, AsyncCall::Pointer &callback) | |
217 | { | |
218 | callback->cancel("comm_read_cancel"); | |
219 | ||
220 | if (!isOpen(fd)) { | |
221 | debugs(5, 4, "fails: FD " << fd << " closed"); | |
222 | return; | |
223 | } | |
224 | ||
225 | Comm::IoCallback *cb = COMMIO_FD_READCB(fd); | |
226 | ||
227 | if (!cb->active()) { | |
228 | debugs(5, 4, "fails: FD " << fd << " inactive"); | |
229 | return; | |
230 | } | |
231 | ||
232 | AsyncCall::Pointer call = cb->callback; | |
233 | ||
234 | /* Ok, we can be reasonably sure we won't lose any data here! */ | |
235 | assert(call == callback); | |
236 | ||
237 | /* Delete the callback */ | |
238 | cb->cancel("comm_read_cancel"); | |
239 | ||
240 | /* And the IO event */ | |
241 | Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); | |
242 | } | |
f53969cc | 243 |