]>
Commit | Line | Data |
---|---|---|
0d0bce6a | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 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. | |
0d0bce6a AR |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 54 Interprocess Communication */ |
10 | ||
f7f3304a | 11 | #include "squid.h" |
a67d2b2e | 12 | #include "base/TextException.h" |
602d9612 | 13 | #include "comm.h" |
e0d28505 | 14 | #include "comm/Connection.h" |
582c2af2 | 15 | #include "globals.h" |
0d0bce6a | 16 | #include "ipc/Kids.h" |
602d9612 A |
17 | #include "ipc/Messages.h" |
18 | #include "ipc/Port.h" | |
0d0bce6a | 19 | #include "ipc/SharedListen.h" |
602d9612 A |
20 | #include "ipc/StartListening.h" |
21 | #include "ipc/TypedMsgHdr.h" | |
5bed43d6 | 22 | #include "tools.h" |
0d0bce6a | 23 | |
0dff3140 | 24 | #include <list> |
3d41e53a FC |
25 | #include <map> |
26 | ||
0d0bce6a AR |
27 | /// holds information necessary to handle JoinListen response |
28 | class PendingOpenRequest | |
29 | { | |
30 | public: | |
31 | Ipc::OpenListenerParams params; ///< actual comm_open_sharedListen() parameters | |
32 | AsyncCall::Pointer callback; // who to notify | |
33 | }; | |
34 | ||
35 | /// maps ID assigned at request time to the response callback | |
36 | typedef std::map<int, PendingOpenRequest> SharedListenRequestMap; | |
37 | static SharedListenRequestMap TheSharedListenRequestMap; | |
38 | ||
0dff3140 AR |
39 | /// accumulates delayed requests until they are ready to be sent, in FIFO order |
40 | typedef std::list<PendingOpenRequest> DelayedSharedListenRequests; | |
41 | static DelayedSharedListenRequests TheDelayedRequests; | |
42 | ||
0d0bce6a AR |
43 | static int |
44 | AddToMap(const PendingOpenRequest &por) | |
45 | { | |
46 | // find unused ID using linear seach; there should not be many entries | |
47 | for (int id = 0; true; ++id) { | |
48 | if (TheSharedListenRequestMap.find(id) == TheSharedListenRequestMap.end()) { | |
49 | TheSharedListenRequestMap[id] = por; | |
50 | return id; | |
51 | } | |
52 | } | |
53 | assert(false); // not reached | |
54 | return -1; | |
55 | } | |
56 | ||
57 | Ipc::OpenListenerParams::OpenListenerParams() | |
58 | { | |
e297be13 | 59 | memset(this, 0, sizeof(*this)); |
0d0bce6a AR |
60 | } |
61 | ||
62 | bool | |
63 | Ipc::OpenListenerParams::operator <(const OpenListenerParams &p) const | |
64 | { | |
65 | if (sock_type != p.sock_type) | |
66 | return sock_type < p.sock_type; | |
67 | ||
68 | if (proto != p.proto) | |
69 | return proto < p.proto; | |
70 | ||
71 | // ignore flags and fdNote differences because they do not affect binding | |
72 | ||
73 | return addr.compareWhole(p.addr) < 0; | |
74 | } | |
75 | ||
0d0bce6a AR |
76 | Ipc::SharedListenRequest::SharedListenRequest(): requestorId(-1), mapId(-1) |
77 | { | |
78 | // caller will then set public data members | |
79 | } | |
80 | ||
81 | Ipc::SharedListenRequest::SharedListenRequest(const TypedMsgHdr &hdrMsg) | |
82 | { | |
8822ebee AR |
83 | hdrMsg.checkType(mtSharedListenRequest); |
84 | hdrMsg.getPod(*this); | |
0d0bce6a AR |
85 | } |
86 | ||
87 | void Ipc::SharedListenRequest::pack(TypedMsgHdr &hdrMsg) const | |
88 | { | |
8822ebee AR |
89 | hdrMsg.setType(mtSharedListenRequest); |
90 | hdrMsg.putPod(*this); | |
0d0bce6a AR |
91 | } |
92 | ||
b72fb55d | 93 | Ipc::SharedListenResponse::SharedListenResponse(int aFd, int anErrNo, int aMapId): |
f53969cc | 94 | fd(aFd), errNo(anErrNo), mapId(aMapId) |
0d0bce6a AR |
95 | { |
96 | } | |
97 | ||
98 | Ipc::SharedListenResponse::SharedListenResponse(const TypedMsgHdr &hdrMsg): | |
f53969cc | 99 | fd(-1), errNo(0), mapId(-1) |
0d0bce6a | 100 | { |
8822ebee AR |
101 | hdrMsg.checkType(mtSharedListenResponse); |
102 | hdrMsg.getPod(*this); | |
b72fb55d | 103 | fd = hdrMsg.getFd(); |
e0d28505 | 104 | // other conn details are passed in OpenListenerParams and filled out by SharedListenJoin() |
0d0bce6a AR |
105 | } |
106 | ||
107 | void Ipc::SharedListenResponse::pack(TypedMsgHdr &hdrMsg) const | |
108 | { | |
8822ebee AR |
109 | hdrMsg.setType(mtSharedListenResponse); |
110 | hdrMsg.putPod(*this); | |
b72fb55d | 111 | hdrMsg.putFd(fd); |
0d0bce6a AR |
112 | } |
113 | ||
0dff3140 AR |
114 | static void |
115 | SendSharedListenRequest(const PendingOpenRequest &por) | |
0d0bce6a | 116 | { |
0dff3140 | 117 | Ipc::SharedListenRequest request; |
0d0bce6a AR |
118 | request.requestorId = KidIdentifier; |
119 | request.params = por.params; | |
120 | request.mapId = AddToMap(por); | |
121 | ||
0dff3140 | 122 | debugs(54, 3, "getting listening FD for " << request.params.addr << |
5667a628 | 123 | " mapId=" << request.mapId); |
0d0bce6a | 124 | |
0dff3140 | 125 | Ipc::TypedMsgHdr message; |
0d0bce6a | 126 | request.pack(message); |
1ee292b7 | 127 | SendMessage(Ipc::Port::CoordinatorAddr(), message); |
0d0bce6a AR |
128 | } |
129 | ||
0dff3140 AR |
130 | static void |
131 | kickDelayedRequest() | |
132 | { | |
133 | if (TheDelayedRequests.empty()) | |
134 | return; // no pending requests to resume | |
135 | ||
136 | debugs(54, 3, "resuming with " << TheSharedListenRequestMap.size() << | |
137 | " active + " << TheDelayedRequests.size() << " delayed requests"); | |
138 | ||
139 | SendSharedListenRequest(*TheDelayedRequests.begin()); | |
140 | TheDelayedRequests.pop_front(); | |
141 | } | |
142 | ||
143 | void | |
144 | Ipc::JoinSharedListen(const OpenListenerParams ¶ms, AsyncCall::Pointer &cb) | |
145 | { | |
146 | PendingOpenRequest por; | |
147 | por.params = params; | |
148 | por.callback = cb; | |
149 | ||
150 | const DelayedSharedListenRequests::size_type concurrencyLimit = 1; | |
151 | if (TheSharedListenRequestMap.size() >= concurrencyLimit) { | |
152 | debugs(54, 3, "waiting for " << TheSharedListenRequestMap.size() << | |
24296cbd | 153 | " active + " << TheDelayedRequests.size() << " delayed requests"); |
0dff3140 AR |
154 | TheDelayedRequests.push_back(por); |
155 | } else { | |
156 | SendSharedListenRequest(por); | |
157 | } | |
158 | } | |
159 | ||
0d0bce6a AR |
160 | void Ipc::SharedListenJoined(const SharedListenResponse &response) |
161 | { | |
e0d28505 | 162 | // Dont debugs c fully since only FD is filled right now. |
0dff3140 AR |
163 | debugs(54, 3, "got listening FD " << response.fd << " errNo=" << |
164 | response.errNo << " mapId=" << response.mapId << " with " << | |
165 | TheSharedListenRequestMap.size() << " active + " << | |
166 | TheDelayedRequests.size() << " delayed requests"); | |
0d0bce6a AR |
167 | |
168 | Must(TheSharedListenRequestMap.find(response.mapId) != TheSharedListenRequestMap.end()); | |
169 | PendingOpenRequest por = TheSharedListenRequestMap[response.mapId]; | |
170 | Must(por.callback != NULL); | |
171 | TheSharedListenRequestMap.erase(response.mapId); | |
172 | ||
b72fb55d CT |
173 | StartListeningCb *cbd = dynamic_cast<StartListeningCb*>(por.callback->getDialer()); |
174 | assert(cbd && cbd->conn != NULL); | |
175 | Must(cbd && cbd->conn != NULL); | |
176 | cbd->conn->fd = response.fd; | |
177 | ||
178 | if (Comm::IsConnOpen(cbd->conn)) { | |
0d0bce6a | 179 | OpenListenerParams &p = por.params; |
b72fb55d CT |
180 | cbd->conn->local = p.addr; |
181 | cbd->conn->flags = p.flags; | |
e0d28505 | 182 | // XXX: leave the comm AI stuff to comm_import_opened()? |
0d0bce6a | 183 | struct addrinfo *AI = NULL; |
4dd643d5 | 184 | p.addr.getAddrInfo(AI); |
0d0bce6a AR |
185 | AI->ai_socktype = p.sock_type; |
186 | AI->ai_protocol = p.proto; | |
b72fb55d | 187 | comm_import_opened(cbd->conn, FdNote(p.fdNote), AI); |
851614a8 | 188 | Ip::Address::FreeAddr(AI); |
0d0bce6a AR |
189 | } |
190 | ||
0d0bce6a | 191 | cbd->errNo = response.errNo; |
e0d28505 | 192 | cbd->handlerSubscription = por.params.handlerSubscription; |
0d0bce6a | 193 | ScheduleCallHere(por.callback); |
0dff3140 AR |
194 | |
195 | kickDelayedRequest(); | |
0d0bce6a | 196 | } |
f53969cc | 197 |