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