Mercurial > notdcc
comparison srvrlib/flod.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c7f6b056b673 |
---|---|
1 /* Distributed Checksum Clearinghouse | |
2 * | |
3 * open, create, and check DCC server output flood mapped file | |
4 * | |
5 * Copyright (c) 2008 by Rhyolite Software, LLC | |
6 * | |
7 * This agreement is not applicable to any entity which sells anti-spam | |
8 * solutions to others or provides an anti-spam solution as part of a | |
9 * security solution sold to other entities, or to a private network | |
10 * which employs the DCC or uses data provided by operation of the DCC | |
11 * but does not provide corresponding data to other users. | |
12 * | |
13 * Permission to use, copy, modify, and distribute this software without | |
14 * changes for any purpose with or without fee is hereby granted, provided | |
15 * that the above copyright notice and this permission notice appear in all | |
16 * copies and any distributed versions or copies are either unchanged | |
17 * or not called anything similar to "DCC" or "Distributed Checksum | |
18 * Clearinghouse". | |
19 * | |
20 * Parties not eligible to receive a license under this agreement can | |
21 * obtain a commercial license to use DCC by contacting Rhyolite Software | |
22 * at sales@rhyolite.com. | |
23 * | |
24 * A commercial license would be for Distributed Checksum and Reputation | |
25 * Clearinghouse software. That software includes additional features. This | |
26 * free license for Distributed ChecksumClearinghouse Software does not in any | |
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse | |
28 * software | |
29 * | |
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL | |
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC | |
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | |
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
37 * SOFTWARE. | |
38 * | |
39 * Rhyolite Software DCC 1.3.103-1.58 $Revision$ | |
40 */ | |
41 | |
42 #include "srvr_defs.h" | |
43 | |
44 FLOD_MMAPS *flod_mmaps; | |
45 DCC_PATH flod_mmap_path; | |
46 DCC_PATH flod_path; | |
47 | |
48 static int mmap_fd = -1; | |
49 | |
50 | |
51 void | |
52 flod_mmap_path_set(void) | |
53 { | |
54 fnm2rel_good(flod_mmap_path, | |
55 grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM, | |
56 ".map"); | |
57 fnm2rel_good(flod_path, | |
58 grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM, | |
59 0); | |
60 } | |
61 | |
62 | |
63 | |
64 u_char | |
65 flod_mmap_sync(DCC_EMSG emsg, u_char touch) | |
66 { | |
67 u_char result = 1; | |
68 | |
69 if (flod_mmap_path[0] == '\0') | |
70 flod_mmap_path_set(); | |
71 | |
72 if (flod_mmaps | |
73 && 0 > MSYNC(flod_mmaps, sizeof(*flod_mmaps), MS_SYNC)) { | |
74 dcc_pemsg(EX_IOERR, emsg, "msync(%s): %s", | |
75 flod_mmap_path, ERROR_STR()); | |
76 result = 0; | |
77 emsg = 0; | |
78 } | |
79 | |
80 if (touch) { | |
81 if (mmap_fd >= 0 | |
82 && 0 > fsync(mmap_fd)) { | |
83 dcc_pemsg(EX_IOERR, emsg, "fsync(%s): %s", | |
84 flod_mmap_path, ERROR_STR()); | |
85 result = 0; | |
86 emsg = 0; | |
87 } | |
88 | |
89 /* Ensure that the mtime changes at least occassionally. | |
90 * Several systems do not update the mtimes of files modified | |
91 * with mmap(). Some like BSD/OS delay changing the mtime until | |
92 * the file is accessed with read(). Others including | |
93 * filesystems on some versions of Linux apparently never change | |
94 * the mtime. */ | |
95 if (!dcc_set_mtime(emsg, flod_mmap_path, mmap_fd, 0)) { | |
96 result = 0; | |
97 emsg = 0; | |
98 } | |
99 } | |
100 | |
101 return result; | |
102 } | |
103 | |
104 | |
105 | |
106 u_char /* 1=no problems, 0=complaints */ | |
107 flod_unmap(DCC_EMSG emsg, const DCCD_STATS *dccd_stats) | |
108 { | |
109 u_char result = 1; | |
110 | |
111 if (!flod_mmap_sync(emsg, 0)) { | |
112 result = 0; | |
113 emsg = 0; | |
114 } | |
115 | |
116 if (flod_mmaps) { | |
117 if (dccd_stats) | |
118 memcpy(&flod_mmaps->dccd_stats, dccd_stats, | |
119 sizeof(flod_mmaps->dccd_stats)); | |
120 if (0 > munmap((void *)flod_mmaps, sizeof(*flod_mmaps))) { | |
121 dcc_pemsg(EX_IOERR, emsg, "munmap(%s,%d): %s", | |
122 flod_mmap_path, | |
123 ISZ(*flod_mmaps), ERROR_STR()); | |
124 result = 0; | |
125 emsg = 0; | |
126 } | |
127 flod_mmaps = 0; | |
128 } | |
129 | |
130 if (mmap_fd >= 0) { | |
131 if (close(mmap_fd) < 0) { | |
132 dcc_pemsg(EX_IOERR, emsg, "close(%s): %s", | |
133 flod_mmap_path, ERROR_STR()); | |
134 result = 0; | |
135 emsg = 0; | |
136 } | |
137 mmap_fd = -1; | |
138 } | |
139 | |
140 return result; | |
141 } | |
142 | |
143 | |
144 | |
145 static int /* 1=success, 0=retry, -1=fatal */ | |
146 flod_mmap_try(DCC_EMSG emsg, | |
147 const DB_SN *sn, | |
148 u_char rw) /* 0=rdonly/unlocked, 1=write/locked */ | |
149 { | |
150 int flags; | |
151 struct stat sb; | |
152 union { | |
153 FLOD_MMAPS m; | |
154 u_char b[1]; | |
155 } init; | |
156 void *p; | |
157 int i; | |
158 | |
159 if (flod_mmap_path[0] == '\0') | |
160 flod_mmap_path_set(); | |
161 | |
162 if (rw) | |
163 mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDWR|O_CREAT, | |
164 DCC_LOCK_OPEN_NOWAIT, | |
165 DCC_LOCK_ALL_FILE, 0); | |
166 else | |
167 mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDONLY, | |
168 DCC_LOCK_OPEN_NOLOCK, 0, 0); | |
169 if (mmap_fd == -1) | |
170 return (errno == EWOULDBLOCK) ? -1 : 0; | |
171 | |
172 if (fstat(mmap_fd, &sb) < 0) { | |
173 dcc_pemsg(EX_IOERR, emsg, "stat(%s): %s", | |
174 flod_mmap_path, ERROR_STR()); | |
175 flod_unmap(0, 0); | |
176 return 0; | |
177 } | |
178 if (0 > fcntl(mmap_fd, F_SETFD, FD_CLOEXEC)) { | |
179 dcc_pemsg(EX_IOERR, emsg, "fcntl(%s, FD_CLOEXEC): %s", | |
180 flod_mmap_path, ERROR_STR()); | |
181 flod_unmap(0, 0); | |
182 return 0; | |
183 } | |
184 | |
185 if (sb.st_size == 0 && rw) { | |
186 memset(&init, 0, sizeof(init)); | |
187 strcpy(init.m.magic, FLOD_MMAP_MAGIC); | |
188 if (sn) | |
189 init.m.sn = *sn; | |
190 i = write(mmap_fd, &init, sizeof(init)); | |
191 if (i < 0) { | |
192 dcc_pemsg(EX_IOERR, emsg, "write(%s, init): %s", | |
193 flod_mmap_path, ERROR_STR()); | |
194 flod_unmap(0, 0); | |
195 return -1; | |
196 } | |
197 if (i != ISZ(init)) { | |
198 dcc_pemsg(EX_IOERR, emsg, | |
199 "write(%s, init)=%d instead of %d", | |
200 flod_mmap_path, i, ISZ(init)); | |
201 flod_unmap(0, 0); | |
202 return -1; | |
203 } | |
204 } else { | |
205 i = read(mmap_fd, &init, sizeof(init)); | |
206 if (i < 0) { | |
207 dcc_pemsg(EX_IOERR, emsg, "read(%s, init): %s", | |
208 flod_mmap_path, ERROR_STR()); | |
209 flod_unmap(0, 0); | |
210 return -1; | |
211 } | |
212 if (i < ISZ(init)) { | |
213 if (i < sb.st_size) { | |
214 dcc_pemsg(EX_IOERR, emsg, "read(%s, init)=%d", | |
215 flod_mmap_path, i); | |
216 flod_unmap(0, 0); | |
217 return -1; | |
218 } | |
219 } | |
220 } | |
221 | |
222 if (sb.st_size >= (off_t)sizeof(init.m.magic) | |
223 && strcmp(init.m.magic, FLOD_MMAP_MAGIC)) { | |
224 dcc_pemsg(EX_IOERR, emsg, "wrong magic in %s;" | |
225 " \"%s\" instead of \"%s\"", | |
226 flod_mmap_path, init.m.magic, FLOD_MMAP_MAGIC); | |
227 flod_unmap(0, 0); | |
228 return 0; | |
229 } | |
230 | |
231 flags = rw ? (PROT_READ|PROT_WRITE) : PROT_READ; | |
232 p = mmap(0, sizeof(*flod_mmaps), flags, MAP_SHARED, mmap_fd, 0); | |
233 if (p == MAP_FAILED) { | |
234 dcc_pemsg(EX_IOERR, emsg, "mmap(%s): %s", | |
235 flod_mmap_path, ERROR_STR()); | |
236 flod_unmap(0, 0); | |
237 return 0; | |
238 } | |
239 flod_mmaps = p; | |
240 | |
241 if (sb.st_size == 0) { | |
242 dcc_pemsg(EX_IOERR, emsg, "%s (re)created", flod_mmap_path); | |
243 } else if (sb.st_size != sizeof(FLOD_MMAPS)) { | |
244 dcc_pemsg(EX_IOERR, emsg, "%s has size %d instead of %d", | |
245 flod_mmap_path, (int)sb.st_size, ISZ(FLOD_MMAPS)); | |
246 flod_unmap(0, 0); | |
247 return 0; | |
248 } | |
249 | |
250 if (sn | |
251 && memcmp(&flod_mmaps->sn, sn, sizeof(flod_mmaps->sn))) { | |
252 char sn1_buf[30], sn2_buf[32]; | |
253 dcc_pemsg(EX_IOERR, emsg, "s/n %s instead of %s in %s", | |
254 ts2str(sn1_buf, sizeof(sn1_buf), &flod_mmaps->sn), | |
255 ts2str(sn2_buf, sizeof(sn2_buf), sn), | |
256 flod_mmap_path); | |
257 flod_unmap(0, 0); | |
258 return 0; | |
259 } | |
260 | |
261 return 1; | |
262 } | |
263 | |
264 | |
265 | |
266 u_char /* 0=failed, 1=mapped */ | |
267 flod_mmap(DCC_EMSG emsg, | |
268 const DB_SN *sn, | |
269 const DCCD_STATS *dccd_stats, | |
270 u_char rw, /* 0=rdonly/unlocked, 1=write/locked */ | |
271 u_char trace) | |
272 { | |
273 int i; | |
274 | |
275 if (!flod_unmap(emsg, dccd_stats) && emsg) { | |
276 if (trace) | |
277 dcc_trace_msg("%s", emsg); | |
278 *emsg = '\0'; | |
279 } | |
280 | |
281 /* try to open the existing file */ | |
282 i = flod_mmap_try(emsg, sn, rw); | |
283 | |
284 /* finished if that went well or we are not allowed to fix things */ | |
285 if (i != 0 || !rw) | |
286 return i > 0; | |
287 | |
288 /* delete the file if it is broken */ | |
289 if (emsg && *emsg != '\0') { | |
290 if (trace) | |
291 dcc_trace_msg("%s", emsg); | |
292 *emsg = '\0'; | |
293 } | |
294 if (0 > unlink(flod_mmap_path) | |
295 && errno != ENOENT) { | |
296 dcc_pemsg(EX_IOERR, emsg, "unlink(%s): %s", | |
297 flod_mmap_path, ERROR_STR()); | |
298 flod_unmap(0, 0); | |
299 return 0; | |
300 } | |
301 flod_unmap(0, 0); | |
302 | |
303 /* try to recreate the file */ | |
304 if (flod_mmap_try(emsg, sn, 1) > 0) { | |
305 if (emsg) { | |
306 if (trace) | |
307 dcc_trace_msg("%s", emsg); | |
308 *emsg = '\0'; | |
309 } | |
310 return 1; | |
311 } | |
312 | |
313 flod_unmap(0, 0); | |
314 return 0; | |
315 } | |
316 | |
317 | |
318 | |
319 const char * | |
320 flod_stats_printf(char *buf, int buf_len, | |
321 int st, /* 0=off, 1=restarting, 2=on */ | |
322 int oflods_total, | |
323 int oflods_active, | |
324 int iflods_active) | |
325 { | |
326 snprintf(buf, buf_len, | |
327 "flood %s %3d streams %d out active %d in", | |
328 st == 0 ? "off" : st == 1 ? "restarting" : "on", | |
329 oflods_total, oflods_active, iflods_active); | |
330 return buf; | |
331 } | |
332 | |
333 | |
334 | |
335 static void | |
336 mmap_fg_sub(char **bufp, int *buf_lenp, | |
337 const char **prefix, const char *str) | |
338 { | |
339 int i; | |
340 | |
341 i = snprintf(*bufp, *buf_lenp, "%s%s", *prefix, str); | |
342 if (*buf_lenp <= i) { | |
343 *buf_lenp = 0; | |
344 } else { | |
345 *bufp += i; | |
346 *buf_lenp -= i; | |
347 } | |
348 *prefix = " "; | |
349 } | |
350 | |
351 | |
352 const char * | |
353 flodmap_fg(char *buf, int buf_len, | |
354 const char *prefix, const FLOD_MMAP *mp) | |
355 { | |
356 char *buf0 = buf; | |
357 | |
358 if (!buf_len) | |
359 return ""; | |
360 *buf = '\0'; | |
361 if (!mp) | |
362 return buf0; | |
363 | |
364 if ((mp->flags & FLODMAP_FG_IN_OFF) | |
365 && (mp->flags & FLODMAP_FG_OUT_OFF)) { | |
366 mmap_fg_sub(&buf, &buf_len, &prefix, "off"); | |
367 } else { | |
368 if (mp->flags & FLODMAP_FG_IN_OFF) | |
369 mmap_fg_sub(&buf, &buf_len, &prefix, "in off"); | |
370 if (mp->flags & FLODMAP_FG_OUT_OFF) | |
371 mmap_fg_sub(&buf, &buf_len, &prefix, "out off"); | |
372 } | |
373 | |
374 if (mp->flags & FLODMAP_FG_ROGUE) | |
375 mmap_fg_sub(&buf, &buf_len, &prefix, "crazy"); | |
376 | |
377 if (mp->flags & FLODMAP_FG_REWINDING) | |
378 mmap_fg_sub(&buf, &buf_len, &prefix, "rewinding"); | |
379 | |
380 if (mp->flags & FLODMAP_FG_NEED_REWIND) | |
381 mmap_fg_sub(&buf, &buf_len, &prefix, "need rewind"); | |
382 else if (mp->flags & FLODMAP_FG_FFWD_IN) | |
383 mmap_fg_sub(&buf, &buf_len, &prefix, "need FFWD"); | |
384 | |
385 if (mp->flags & FLODMAP_FG_PASSIVE) | |
386 mmap_fg_sub(&buf, &buf_len, &prefix, "passive"); | |
387 if ((mp->flags & FLODMAP_FG_OUT_SRVR) | |
388 && !(mp->flags & FLODMAP_FG_PASSIVE)) | |
389 mmap_fg_sub(&buf, &buf_len, &prefix, "forced passive"); | |
390 | |
391 if (!(mp->flags & FLODMAP_FG_IN_SRVR)) { | |
392 if (mp->flags & FLODMAP_FG_SOCKS) | |
393 mmap_fg_sub(&buf, &buf_len, &prefix, "SOCKS"); | |
394 if (mp->flags & FLODMAP_FG_NAT) | |
395 mmap_fg_sub(&buf, &buf_len, &prefix, "NAT"); | |
396 } else { | |
397 if (mp->flags & FLODMAP_FG_SOCKS) | |
398 mmap_fg_sub(&buf, &buf_len, &prefix, "rejected SOCKS"); | |
399 if (mp->flags & FLODMAP_FG_NAT) | |
400 mmap_fg_sub(&buf, &buf_len, &prefix, "rejected NAT"); | |
401 } | |
402 | |
403 if (mp->flags & FLODMAP_FG_LEAF) | |
404 mmap_fg_sub(&buf, &buf_len, &prefix, "leaf"); | |
405 | |
406 if (mp->flags & FLODMAP_FG_MAPPED) | |
407 mmap_fg_sub(&buf, &buf_len, &prefix, "IDs mapped"); | |
408 | |
409 if (mp->flags & FLODMAP_FG_FFWD_IN) | |
410 mmap_fg_sub(&buf, &buf_len, &prefix, "want fastforward"); | |
411 | |
412 if (mp->flags & FLODMAP_FG_USE_2PASSWD) | |
413 mmap_fg_sub(&buf, &buf_len, &prefix, "2nd password"); | |
414 | |
415 if (mp->flags & FLODMAP_FG_IPv4) | |
416 mmap_fg_sub(&buf, &buf_len, &prefix, "IPv4"); | |
417 | |
418 if (mp->flags & FLODMAP_FG_IPv6) | |
419 mmap_fg_sub(&buf, &buf_len, &prefix, "IPv6"); | |
420 | |
421 return buf0; | |
422 } | |
423 | |
424 | |
425 | |
426 /* this function lets clients such as dbclean know when flooding is quiet */ | |
427 int /* -1=sick, 0=off, 1=not off */ | |
428 flod_running(const char *st) | |
429 { | |
430 char off_buf[11]; | |
431 int out, active, in; | |
432 | |
433 if (4 != sscanf(st, "flood %10s %d streams %d out active %d in", | |
434 off_buf, &out, &active, &in)) | |
435 return 1; | |
436 | |
437 if (strcmp(off_buf, "off")) | |
438 return 1; | |
439 return active != 0 || in != 0; | |
440 } |