]> git.ipfire.org Git - thirdparty/squid.git/blob - src/fd.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / fd.cc
1 /*
2 * Copyright (C) 1996-2023 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 51 Filedescriptor Functions */
10
11 #include "squid.h"
12 #include "comm/Loops.h"
13 #include "debug/Messages.h"
14 #include "debug/Stream.h"
15 #include "fatal.h"
16 #include "fd.h"
17 #include "fde.h"
18 #include "globals.h"
19
20 // Solaris and possibly others lack MSG_NOSIGNAL optimization
21 // TODO: move this into compat/? Use a dedicated compat file to avoid dragging
22 // sys/socket.h into the rest of Squid??
23 #ifndef MSG_NOSIGNAL
24 #define MSG_NOSIGNAL 0
25 #endif
26
27 int default_read_method(int, char *, int);
28 int default_write_method(int, const char *, int);
29 #if _SQUID_WINDOWS_
30 int socket_read_method(int, char *, int);
31 int socket_write_method(int, const char *, int);
32 int file_read_method(int, char *, int);
33 int file_write_method(int, const char *, int);
34 #else
35 int msghdr_read_method(int, char *, int);
36 int msghdr_write_method(int, const char *, int);
37 #endif
38
39 const char *fdTypeStr[] = {
40 "None",
41 "Log",
42 "File",
43 "Socket",
44 "Pipe",
45 "MsgHdr",
46 "Unknown"
47 };
48
49 static void fdUpdateBiggest(int fd, int);
50
51 static void
52 fdUpdateBiggest(int fd, int opening)
53 {
54 if (fd < Biggest_FD)
55 return;
56
57 assert(fd < Squid_MaxFD);
58
59 if (fd > Biggest_FD) {
60 /*
61 * assert that we are not closing a FD bigger than
62 * our known biggest FD
63 */
64 assert(opening);
65 Biggest_FD = fd;
66 return;
67 }
68
69 /* if we are here, then fd == Biggest_FD */
70 /*
71 * assert that we are closing the biggest FD; we can't be
72 * re-opening it
73 */
74 assert(!opening);
75
76 while (Biggest_FD >= 0 && !fd_table[Biggest_FD].flags.open)
77 --Biggest_FD;
78 }
79
80 void
81 fd_close(int fd)
82 {
83 fde *F = &fd_table[fd];
84
85 assert(fd >= 0);
86 assert(F->flags.open);
87
88 if (F->type == FD_FILE) {
89 assert(F->read_handler == nullptr);
90 assert(F->write_handler == nullptr);
91 }
92
93 debugs(51, 3, "fd_close FD " << fd << " " << F->desc);
94 Comm::ResetSelect(fd);
95 F->flags.open = false;
96 fdUpdateBiggest(fd, 0);
97 --Number_FD;
98 F->clear();
99 }
100
101 #if _SQUID_WINDOWS_
102
103 int
104 socket_read_method(int fd, char *buf, int len)
105 {
106 return recv(fd, (void *) buf, len, 0);
107 }
108
109 int
110 file_read_method(int fd, char *buf, int len)
111 {
112 return _read(fd, buf, len);
113 }
114
115 int
116 socket_write_method(int fd, const char *buf, int len)
117 {
118 return send(fd, (const void *) buf, len, 0);
119 }
120
121 int
122 file_write_method(int fd, const char *buf, int len)
123 {
124 return _write(fd, buf, len);
125 }
126
127 #else
128 int
129 default_read_method(int fd, char *buf, int len)
130 {
131 return read(fd, buf, len);
132 }
133
134 int
135 default_write_method(int fd, const char *buf, int len)
136 {
137 return write(fd, buf, len);
138 }
139
140 int
141 msghdr_read_method(int fd, char *buf, int)
142 {
143 return recvmsg(fd, reinterpret_cast<msghdr*>(buf), MSG_DONTWAIT);
144 }
145
146 int
147 msghdr_write_method(int fd, const char *buf, int len)
148 {
149 const int i = sendmsg(fd, reinterpret_cast<const msghdr*>(buf), MSG_NOSIGNAL);
150 return i > 0 ? len : i; // len is imprecise but the caller expects a match
151 }
152
153 #endif
154
155 void
156 fd_open(int fd, unsigned int type, const char *desc)
157 {
158 fde *F;
159 assert(fd >= 0);
160 F = &fd_table[fd];
161
162 if (F->flags.open) {
163 debugs(51, DBG_IMPORTANT, "WARNING: Closing open FD " << std::setw(4) << fd);
164 fd_close(fd);
165 }
166
167 assert(!F->flags.open);
168 debugs(51, 3, "fd_open() FD " << fd << " " << desc);
169 F->type = type;
170 F->flags.open = true;
171 F->epoll_state = 0;
172 #if _SQUID_WINDOWS_
173
174 F->win32.handle = _get_osfhandle(fd);
175
176 switch (type) {
177
178 case FD_SOCKET:
179
180 case FD_PIPE:
181 F->setIo(&socket_read_method, &socket_write_method);
182 break;
183
184 case FD_FILE:
185
186 case FD_LOG:
187 F->setIo(&file_read_method, &file_write_method);
188 break;
189
190 default:
191 fatalf("fd_open(): unknown FD type - FD#: %i, type: %u, desc %s\n", fd, type, desc);
192 }
193
194 #else
195 switch (type) {
196
197 case FD_MSGHDR:
198 F->setIo(&msghdr_read_method, &msghdr_write_method);
199 break;
200
201 default:
202 F->setIo(&default_read_method, &default_write_method);
203 break;
204 }
205
206 #endif
207
208 fdUpdateBiggest(fd, 1);
209
210 fd_note(fd, desc);
211
212 ++Number_FD;
213 }
214
215 void
216 fd_note(int fd, const char *s)
217 {
218 fde *F = &fd_table[fd];
219 if (s)
220 xstrncpy(F->desc, s, FD_DESC_SZ);
221 else
222 *(F->desc) = 0; // ""-string
223 }
224
225 void
226 fd_bytes(int fd, int len, unsigned int type)
227 {
228 fde *F = &fd_table[fd];
229
230 if (len < 0)
231 return;
232
233 assert(type == FD_READ || type == FD_WRITE);
234
235 if (type == FD_READ)
236 F->bytes_read += len;
237 else
238 F->bytes_written += len;
239 }
240
241 void
242 fdDumpOpen(void)
243 {
244 int i;
245 fde *F;
246
247 for (i = 0; i < Squid_MaxFD; ++i) {
248 F = &fd_table[i];
249
250 if (!F->flags.open)
251 continue;
252
253 if (i == fileno(debug_log))
254 continue;
255
256 debugs(51, Important(17), "Open FD "<< std::left<< std::setw(10) <<
257 (F->bytes_read && F->bytes_written ? "READ/WRITE" :
258 F->bytes_read ? "READING" : F->bytes_written ? "WRITING" :
259 "UNSTARTED") <<
260 " "<< std::right << std::setw(4) << i << " " << F->desc);
261 }
262 }
263
264 int
265 fdNFree(void)
266 {
267 return Squid_MaxFD - Number_FD - Opening_FD;
268 }
269
270 int
271 fdUsageHigh(void)
272 {
273 int nrfree = fdNFree();
274
275 if (nrfree < (RESERVED_FD << 1))
276 return 1;
277
278 if (nrfree < (Number_FD >> 2))
279 return 1;
280
281 return 0;
282 }
283
284 /* Called when we runs out of file descriptors */
285 void
286 fdAdjustReserved(void)
287 {
288 int newReserve;
289 int x;
290 static time_t last = 0;
291 /*
292 * don't update too frequently
293 */
294
295 if (last + 5 > squid_curtime)
296 return;
297
298 /*
299 * Calculate a new reserve, based on current usage and a small extra
300 */
301 newReserve = Squid_MaxFD - Number_FD + min(25, Squid_MaxFD / 16);
302
303 if (newReserve <= RESERVED_FD)
304 return;
305
306 x = Squid_MaxFD - 20 - min(25, Squid_MaxFD / 16);
307
308 if (newReserve > x) {
309 /* perhaps this should be fatal()? -DW */
310 debugs(51, DBG_CRITICAL, "WARNING: This machine has a serious shortage of filedescriptors.");
311 newReserve = x;
312 }
313
314 if (Squid_MaxFD - newReserve < min(256, Squid_MaxFD / 2))
315 fatalf("Too few filedescriptors available in the system (%d usable of %d).\n", Squid_MaxFD - newReserve, Squid_MaxFD);
316
317 debugs(51, DBG_CRITICAL, "Reserved FD adjusted from " << RESERVED_FD << " to " << newReserve <<
318 " due to failures (" << (Squid_MaxFD - newReserve) << "/" << Squid_MaxFD << " file descriptors available)");
319 RESERVED_FD = newReserve;
320 }
321