svn commit: r246722 - user/des/ndr

Dag-Erling Smørgrav des at FreeBSD.org
Tue Feb 12 22:35:16 UTC 2013


Author: des
Date: Tue Feb 12 22:35:14 2013
New Revision: 246722
URL: http://svnweb.freebsd.org/changeset/base/246722

Log:
  Old code from projcvs I'd completely forgotten about.

Added:
  user/des/ndr/Makefile   (contents, props changed)
  user/des/ndr/ndr.1   (contents, props changed)
  user/des/ndr/ndr.h   (contents, props changed)
  user/des/ndr/ndr_client.c   (contents, props changed)
  user/des/ndr/ndr_main.c   (contents, props changed)
  user/des/ndr/ndr_protocol.c   (contents, props changed)
  user/des/ndr/ndr_server.c   (contents, props changed)
Directory Properties:
  user/des/ndr/   (props changed)

Added: user/des/ndr/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/Makefile	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+PROG	 = ndr
+SRCS	 = ndr_main.c ndr_protocol.c ndr_client.c ndr_server.c
+CSTD	 = c99
+WARNS	?= 6
+WFORMAT	?= 1
+
+DPADD	 = ${LIBMD}
+LDADD	 = -lmd
+
+.include <bsd.prog.mk>

Added: user/des/ndr/ndr.1
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr.1	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,134 @@
+.\"-
+.\" Copyright (c) 2007 Dag-Erling Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 20, 2007
+.Dt NDR 1
+.Os
+.Sh NAME
+.Nm ndr
+.Nd network-assisted disk recovery
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Op Fl a Ar addr
+.Op Fl d Ar dir
+.Op Fl p Ar port
+.Fl s
+.Nm
+.Op Fl v
+.Op Fl a Ar addr
+.Op Fl p Ar port
+.Fl c
+.Ar device
+.Ar host
+.Op Ar port
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to recover the contents of a damaged disk over the
+network.
+One instance of
+.Nm
+runs in client mode on the machine to which the damaged disk is
+attached.
+Another instance runs in server mode on a separate machine.
+.Pp
+When the client contacts the server and announces the device which is
+to be recovered, the server creates a file of the appropriate size and
+starts requesting blocks of data from the client.
+As recovery progresses, the server keeps track of recovered and failed
+blocks in a separate file.
+Thus, both the server and the client can be interrupted and restarted
+without losing progress.
+This is particularly useful when a disk is so badly damaged that the
+client machine crashes during recovery.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Fl a Ar addr
+Bind to the specified address.
+.It Fl c
+Work in client mode.
+The name of the device to recover, the name or address of the server,
+and (optionally) the server's port number must be specified on the
+command line after all other options.
+.It Fl d Ar dir
+In server mode, work from the specified directory.
+For each client that connects to the server, a subdirectory named
+after the IP address of the client is created within the working
+directory.
+The data and map files for each device are stored in directories named
+after the device within each client directory.
+.It Fl p Ar port
+Bind to the specified port.
+.It Fl s
+Work in server mode.
+.It Fl v
+Increase the verbosity level.
+Specifying this option more than once may result in overwhelming
+amounts of debugging output.
+.El
+.Sh EXAMPLES
+Start a server which will listen on port 6543 at the address
+corresponding to
+.Pa ndr.example.com ,
+store the data it receives in
+.Pa /var/ndr ,
+and show a moderate amount of debugging information:
+.Bd -literal -offset indent
+ndr -s -a ndr.example.com -p 6543 -d /var/ndr -v
+.Ed
+.Pp
+Start a client which will transfer the contents of
+.Pa /dev/ad4
+to the server running on port 6543 on
+.Pa ndr.example.com :
+.Bd -literal -offset indent
+ndr -c /dev/ad4 ndr.example.com 6543
+.Ed
+.Pp
+The following
+.Xr hexdump 1
+command line displays the contents of a map file:
+.Bd -literal -offset indent
+hexdump -v -e '"%07.7_ax " 64/1 "%_c" "\\n"' map
+.Ed
+.Pp
+Each output line starts with a hexadecimal offset followed by 64 ASCII
+characters, each representing one block of the device.
+Successfully recovered blocks are marked with a hash sign.
+Blocks which have failed but will be retried are marked with a digit
+reflecting the number of attempts that have been made.
+Blocks which
+.Nm
+has given up on are marked with an asterisk.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility and this manual page were written by
+.An Dag-Erling Sm\(/orgrav Aq des at FreeBSD.org .

Added: user/des/ndr/ndr.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr.h	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef NDR_H_INCLUDED
+#define NDR_H_INCLUDED
+
+void	 verbose(int level, const char *fmt, ...);
+void	 status(const char *fmt, ...);
+
+void	 client(const char *device, const char *saddr, const char *sport,
+    const char *daddr, const char *dport);
+void	 server(const char *laddr, const char *lport);
+
+int	 client_socket(const char *saddr, const char *sport,
+    const char *daddr, const char *dport);
+int	 server_socket(const char *laddr, const char *lport);
+int	 accept_socket(int sd, char **saddr, char **sport);
+
+void	 sendstr(int sd, const char *str, size_t len);
+void	 sendstrf(int sd, const char *fmt, ...);
+void	 senddata(int sd, const void *buf, size_t len);
+void	 read_full(int sd, void *buf, size_t len);
+char	*recvstr(int sd, char **str, size_t *len);
+void	*recvdata(int sd, void **buf, size_t *len, size_t *datalen);
+
+#endif

Added: user/des/ndr/ndr_client.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr_client.c	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <md5.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ndr.h"
+
+void
+client(const char *device, const char *saddr, const char *sport,
+    const char *daddr, const char *dport)
+{
+	uintmax_t size, bsize;
+	struct stat st;
+	int dd, sd;
+
+	/* open device */
+	if ((dd = open(device, O_RDONLY)) < 0)
+		err(1, "%s", device);
+	if (fstat(dd, &st) == -1)
+		err(1, "fstat()");
+	if (S_ISCHR(st.st_mode)) {
+		off_t ot;
+		unsigned int ui;
+
+		if (ioctl(dd, DIOCGMEDIASIZE, &ot) == -1)
+			err(1, "ioctl(DIOCGMEDIASIZE)");
+		size = ot;
+		if (ioctl(dd, DIOCGSECTORSIZE, &ui) == -1)
+			err(1, "ioctl(DIOCGSECTORSIZE)");
+		bsize = ui;
+	} else if (S_ISREG(st.st_mode)) {
+		size = st.st_size;
+		bsize = st.st_blksize;
+	} else {
+		errx(1, "invalid device type");
+	}
+
+	/* connect to server */
+	sd = client_socket(saddr, sport, daddr, dport);
+
+	/* send device information */
+	sendstrf(sd, "device %s", device);
+	sendstrf(sd, "size %016jx %08jx", size, bsize);
+	sendstrf(sd, "ready");
+
+	/* process server requests */
+	void *buf = NULL;
+	size_t buflen = 0;
+	char *str = NULL;
+	size_t len = 0;
+	for (;;) {
+		uintmax_t rstart, rstop;
+		int verify;
+
+		recvstr(sd, &str, &len);
+		if (strcmp(str, "done") == 0) {
+			break;
+		} else if (sscanf(str, "verify %jx %jx", &rstart, &rstop) == 2) {
+			verify = 1;
+		} else if (sscanf(str, "read %jx %jx", &rstart, &rstop) == 2) {
+			verify = 0;
+		} else {
+			errx(1, "protocol error");
+		}
+
+		if (rstop < rstart)
+			errx(1, "protocol error");
+
+		off_t off = rstart * bsize;
+		size_t rlen = (rstop - rstart + 1) * bsize;
+		if ((uintmax_t)(off + rlen) > size ||
+		    lseek(dd, off, SEEK_SET) != off) {
+			sendstrf(sd, "failed");
+			continue;
+		}
+		if (buflen < rlen)
+			if ((buf = reallocf(buf, rlen)) == NULL)
+				err(1, "realloc()");
+		status("%s blocks %ju - %ju from %s",
+		    verify ? "verifying" : "reading",
+		    rstart, rstop, device);
+		ssize_t ret = read(dd, buf, rlen);
+		if (ret < 0) {
+			warn("read()");
+			sendstrf(sd, "failed");
+			continue;
+		}
+		uintmax_t dlen = ret;
+		uintmax_t dstart = rstart;
+		uintmax_t dstop = rstop;
+		if (dlen < rlen) {
+			warnx("read(): short read");
+			dstop = dstart + dlen / bsize - 1;
+		}
+		if (verify) {
+			char md5[33];
+			MD5Data(buf, dlen, md5);
+			sendstrf(sd, "md5 %016jx %016jx", dstart, dstop);
+			sendstrf(sd, "%s", md5);
+		} else {
+			sendstrf(sd, "data %016jx %016jx", dstart, dstop);
+			senddata(sd, buf, (dstop - dstart + 1) * bsize);
+		}
+	}
+	status("done");
+	status("");
+	exit(0);
+}

Added: user/des/ndr/ndr_main.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr_main.c	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ndr.h"
+
+static const char	*a_arg;
+static int		 c_flag;
+static const char	*d_arg;
+static const char	*p_arg;
+static int		 s_flag;
+static int		 v_count;
+
+static void
+usage(void)
+{
+
+	fprintf(stderr,
+	    "usage: ndr [-v] [-d dir] [-a addr] [-p port] -s\n"
+	    "       ndr [-v] -c <device> <server> [<port>]\n");
+	exit(1);
+}
+
+void
+verbose(int level, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (v_count >= level) {
+		va_start(ap, fmt);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+void
+status(const char *fmt, ...)
+{
+	static struct timeval prev;
+	struct timeval now;
+	static int olen = 0;
+	va_list ap;
+	int len;
+
+	if (!isatty(STDERR_FILENO) || v_count > 1)
+		return;
+
+	if (fmt[0] == '\0') {
+		/* cleanup requested */
+		fputc('\n', stderr);
+		return;
+	}
+
+	gettimeofday(&now, NULL);
+	if (now.tv_sec == prev.tv_sec)
+		return;
+
+	prev = now;
+	fputc('\r', stderr);
+	va_start(ap, fmt);
+	len = vfprintf(stderr, fmt, ap);
+	va_end(ap);
+
+	for (int i = len; i < olen; ++i)
+		fputc(' ', stderr);
+	olen = len;
+}
+
+int
+main(int argc, char *argv[])
+{
+	int opt;
+
+	while ((opt = getopt(argc, argv, "a:cd:p:sv")) != -1)
+		switch (opt) {
+		case 'a':
+			a_arg = optarg;
+			break;
+		case 'c':
+			c_flag = 1;
+			break;
+		case 'd':
+			d_arg = optarg;
+			break;
+		case 'p':
+			p_arg = optarg;
+			break;
+		case 's':
+			s_flag = 1;
+			break;
+		case 'v':
+			v_count++;
+			break;
+		default:
+			usage();
+		}
+
+	argc -= optind;
+	argv += optind;
+
+	if (!(c_flag ^ s_flag))
+		usage();
+
+	if (c_flag) {
+		if (d_arg || argc < 2 || argc > 3)
+			usage();
+		client(argv[0], a_arg, p_arg, argv[1], argv[2]);
+	} else if (s_flag) {
+		if (argc > 0)
+			usage();
+		if (d_arg && chdir(d_arg) != 0)
+			err(1, "chdir(%s)", d_arg);
+		server(a_arg, p_arg);
+	} else {
+		usage();
+	}
+	errx(1, "not reached");
+}

Added: user/des/ndr/ndr_protocol.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr_protocol.c	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,336 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ndr.h"
+
+static const char	*ndr_default_port = "9110";
+static const char	*ndr_client_sig = "ndr client\n";
+static const char	*ndr_server_sig = "ndr server\n";
+
+static int
+handshake(int sd, const char *mine, const char *theirs)
+{
+	ssize_t mlen = strlen(mine);
+	ssize_t tlen = strlen(theirs);
+	char buf[tlen];
+
+	if (write(sd, mine, mlen) != mlen ||
+	    read(sd, buf, tlen) != tlen ||
+	    strncmp(buf, theirs, tlen) != 0)
+		return (-1);
+	return (0);
+}
+
+int
+client_socket(const char *saddr, const char *sport,
+    const char *daddr, const char *dport)
+{
+	struct addrinfo hints, *sres, *dres;
+	int one, ret, sd;
+
+	/* resolve server address */
+	memset(&hints, 0, sizeof hints);
+	hints.ai_flags = 0;
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	dres = NULL;
+	if (dport == NULL)
+		dport = ndr_default_port;
+	if ((ret = getaddrinfo(daddr, dport, &hints, &dres)) != 0)
+		errx(1, "getaddrinfo(): %s", gai_strerror(ret));
+
+	/* open socket */
+	if ((sd = socket(dres->ai_family, dres->ai_socktype, dres->ai_protocol)) < 0)
+		err(1, "socket()");
+
+	/* resolve source address if given */
+	if (saddr != NULL || sport != NULL) {
+		memset(&hints, 0, sizeof hints);
+		hints.ai_flags = AI_PASSIVE;
+		hints.ai_family = dres->ai_family;
+		hints.ai_socktype = dres->ai_socktype;
+		hints.ai_protocol = dres->ai_protocol;
+		sres = NULL;
+		if ((ret = getaddrinfo(saddr, sport, &hints, &sres)) != 0)
+			errx(1, "getaddrinfo(): %s", gai_strerror(ret));
+		one = 1;
+		if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) != 0)
+			err(1, "setsockopt(SO_REUSEADDR)");
+		if (bind(sd, sres->ai_addr, sres->ai_addrlen) != 0)
+			err(1, "connect()");
+		freeaddrinfo(sres);
+	}
+
+	/* connect to server */
+	if (connect(sd, dres->ai_addr, dres->ai_addrlen) != 0)
+		err(1, "connect()");
+	freeaddrinfo(dres);
+
+	verbose(1, "connected to server %s:%s\n", daddr, dport);
+
+	/* handshake */
+	if (handshake(sd, ndr_client_sig, ndr_server_sig) != 0)
+		errx(1, "handshake failed");
+
+	return (sd);
+}
+
+int
+server_socket(const char *laddr, const char *lport)
+{
+	struct addrinfo hints, *lres;
+	int one, ret, sd;
+
+	/* resolve listening address */
+	memset(&hints, 0, sizeof hints);
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	lres = NULL;
+	if (lport == NULL)
+		lport = ndr_default_port;
+	if ((ret = getaddrinfo(laddr, lport, &hints, &lres)) != 0)
+		errx(1, "getaddrinfo(): %s", gai_strerror(ret));
+
+	/* open listening socket */
+	if ((sd = socket(lres->ai_family, lres->ai_socktype, lres->ai_protocol)) < 0)
+		err(1, "socket()");
+	one = 1;
+	if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof one) != 0)
+		err(1, "setsockopt(SO_REUSEPORT)");
+	if (bind(sd, lres->ai_addr, lres->ai_addrlen) != 0)
+		err(1, "bind()");
+	if (listen(sd, 16) != 0)
+		err(1, "listen()");
+	freeaddrinfo(lres);
+
+	verbose(1, "server listening on %s:%s\n", laddr ? laddr : "*", lport);
+
+	return (sd);
+}
+
+int
+accept_socket(int sd, char **saddr, char **sport)
+{
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	int ad, ret;
+
+	memset(&addr, 0, addrlen = sizeof addr);
+	if ((ad = accept(sd, (struct sockaddr *)&addr, &addrlen)) < 0)
+		return (-1);
+
+	if ((*saddr = malloc(NI_MAXHOST)) == NULL ||
+	    (*sport = malloc(NI_MAXSERV)) == NULL)
+		err(1, "malloc()");
+
+	/* resolve client address */
+	if ((ret = getnameinfo((struct sockaddr *)&addr, addrlen,
+	    *saddr, NI_MAXHOST, *sport, NI_MAXSERV,
+	    NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
+		/* shouldn't happen */
+		err(1, "getnameinfo(): %s", gai_strerror(ret));
+
+	verbose(1, "accepted connection from %s:%s\n", *saddr, *sport);
+
+	if (handshake(ad, ndr_server_sig, ndr_client_sig) != 0) {
+		verbose(1, "handshake failed");
+		close(ad);
+		return (-1);
+	}
+
+	return (ad);
+}
+
+void
+sendstr(int sd, const char *str, size_t len)
+{
+	struct iovec iov[3];
+	uint32_t count;
+	char s = 's';
+	ssize_t res, ret;
+
+	if (len == 0)
+		len = strlen(str);
+	count = len;
+	verbose(2, ">>> s %08x %s\n", count, str);
+	count = htonl(count);
+	res = 0;
+	iov[0].iov_base = &s;
+	res += (iov[0].iov_len = 1);
+	iov[1].iov_base = &count;
+	res += (iov[1].iov_len = sizeof count);
+	iov[2].iov_base = (void *)(uintptr_t)str;
+	res += (iov[2].iov_len = len);
+	if ((ret = writev(sd, iov, 3)) != res) {
+		if (ret == -1)
+			err(1, "writev()");
+		errx(1, "writev(): short write (%zd / %zd)", ret, res);
+	}
+}
+
+void
+sendstrf(int sd, const char *fmt, ...)
+{
+	va_list ap;
+	char *str;
+	int len;
+
+	str = NULL;
+	va_start(ap, fmt);
+	if ((len = vasprintf(&str, fmt, ap)) == -1)
+		err(1, "malloc()");
+	va_end(ap);
+
+	sendstr(sd, str, len);
+	free(str);
+}
+
+void
+senddata(int sd, const void *buf, size_t len)
+{
+	struct iovec iov[3];
+	uint32_t count;
+	char d = 'd';
+	ssize_t res, ret;
+
+	if (len == 0)
+		len = strlen(buf);
+	count = len;
+	verbose(3, ">>> d %08x <binary data>\n", count);
+	count = htonl(count);
+	res = 0;
+	iov[0].iov_base = &d;
+	res += (iov[0].iov_len = 1);
+	iov[1].iov_base = &count;
+	res += (iov[1].iov_len = sizeof count);
+	iov[2].iov_base = (void *)(uintptr_t)buf;
+	res += (iov[2].iov_len = len);
+	if ((ret = writev(sd, iov, 3)) != res) {
+		if (ret == -1)
+			err(1, "writev()");
+		errx(1, "writev(): short write (%zd / %zd)", ret, res);
+	}
+}
+
+void
+read_full(int sd, void *buf, size_t len)
+{
+	ssize_t res, ret;
+	int retry;
+
+	for (retry = 0, res = len; res > 0; res -= ret) {
+		while ((ret = read(sd, buf, res)) < 0)
+			if (errno != EAGAIN && errno != EINTR)
+				err(1, "read()");
+		if (ret == 0) {
+			if (++retry < 5)
+				continue;
+			errx(1, "read(): short read (%zd / %zu)",
+			    len - res, len);
+		}
+		retry = 0;
+		buf = (char *)buf + ret;
+	}
+}
+
+char *
+recvstr(int sd, char **str, size_t *len)
+{
+	uint32_t count;
+	char s;
+
+	/* read marker */
+	read_full(sd, &s, sizeof s);
+	if (s != 's')
+		errx(1, "protocol error");
+
+	/* read count */
+	read_full(sd, &count, sizeof count);
+	count = ntohl(count);
+
+	/* make sure the buffer is sufficiently large */
+	if (*len < count + 1)
+		if ((*str = reallocf(*str, count + 1)) == NULL)
+			err(1, "realloc()");
+
+	/* read string */
+	read_full(sd, *str, count);
+	(*str)[count] = '\0';
+
+	/* check for early termination */
+	for (unsigned int i = 0; i < count; ++i)
+		if ((*str)[i] == '\0')
+			err(1, "protocol error");
+
+	verbose(2, "<<< s %08x %s\n", count, *str);
+	return (*str);
+}
+
+void *
+recvdata(int sd, void **buf, size_t *len, size_t *datalen)
+{
+	uint32_t count;
+	char d;
+
+	/* read marker */
+	read_full(sd, &d, sizeof d);
+	if (d != 'd')
+		errx(1, "protocol error");
+
+	/* read count */
+	read_full(sd, &count, sizeof count);
+	count = ntohl(count);
+
+	/* make sure the buffer is sufficiently large */
+	if (*len < count)
+		if ((*buf = reallocf(*buf, count)) == NULL)
+			err(1, "realloc()");
+
+	/* read data */
+	read_full(sd, *buf, count);
+
+	verbose(3, "<<< d %08x <binary data>\n", count);
+	*datalen = count;
+	return (*buf);
+}

Added: user/des/ndr/ndr_server.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/des/ndr/ndr_server.c	Tue Feb 12 22:35:14 2013	(r246722)
@@ -0,0 +1,436 @@
+/*-
+ * Copyright (c) 2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <md5.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ndr.h"
+
+struct client {
+	pid_t		 pid;		/* handler's PID */
+
+	int		 sd;		/* socket descriptor */
+	char		*host;		/* host name */
+	char		*port;		/* port number */
+	char		*device;	/* device name */
+
+	char		*wpath;		/* working directory */
+	char		*dpath;		/* data file */
+	int		 dd;		/* data file descriptor */
+	char		*mpath;		/* map file */
+	int		 md;		/* map file descriptor */
+	char		*map;		/* map file pointer */
+
+	uintmax_t	 size;		/* device size */
+	uintmax_t	 bsize;		/* device block size */
+	uintmax_t	 blocks;	/* # blocks total (size / bsize) */
+	uintmax_t	 failed;	/* # blocks failed */
+	uintmax_t	 received;	/* # blocks successfully recovered */
+	uintmax_t	 retry;		/* # blocks needing retry */
+
+	void		*buf;		/* buffer for receiving data */
+	size_t		 bufsz;		/* current size of buffer */
+	size_t		 buflen;	/* current length of buffer contents */
+
+	char		*str;		/* buffer for receiving strings */
+	size_t		 strsz;		/* current size of string buffer */
+};
+
+static volatile sig_atomic_t interrupted;
+
+static void
+interrupt(int sig)
+{
+
+	(void)sig;
+	interrupted = 1;
+}
+
+static void
+reaper(int sig)
+{
+	int ret;
+
+	(void)sig;
+	if (waitpid(0, &ret, WNOHANG) > 0 && WIFSIGNALED(ret))
+		raise(WTERMSIG(ret));
+}
+
+static void
+init_paths(struct client *cp)
+{
+	char path[PATH_MAX], rpath[PATH_MAX];
+	char *p, *q, t;
+
+	/* XXX overflow */
+	snprintf(path, sizeof path, "%s/%s", cp->host, cp->device);
+
+	/* create directory if necessary */
+	for (p = q = path; *p != '\0'; p = q) {
+		if ((q = strchr(p, '/')) == NULL)
+			q = strchr(p, '\0');
+		if ((t = *q) != '\0')
+			*q = '\0';
+		if (mkdir(path, 0755) != 0 && errno != EEXIST)
+			err(1, "mkdir(%s)", path);
+		if (t == '\0')
+			break;
+		*q++ = t;
+	}
+
+	/* resolve paths */
+	realpath(path, rpath);
+	if ((cp->wpath = strdup(rpath)) == NULL)
+		err(1, "strdup()");
+	if ((asprintf(&cp->dpath, "%s/data", cp->wpath)) < 0 ||
+	    (asprintf(&cp->mpath, "%s/map", cp->wpath)) < 0)
+		err(1, "asprintf()");
+}
+
+static void
+init_files(struct client *cp)
+{
+	struct stat st;
+	int new = 0;
+
+	/* initialize data and map */
+	if ((cp->dd = open(cp->dpath, O_RDWR|O_CREAT, 0600)) < 0)
+		err(1, "%s", cp->dpath);
+	if (fstat(cp->dd, &st) != 0)
+		err(1, "fstat(%s)", cp->dpath);
+	if (st.st_size != (off_t)cp->size)
+		new = 1;
+	if ((cp->md = open(cp->mpath, O_RDWR|O_CREAT, 0600)) < 0)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list