diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srvrlib/flod.c	Tue Mar 10 13:49:58 2009 +0100
@@ -0,0 +1,440 @@
+/* Distributed Checksum Clearinghouse
+ *
+ * open, create, and check DCC server output flood mapped file
+ *
+ * Copyright (c) 2008 by Rhyolite Software, LLC
+ *
+ * This agreement is not applicable to any entity which sells anti-spam
+ * solutions to others or provides an anti-spam solution as part of a
+ * security solution sold to other entities, or to a private network
+ * which employs the DCC or uses data provided by operation of the DCC
+ * but does not provide corresponding data to other users.
+ *
+ * Permission to use, copy, modify, and distribute this software without
+ * changes for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear in all
+ * copies and any distributed versions or copies are either unchanged
+ * or not called anything similar to "DCC" or "Distributed Checksum
+ * Clearinghouse".
+ *
+ * Parties not eligible to receive a license under this agreement can
+ * obtain a commercial license to use DCC by contacting Rhyolite Software
+ * at sales@rhyolite.com.
+ *
+ * A commercial license would be for Distributed Checksum and Reputation
+ * Clearinghouse software.  That software includes additional features.  This
+ * free license for Distributed ChecksumClearinghouse Software does not in any
+ * way grant permision to use Distributed Checksum and Reputation Clearinghouse
+ * software
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
+ * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Rhyolite Software DCC 1.3.103-1.58 $Revision$
+ */
+
+#include "srvr_defs.h"
+
+FLOD_MMAPS *flod_mmaps;
+DCC_PATH flod_mmap_path;
+DCC_PATH flod_path;
+
+static int mmap_fd = -1;
+
+
+void
+flod_mmap_path_set(void)
+{
+	fnm2rel_good(flod_mmap_path,
+		     grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM,
+		     ".map");
+	fnm2rel_good(flod_path,
+		     grey_on ? GREY_FLOD_NM : DCCD_FLOD_NM,
+		     0);
+}
+
+
+
+u_char
+flod_mmap_sync(DCC_EMSG emsg, u_char touch)
+{
+	u_char result = 1;
+
+	if (flod_mmap_path[0] == '\0')
+		flod_mmap_path_set();
+
+	if (flod_mmaps
+	    && 0 > MSYNC(flod_mmaps, sizeof(*flod_mmaps), MS_SYNC)) {
+		dcc_pemsg(EX_IOERR, emsg, "msync(%s): %s",
+			  flod_mmap_path, ERROR_STR());
+		result = 0;
+		emsg = 0;
+	}
+
+	if (touch) {
+		if (mmap_fd >= 0
+		    && 0 > fsync(mmap_fd)) {
+			dcc_pemsg(EX_IOERR, emsg, "fsync(%s): %s",
+				  flod_mmap_path, ERROR_STR());
+			result = 0;
+			emsg = 0;
+		}
+
+		/* Ensure that the mtime changes at least occassionally.
+		 * Several systems do not update the mtimes of files modified
+		 * with mmap().  Some like BSD/OS delay changing the mtime until
+		 * the file is accessed with read().  Others including
+		 * filesystems on some versions of Linux apparently never change
+		 * the mtime. */
+		if (!dcc_set_mtime(emsg, flod_mmap_path, mmap_fd, 0)) {
+			result = 0;
+			emsg = 0;
+		}
+	}
+
+	return result;
+}
+
+
+
+u_char					/* 1=no problems, 0=complaints */
+flod_unmap(DCC_EMSG emsg, const DCCD_STATS *dccd_stats)
+{
+	u_char result = 1;
+
+	if (!flod_mmap_sync(emsg, 0)) {
+		result = 0;
+		emsg = 0;
+	}
+
+	if (flod_mmaps) {
+		if (dccd_stats)
+			memcpy(&flod_mmaps->dccd_stats, dccd_stats,
+			       sizeof(flod_mmaps->dccd_stats));
+		if (0 > munmap((void *)flod_mmaps, sizeof(*flod_mmaps))) {
+			dcc_pemsg(EX_IOERR, emsg, "munmap(%s,%d): %s",
+				  flod_mmap_path,
+				  ISZ(*flod_mmaps), ERROR_STR());
+			result = 0;
+			emsg = 0;
+		}
+		flod_mmaps = 0;
+	}
+
+	if (mmap_fd >= 0) {
+		if (close(mmap_fd) < 0) {
+			dcc_pemsg(EX_IOERR, emsg, "close(%s): %s",
+				  flod_mmap_path, ERROR_STR());
+			result = 0;
+			emsg = 0;
+		}
+		mmap_fd = -1;
+	}
+
+	return result;
+}
+
+
+
+static int				/* 1=success, 0=retry, -1=fatal */
+flod_mmap_try(DCC_EMSG emsg,
+	      const DB_SN *sn,
+	      u_char rw)		/* 0=rdonly/unlocked, 1=write/locked */
+{
+	int flags;
+	struct stat sb;
+	union {
+	    FLOD_MMAPS	m;
+	    u_char	b[1];
+	} init;
+	void *p;
+	int i;
+
+	if (flod_mmap_path[0] == '\0')
+		flod_mmap_path_set();
+
+	if (rw)
+		mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDWR|O_CREAT,
+					DCC_LOCK_OPEN_NOWAIT,
+					DCC_LOCK_ALL_FILE, 0);
+	else
+		mmap_fd = dcc_lock_open(emsg, flod_mmap_path, O_RDONLY,
+					DCC_LOCK_OPEN_NOLOCK, 0, 0);
+	if (mmap_fd == -1)
+		return (errno == EWOULDBLOCK) ? -1 : 0;
+
+	if (fstat(mmap_fd, &sb) < 0) {
+		dcc_pemsg(EX_IOERR, emsg, "stat(%s): %s",
+			  flod_mmap_path, ERROR_STR());
+		flod_unmap(0, 0);
+		return 0;
+	}
+	if (0 > fcntl(mmap_fd, F_SETFD, FD_CLOEXEC)) {
+		dcc_pemsg(EX_IOERR, emsg, "fcntl(%s, FD_CLOEXEC): %s",
+			  flod_mmap_path, ERROR_STR());
+		flod_unmap(0, 0);
+		return 0;
+	}
+
+	if (sb.st_size == 0 && rw) {
+		memset(&init, 0, sizeof(init));
+		strcpy(init.m.magic, FLOD_MMAP_MAGIC);
+		if (sn)
+			init.m.sn = *sn;
+		i = write(mmap_fd, &init, sizeof(init));
+		if (i < 0) {
+			dcc_pemsg(EX_IOERR, emsg, "write(%s, init): %s",
+				  flod_mmap_path, ERROR_STR());
+			flod_unmap(0, 0);
+			return -1;
+		}
+		if (i != ISZ(init)) {
+			dcc_pemsg(EX_IOERR, emsg,
+				  "write(%s, init)=%d instead of %d",
+				  flod_mmap_path, i, ISZ(init));
+			flod_unmap(0, 0);
+			return -1;
+		}
+	} else {
+		i = read(mmap_fd, &init, sizeof(init));
+		if (i < 0) {
+			dcc_pemsg(EX_IOERR, emsg, "read(%s, init): %s",
+				  flod_mmap_path, ERROR_STR());
+			flod_unmap(0, 0);
+			return -1;
+		}
+		if (i < ISZ(init)) {
+			if (i < sb.st_size) {
+				dcc_pemsg(EX_IOERR, emsg, "read(%s, init)=%d",
+					  flod_mmap_path, i);
+				flod_unmap(0, 0);
+				return -1;
+			}
+		}
+	}
+
+	if (sb.st_size >= (off_t)sizeof(init.m.magic)
+	    && strcmp(init.m.magic, FLOD_MMAP_MAGIC)) {
+		dcc_pemsg(EX_IOERR, emsg, "wrong magic in %s;"
+			  " \"%s\" instead of \"%s\"",
+			  flod_mmap_path, init.m.magic, FLOD_MMAP_MAGIC);
+		flod_unmap(0, 0);
+		return 0;
+	}
+
+	flags = rw ? (PROT_READ|PROT_WRITE) : PROT_READ;
+	p = mmap(0, sizeof(*flod_mmaps), flags, MAP_SHARED, mmap_fd, 0);
+	if (p == MAP_FAILED) {
+		dcc_pemsg(EX_IOERR, emsg, "mmap(%s): %s",
+			  flod_mmap_path, ERROR_STR());
+		flod_unmap(0, 0);
+		return 0;
+	}
+	flod_mmaps = p;
+
+	if (sb.st_size == 0) {
+		dcc_pemsg(EX_IOERR, emsg, "%s (re)created", flod_mmap_path);
+	} else if (sb.st_size != sizeof(FLOD_MMAPS)) {
+		dcc_pemsg(EX_IOERR, emsg, "%s has size %d instead of %d",
+			  flod_mmap_path, (int)sb.st_size, ISZ(FLOD_MMAPS));
+		flod_unmap(0, 0);
+		return 0;
+	}
+
+	if (sn
+	    && memcmp(&flod_mmaps->sn, sn, sizeof(flod_mmaps->sn))) {
+		char sn1_buf[30], sn2_buf[32];
+		dcc_pemsg(EX_IOERR, emsg, "s/n %s instead of %s in %s",
+			  ts2str(sn1_buf, sizeof(sn1_buf), &flod_mmaps->sn),
+			  ts2str(sn2_buf, sizeof(sn2_buf), sn),
+			  flod_mmap_path);
+		flod_unmap(0, 0);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+
+u_char					/* 0=failed, 1=mapped */
+flod_mmap(DCC_EMSG emsg,
+	  const DB_SN *sn,
+	  const DCCD_STATS *dccd_stats,
+	  u_char rw,			/* 0=rdonly/unlocked, 1=write/locked */
+	  u_char trace)
+{
+	int i;
+
+	if (!flod_unmap(emsg, dccd_stats) && emsg) {
+		if (trace)
+			dcc_trace_msg("%s", emsg);
+		*emsg = '\0';
+	}
+
+	/* try to open the existing file */
+	i = flod_mmap_try(emsg, sn, rw);
+
+	/* finished if that went well or we are not allowed to fix things */
+	if (i != 0 || !rw)
+		return i > 0;
+
+	/* delete the file if it is broken */
+	if (emsg && *emsg != '\0') {
+		if (trace)
+			dcc_trace_msg("%s", emsg);
+		*emsg = '\0';
+	}
+	if (0 > unlink(flod_mmap_path)
+	    && errno != ENOENT) {
+		dcc_pemsg(EX_IOERR, emsg, "unlink(%s): %s",
+			  flod_mmap_path, ERROR_STR());
+		flod_unmap(0, 0);
+		return 0;
+	}
+	flod_unmap(0, 0);
+
+	/* try to recreate the file */
+	if (flod_mmap_try(emsg, sn, 1) > 0) {
+		if (emsg) {
+			if (trace)
+				dcc_trace_msg("%s", emsg);
+			*emsg = '\0';
+		}
+		return 1;
+	}
+
+	flod_unmap(0, 0);
+	return 0;
+}
+
+
+
+const char *
+flod_stats_printf(char *buf, int buf_len,
+		  int st,		/* 0=off, 1=restarting, 2=on */
+		  int oflods_total,
+		  int oflods_active,
+		  int iflods_active)
+{
+	snprintf(buf, buf_len,
+		 "flood %s %3d streams  %d out active %d in",
+		 st == 0 ? "off" : st == 1 ? "restarting" : "on",
+		 oflods_total, oflods_active, iflods_active);
+	return buf;
+}
+
+
+
+static void
+mmap_fg_sub(char **bufp, int *buf_lenp,
+	    const char **prefix, const char *str)
+{
+	int i;
+
+	i = snprintf(*bufp, *buf_lenp, "%s%s", *prefix, str);
+	if (*buf_lenp <= i) {
+		*buf_lenp = 0;
+	} else {
+		*bufp += i;
+		*buf_lenp -= i;
+	}
+	*prefix = "  ";
+}
+
+
+const char *
+flodmap_fg(char *buf, int buf_len,
+	     const char *prefix, const FLOD_MMAP *mp)
+{
+	char *buf0 = buf;
+
+	if (!buf_len)
+		return "";
+	*buf = '\0';
+	if (!mp)
+		return buf0;
+
+	if ((mp->flags & FLODMAP_FG_IN_OFF)
+	    && (mp->flags & FLODMAP_FG_OUT_OFF)) {
+		mmap_fg_sub(&buf, &buf_len, &prefix, "off");
+	} else {
+		if (mp->flags & FLODMAP_FG_IN_OFF)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "in off");
+		if (mp->flags & FLODMAP_FG_OUT_OFF)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "out off");
+	}
+
+	if (mp->flags & FLODMAP_FG_ROGUE)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "crazy");
+
+	if (mp->flags & FLODMAP_FG_REWINDING)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "rewinding");
+
+	if (mp->flags & FLODMAP_FG_NEED_REWIND)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "need rewind");
+	else if (mp->flags & FLODMAP_FG_FFWD_IN)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "need FFWD");
+
+	if (mp->flags & FLODMAP_FG_PASSIVE)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "passive");
+	if ((mp->flags & FLODMAP_FG_OUT_SRVR)
+	    && !(mp->flags & FLODMAP_FG_PASSIVE))
+		mmap_fg_sub(&buf, &buf_len, &prefix, "forced passive");
+
+	if (!(mp->flags & FLODMAP_FG_IN_SRVR)) {
+		if (mp->flags & FLODMAP_FG_SOCKS)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "SOCKS");
+		if (mp->flags & FLODMAP_FG_NAT)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "NAT");
+	} else {
+		if (mp->flags & FLODMAP_FG_SOCKS)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "rejected SOCKS");
+		if (mp->flags & FLODMAP_FG_NAT)
+			mmap_fg_sub(&buf, &buf_len, &prefix, "rejected NAT");
+	}
+
+	if (mp->flags & FLODMAP_FG_LEAF)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "leaf");
+
+	if (mp->flags & FLODMAP_FG_MAPPED)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "IDs mapped");
+
+	if (mp->flags & FLODMAP_FG_FFWD_IN)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "want fastforward");
+
+	if (mp->flags & FLODMAP_FG_USE_2PASSWD)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "2nd password");
+
+	if (mp->flags & FLODMAP_FG_IPv4)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "IPv4");
+
+	if (mp->flags & FLODMAP_FG_IPv6)
+		mmap_fg_sub(&buf, &buf_len, &prefix, "IPv6");
+
+	return buf0;
+}
+
+
+
+/* this function lets clients such as dbclean know when flooding is quiet */
+int					/* -1=sick, 0=off, 1=not off */
+flod_running(const char *st)
+{
+	char off_buf[11];
+	int out, active, in;
+
+	if (4 != sscanf(st, "flood %10s %d streams %d out active %d in",
+			off_buf, &out, &active, &in))
+		return 1;
+
+	if (strcmp(off_buf, "off"))
+		return 1;
+	return active != 0 || in != 0;
+}