1 /* 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors 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. 7 */ 8 9 /* DEBUG: section 84 Helper process maintenance */ 10 11 #ifndef SQUID_HELPER_H 12 #define SQUID_HELPER_H 13 14 #include "base/AsyncCall.h" 15 #include "base/InstanceId.h" 16 #include "cbdata.h" 17 #include "comm/forward.h" 18 #include "dlink.h" 19 #include "helper/ChildConfig.h" 20 #include "helper/forward.h" 21 #include "helper/Reply.h" 22 #include "helper/Request.h" 23 #include "ip/Address.h" 24 #include "sbuf/SBuf.h" 25 26 #include <list> 27 #include <map> 28 #include <queue> 29 30 class Packable; 31 class wordlist; 32 33 namespace Helper 34 { 35 /// Holds the required data to serve a helper request. 36 class Xaction { 37 MEMPROXY_CLASS(Helper::Xaction); 38 public: Xaction(HLPCB * c,void * d,const char * b)39 Xaction(HLPCB *c, void *d, const char *b): request(c, d, b) {} 40 Helper::Request request; 41 Helper::Reply reply; 42 }; 43 } 44 45 /** 46 * Managers a set of individual helper processes with a common queue of requests. 47 * 48 * With respect to load, a helper goes through these states (roughly): 49 * idle: no processes are working on requests (and no requests are queued); 50 * normal: some, but not all processes are working (and no requests are queued); 51 * busy: all processes are working (and some requests are possibly queued); 52 * overloaded: a busy helper with more than queue-size requests in the queue. 53 * 54 * A busy helper queues new requests and issues a WARNING every 10 minutes or so. 55 * An overloaded helper either drops new requests or keeps queuing them, depending on 56 * whether the caller can handle dropped requests (trySubmit vs helperSubmit APIs). 57 * If an overloaded helper has been overloaded for 3+ minutes, an attempt to use 58 * it results in on-persistent-overload action, which may kill worker. 59 */ 60 class helper 61 { 62 CBDATA_CLASS(helper); 63 64 public: helper(const char * name)65 inline helper(const char *name) : 66 cmdline(NULL), 67 id_name(name), 68 ipc_type(0), 69 droppedRequests(0), 70 overloadStart(0), 71 last_queue_warn(0), 72 last_restart(0), 73 timeout(0), 74 retryTimedOut(false), 75 retryBrokenHelper(false), 76 eom('\n') { 77 memset(&stats, 0, sizeof(stats)); 78 } 79 ~helper(); 80 81 /// \returns next request in the queue, or nil. 82 Helper::Xaction *nextRequest(); 83 84 /// If possible, submit request. Otherwise, either kill Squid or return false. 85 bool trySubmit(const char *buf, HLPCB * callback, void *data); 86 87 /// Submits a request to the helper or add it to the queue if none of 88 /// the servers is available. 89 void submitRequest(Helper::Xaction *r); 90 91 /// Dump some stats about the helper state to a Packable object 92 void packStatsInto(Packable *p, const char *label = NULL) const; 93 /// whether the helper will be in "overloaded" state after one more request 94 /// already overloaded helpers return true 95 bool willOverload() const; 96 97 public: 98 wordlist *cmdline; 99 dlink_list servers; 100 std::queue<Helper::Xaction *> queue; 101 const char *id_name; 102 Helper::ChildConfig childs; ///< Configuration settings for number running. 103 int ipc_type; 104 Ip::Address addr; 105 unsigned int droppedRequests; ///< requests not sent during helper overload 106 time_t overloadStart; ///< when the helper became overloaded (zero if it is not) 107 time_t last_queue_warn; 108 time_t last_restart; 109 time_t timeout; ///< Requests timeout 110 bool retryTimedOut; ///< Whether the timed-out requests must retried 111 bool retryBrokenHelper; ///< Whether the requests must retried on BH replies 112 SBuf onTimedOutResponse; ///< The response to use when helper response timedout 113 char eom; ///< The char which marks the end of (response) message, normally '\n' 114 115 struct _stats { 116 int requests; 117 int replies; 118 int timedout; 119 int queue_size; 120 int avg_svc_time; 121 } stats; 122 123 protected: 124 friend void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data); 125 bool queueFull() const; 126 bool overloaded() const; 127 void syncQueueStats(); 128 bool prepSubmit(); 129 void submit(const char *buf, HLPCB * callback, void *data); 130 }; 131 132 class statefulhelper : public helper 133 { 134 CBDATA_CLASS(statefulhelper); 135 136 public: statefulhelper(const char * name)137 inline statefulhelper(const char *name) : helper(name), datapool(NULL) {} ~statefulhelper()138 inline ~statefulhelper() {} 139 140 public: 141 MemAllocator *datapool; 142 143 private: 144 friend void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver); 145 void submit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver); 146 bool trySubmit(const char *buf, HLPCB * callback, void *data, helper_stateful_server *lastserver); 147 }; 148 149 /** 150 * Fields shared between stateless and stateful helper servers. 151 */ 152 class HelperServerBase 153 { 154 public: 155 /** Closes pipes to the helper safely. 156 * Handles the case where the read and write pipes are the same FD. 157 * 158 * \param name displayed for the helper being shutdown if logging an error 159 */ 160 void closePipesSafely(const char *name); 161 162 /** Closes the reading pipe. 163 * If the read and write sockets are the same the write pipe will 164 * also be closed. Otherwise its left open for later handling. 165 * 166 * \param name displayed for the helper being shutdown if logging an error 167 */ 168 void closeWritePipeSafely(const char *name); 169 170 public: 171 /// Helper program identifier; does not change when contents do, 172 /// including during assignment 173 const InstanceId<HelperServerBase> index; 174 int pid; 175 Ip::Address addr; 176 Comm::ConnectionPointer readPipe; 177 Comm::ConnectionPointer writePipe; 178 void *hIpc; 179 180 char *rbuf; 181 size_t rbuf_sz; 182 size_t roffset; 183 184 struct timeval dispatch_time; 185 struct timeval answer_time; 186 187 dlink_node link; 188 189 struct _helper_flags { 190 bool writing; 191 bool closing; 192 bool shutdown; 193 bool reserved; 194 } flags; 195 196 typedef std::list<Helper::Xaction *> Requests; 197 Requests requests; ///< requests in order of submission/expiration 198 199 struct { 200 uint64_t uses; //< requests sent to this helper 201 uint64_t replies; //< replies received from this helper 202 uint64_t pending; //< queued lookups waiting to be sent to this helper 203 uint64_t releases; //< times release() has been called on this helper (if stateful) 204 uint64_t timedout; //< requests which timed-out 205 } stats; 206 void initStats(); 207 }; 208 209 class MemBuf; 210 class CommTimeoutCbParams; 211 212 class helper_server : public HelperServerBase 213 { 214 CBDATA_CLASS(helper_server); 215 216 public: 217 uint64_t nextRequestId; 218 219 MemBuf *wqueue; 220 MemBuf *writebuf; 221 222 helper *parent; 223 224 /// The helper request Xaction object for the current reply . 225 /// A helper reply may be distributed to more than one of the retrieved 226 /// packets from helper. This member stores the Xaction object as long as 227 /// the end-of-message for current reply is not retrieved. 228 Helper::Xaction *replyXaction; 229 230 /// Whether to ignore current message, because it is timed-out or other reason 231 bool ignoreToEom; 232 233 // STL says storing std::list iterators is safe when changing the list 234 typedef std::map<uint64_t, Requests::iterator> RequestIndex; 235 RequestIndex requestsIndex; ///< maps request IDs to requests 236 237 /// Search in queue for the request with requestId, return the related 238 /// Xaction object and remove it from queue. 239 /// If concurrency is disabled then the requestId is ignored and the 240 /// Xaction of the next request in queue is retrieved. 241 Helper::Xaction *popRequest(int requestId); 242 243 /// Run over the active requests lists and forces a retry, or timedout reply 244 /// or the configured "on timeout response" for timedout requests. 245 void checkForTimedOutRequests(bool const retry); 246 247 /// Read timeout handler 248 static void requestTimeout(const CommTimeoutCbParams &io); 249 }; 250 251 class helper_stateful_server : public HelperServerBase 252 { 253 CBDATA_CLASS(helper_stateful_server); 254 255 public: 256 /* MemBuf wqueue; */ 257 /* MemBuf writebuf; */ 258 259 statefulhelper *parent; 260 261 void *data; /* State data used by the calling routines */ 262 }; 263 264 /* helper.c */ 265 void helperOpenServers(helper * hlp); 266 void helperStatefulOpenServers(statefulhelper * hlp); 267 void helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data); 268 void helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPCB * callback, void *data, helper_stateful_server * lastserver); 269 void helperShutdown(helper * hlp); 270 void helperStatefulShutdown(statefulhelper * hlp); 271 void helperStatefulReleaseServer(helper_stateful_server * srv); 272 void *helperStatefulServerGetData(helper_stateful_server * srv); 273 274 #endif /* SQUID_HELPER_H */ 275 276