]>
Commit | Line | Data |
---|---|---|
51ea0904 | 1 | /* |
bbc27441 | 2 | * Copyright (C) 1996-2014 The Squid Software Foundation and contributors |
51ea0904 | 3 | * |
bbc27441 AJ |
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. | |
51ea0904 CT |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 54 Interprocess Communication */ |
10 | ||
f7f3304a | 11 | #include "squid.h" |
51ea0904 CT |
12 | #include "base/AsyncJobCalls.h" |
13 | #include "base/TextException.h" | |
1b76e6c1 AJ |
14 | #include "errorpage.h" |
15 | #include "HttpReply.h" | |
16 | #include "HttpRequest.h" | |
51ea0904 CT |
17 | #include "ipc/Forwarder.h" |
18 | #include "ipc/Port.h" | |
19 | #include "ipc/TypedMsgHdr.h" | |
20 | ||
51ea0904 CT |
21 | CBDATA_NAMESPACED_CLASS_INIT(Ipc, Forwarder); |
22 | ||
23 | Ipc::Forwarder::RequestsMap Ipc::Forwarder::TheRequestsMap; | |
24 | unsigned int Ipc::Forwarder::LastRequestId = 0; | |
25 | ||
26 | Ipc::Forwarder::Forwarder(Request::Pointer aRequest, double aTimeout): | |
8fb5a96c CT |
27 | AsyncJob("Ipc::Forwarder"), |
28 | request(aRequest), timeout(aTimeout) | |
51ea0904 CT |
29 | { |
30 | debugs(54, 5, HERE); | |
31 | } | |
32 | ||
33 | Ipc::Forwarder::~Forwarder() | |
34 | { | |
35 | debugs(54, 5, HERE); | |
36 | Must(request->requestId == 0); | |
37 | cleanup(); | |
38 | } | |
39 | ||
40 | /// perform cleanup actions | |
41 | void | |
42 | Ipc::Forwarder::cleanup() | |
43 | { | |
44 | } | |
45 | ||
46 | void | |
47 | Ipc::Forwarder::start() | |
48 | { | |
49 | debugs(54, 3, HERE); | |
50 | ||
51 | typedef NullaryMemFunT<Forwarder> Dialer; | |
933a6aed | 52 | AsyncCall::Pointer callback = JobCallback(54, 5, Dialer, this, Forwarder::handleRemoteAck); |
51ea0904 CT |
53 | if (++LastRequestId == 0) // don't use zero value as request->requestId |
54 | ++LastRequestId; | |
55 | request->requestId = LastRequestId; | |
56 | TheRequestsMap[request->requestId] = callback; | |
57 | TypedMsgHdr message; | |
58 | ||
59 | try { | |
60 | request->pack(message); | |
61 | } catch (...) { | |
62 | // assume the pack() call failed because the message did not fit | |
63 | // TODO: add a more specific exception? | |
64 | handleError(); | |
65 | } | |
66 | ||
1ee292b7 | 67 | SendMessage(Ipc::Port::CoordinatorAddr(), message); |
51ea0904 CT |
68 | eventAdd("Ipc::Forwarder::requestTimedOut", &Forwarder::RequestTimedOut, |
69 | this, timeout, 0, false); | |
70 | } | |
71 | ||
72 | void | |
73 | Ipc::Forwarder::swanSong() | |
74 | { | |
75 | debugs(54, 5, HERE); | |
76 | removeTimeoutEvent(); | |
77 | if (request->requestId > 0) { | |
78 | DequeueRequest(request->requestId); | |
79 | request->requestId = 0; | |
80 | } | |
81 | cleanup(); | |
82 | } | |
83 | ||
84 | bool | |
85 | Ipc::Forwarder::doneAll() const | |
86 | { | |
87 | debugs(54, 5, HERE); | |
88 | return request->requestId == 0; | |
89 | } | |
90 | ||
91 | /// called when Coordinator starts processing the request | |
92 | void | |
93 | Ipc::Forwarder::handleRemoteAck() | |
94 | { | |
95 | debugs(54, 3, HERE); | |
96 | request->requestId = 0; | |
1a98557c AR |
97 | // Do not clear ENTRY_FWD_HDR_WAIT or do entry->complete() because |
98 | // it will trigger our client side processing. Let job cleanup close. | |
51ea0904 CT |
99 | } |
100 | ||
101 | /// Ipc::Forwarder::requestTimedOut wrapper | |
102 | void | |
103 | Ipc::Forwarder::RequestTimedOut(void* param) | |
104 | { | |
105 | debugs(54, 3, HERE); | |
106 | Must(param != NULL); | |
107 | Forwarder* fwdr = static_cast<Forwarder*>(param); | |
108 | // use async call to enable job call protection that time events lack | |
933a6aed | 109 | CallJobHere(54, 5, fwdr, Forwarder, requestTimedOut); |
51ea0904 CT |
110 | } |
111 | ||
112 | /// called when Coordinator fails to start processing the request [in time] | |
113 | void | |
114 | Ipc::Forwarder::requestTimedOut() | |
115 | { | |
116 | debugs(54, 3, HERE); | |
117 | handleTimeout(); | |
118 | } | |
119 | ||
120 | void | |
121 | Ipc::Forwarder::handleError() | |
122 | { | |
123 | mustStop("error"); | |
124 | } | |
125 | ||
126 | void | |
127 | Ipc::Forwarder::handleTimeout() | |
128 | { | |
129 | mustStop("timeout"); | |
130 | } | |
131 | ||
132 | /// terminate with an error | |
133 | void | |
134 | Ipc::Forwarder::handleException(const std::exception& e) | |
135 | { | |
933a6aed | 136 | debugs(54, 3, HERE << e.what()); |
51ea0904 CT |
137 | mustStop("exception"); |
138 | } | |
139 | ||
140 | void | |
141 | Ipc::Forwarder::callException(const std::exception& e) | |
142 | { | |
143 | try { | |
144 | handleException(e); | |
145 | } catch (const std::exception& ex) { | |
146 | debugs(54, DBG_CRITICAL, HERE << ex.what()); | |
147 | } | |
148 | AsyncJob::callException(e); | |
149 | } | |
150 | ||
151 | /// returns and forgets the right Forwarder callback for the request | |
152 | AsyncCall::Pointer | |
153 | Ipc::Forwarder::DequeueRequest(unsigned int requestId) | |
154 | { | |
155 | debugs(54, 3, HERE); | |
156 | Must(requestId != 0); | |
157 | AsyncCall::Pointer call; | |
158 | RequestsMap::iterator request = TheRequestsMap.find(requestId); | |
159 | if (request != TheRequestsMap.end()) { | |
160 | call = request->second; | |
161 | Must(call != NULL); | |
162 | TheRequestsMap.erase(request); | |
163 | } | |
164 | return call; | |
165 | } | |
166 | ||
167 | /// called when we are no longer waiting for Coordinator to respond | |
168 | void | |
169 | Ipc::Forwarder::removeTimeoutEvent() | |
170 | { | |
171 | if (eventFind(&Forwarder::RequestTimedOut, this)) | |
172 | eventDelete(&Forwarder::RequestTimedOut, this); | |
173 | } | |
174 | ||
175 | void | |
176 | Ipc::Forwarder::HandleRemoteAck(unsigned int requestId) | |
177 | { | |
178 | debugs(54, 3, HERE); | |
179 | Must(requestId != 0); | |
180 | ||
181 | AsyncCall::Pointer call = DequeueRequest(requestId); | |
182 | if (call != NULL) | |
183 | ScheduleCallHere(call); | |
184 | } |