Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 May 2011 11:06:18 +0000 (UTC)
From:      Pawel Jakub Dawidek <pjd@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r222115 - head/sbin/hastd
Message-ID:  <201105201106.p4KB6Ir4081224@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pjd
Date: Fri May 20 11:06:17 2011
New Revision: 222115
URL: http://svn.freebsd.org/changeset/base/222115

Log:
  Rename proto_tcp4.c to proto_tcp.c in preparation for IPv6 support.
  
  MFC after:	2 weeks

Added:
  head/sbin/hastd/proto_tcp.c
     - copied unchanged from r222085, head/sbin/hastd/proto_tcp4.c
Deleted:
  head/sbin/hastd/proto_tcp4.c
Modified:
  head/sbin/hastd/Makefile

Modified: head/sbin/hastd/Makefile
==============================================================================
--- head/sbin/hastd/Makefile	Fri May 20 07:51:46 2011	(r222114)
+++ head/sbin/hastd/Makefile	Fri May 20 11:06:17 2011	(r222115)
@@ -12,7 +12,7 @@ SRCS+=	metadata.c
 SRCS+=	nv.c
 SRCS+=	secondary.c
 SRCS+=	parse.y pjdlog.c primary.c
-SRCS+=	proto.c proto_common.c proto_socketpair.c proto_tcp4.c proto_uds.c
+SRCS+=	proto.c proto_common.c proto_socketpair.c proto_tcp.c proto_uds.c
 SRCS+=	rangelock.c
 SRCS+=	subr.c
 SRCS+=	token.l

Copied: head/sbin/hastd/proto_tcp.c (from r222085, head/sbin/hastd/proto_tcp4.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sbin/hastd/proto_tcp.c	Fri May 20 11:06:17 2011	(r222115, copy of r222085, head/sbin/hastd/proto_tcp4.c)
@@ -0,0 +1,597 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pjdlog.h"
+#include "proto_impl.h"
+#include "subr.h"
+
+#define	TCP4_CTX_MAGIC	0x7c441c
+struct tcp4_ctx {
+	int			tc_magic;
+	struct sockaddr_in	tc_sin;
+	int			tc_fd;
+	int			tc_side;
+#define	TCP4_SIDE_CLIENT	0
+#define	TCP4_SIDE_SERVER_LISTEN	1
+#define	TCP4_SIDE_SERVER_WORK	2
+};
+
+static int tcp4_connect_wait(void *ctx, int timeout);
+static void tcp4_close(void *ctx);
+
+static in_addr_t
+str2ip(const char *str)
+{
+	struct hostent *hp;
+	in_addr_t ip;
+
+	ip = inet_addr(str);
+	if (ip != INADDR_NONE) {
+		/* It is a valid IP address. */
+		return (ip);
+	}
+	/* Check if it is a valid host name. */
+	hp = gethostbyname(str);
+	if (hp == NULL)
+		return (INADDR_NONE);
+	return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
+}
+
+/*
+ * Function converts the given string to unsigned number.
+ */
+static int
+numfromstr(const char *str, intmax_t minnum, intmax_t maxnum, intmax_t *nump)
+{
+	intmax_t digit, num;
+
+	if (str[0] == '\0')
+		goto invalid;	/* Empty string. */
+	num = 0;
+	for (; *str != '\0'; str++) {
+		if (*str < '0' || *str > '9')
+			goto invalid;	/* Non-digit character. */
+		digit = *str - '0';
+		if (num > num * 10 + digit)
+			goto invalid;	/* Overflow. */
+		num = num * 10 + digit;
+		if (num > maxnum)
+			goto invalid;	/* Too big. */
+	}
+	if (num < minnum)
+		goto invalid;	/* Too small. */
+	*nump = num;
+	return (0);
+invalid:
+	errno = EINVAL;
+	return (-1);
+}
+
+static int
+tcp4_addr(const char *addr, int defport, struct sockaddr_in *sinp)
+{
+	char iporhost[MAXHOSTNAMELEN];
+	const char *pp;
+	size_t size;
+	in_addr_t ip;
+
+	if (addr == NULL)
+		return (-1);
+
+	if (strncasecmp(addr, "tcp4://", 7) == 0)
+		addr += 7;
+	else if (strncasecmp(addr, "tcp://", 6) == 0)
+		addr += 6;
+	else {
+		/*
+		 * Because TCP4 is the default assume IP or host is given without
+		 * prefix.
+		 */
+	}
+
+	sinp->sin_family = AF_INET;
+	sinp->sin_len = sizeof(*sinp);
+	/* Extract optional port. */
+	pp = strrchr(addr, ':');
+	if (pp == NULL) {
+		/* Port not given, use the default. */
+		sinp->sin_port = htons(defport);
+	} else {
+		intmax_t port;
+
+		if (numfromstr(pp + 1, 1, 65535, &port) < 0)
+			return (errno);
+		sinp->sin_port = htons(port);
+	}
+	/* Extract host name or IP address. */
+	if (pp == NULL) {
+		size = sizeof(iporhost);
+		if (strlcpy(iporhost, addr, size) >= size)
+			return (ENAMETOOLONG);
+	} else {
+		size = (size_t)(pp - addr + 1);
+		if (size > sizeof(iporhost))
+			return (ENAMETOOLONG);
+		(void)strlcpy(iporhost, addr, size);
+	}
+	/* Convert string (IP address or host name) to in_addr_t. */
+	ip = str2ip(iporhost);
+	if (ip == INADDR_NONE)
+		return (EINVAL);
+	sinp->sin_addr.s_addr = ip;
+
+	return (0);
+}
+
+static int
+tcp4_setup_new(const char *addr, int side, void **ctxp)
+{
+	struct tcp4_ctx *tctx;
+	int ret, nodelay;
+
+	PJDLOG_ASSERT(addr != NULL);
+	PJDLOG_ASSERT(side == TCP4_SIDE_CLIENT ||
+	    side == TCP4_SIDE_SERVER_LISTEN);
+	PJDLOG_ASSERT(ctxp != NULL);
+
+	tctx = malloc(sizeof(*tctx));
+	if (tctx == NULL)
+		return (errno);
+
+	/* Parse given address. */
+	if ((ret = tcp4_addr(addr, PROTO_TCP4_DEFAULT_PORT,
+	    &tctx->tc_sin)) != 0) {
+		free(tctx);
+		return (ret);
+	}
+
+	PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+
+	tctx->tc_fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (tctx->tc_fd == -1) {
+		ret = errno;
+		free(tctx);
+		return (ret);
+	}
+
+	PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+
+	/* Socket settings. */
+	nodelay = 1;
+	if (setsockopt(tctx->tc_fd, IPPROTO_TCP, TCP_NODELAY, &nodelay,
+	    sizeof(nodelay)) == -1) {
+		pjdlog_errno(LOG_WARNING, "Unable to set TCP_NOELAY");
+	}
+
+	tctx->tc_side = side;
+	tctx->tc_magic = TCP4_CTX_MAGIC;
+	*ctxp = tctx;
+
+	return (0);
+}
+
+static int
+tcp4_setup_wrap(int fd, int side, void **ctxp)
+{
+	struct tcp4_ctx *tctx;
+
+	PJDLOG_ASSERT(fd >= 0);
+	PJDLOG_ASSERT(side == TCP4_SIDE_CLIENT ||
+	    side == TCP4_SIDE_SERVER_WORK);
+	PJDLOG_ASSERT(ctxp != NULL);
+
+	tctx = malloc(sizeof(*tctx));
+	if (tctx == NULL)
+		return (errno);
+
+	tctx->tc_fd = fd;
+	tctx->tc_sin.sin_family = AF_UNSPEC;
+	tctx->tc_side = side;
+	tctx->tc_magic = TCP4_CTX_MAGIC;
+	*ctxp = tctx;
+
+	return (0);
+}
+
+static int
+tcp4_client(const char *srcaddr, const char *dstaddr, void **ctxp)
+{
+	struct tcp4_ctx *tctx;
+	struct sockaddr_in sin;
+	int ret;
+
+	ret = tcp4_setup_new(dstaddr, TCP4_SIDE_CLIENT, ctxp);
+	if (ret != 0)
+		return (ret);
+	tctx = *ctxp;
+	if (srcaddr == NULL)
+		return (0);
+	ret = tcp4_addr(srcaddr, 0, &sin);
+	if (ret != 0) {
+		tcp4_close(tctx);
+		return (ret);
+	}
+	if (bind(tctx->tc_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+		ret = errno;
+		tcp4_close(tctx);
+		return (ret);
+	}
+	return (0);
+}
+
+static int
+tcp4_connect(void *ctx, int timeout)
+{
+	struct tcp4_ctx *tctx = ctx;
+	int error, flags;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+	PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT);
+	PJDLOG_ASSERT(tctx->tc_fd >= 0);
+	PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+	PJDLOG_ASSERT(timeout >= -1);
+
+	flags = fcntl(tctx->tc_fd, F_GETFL);
+	if (flags == -1) {
+		KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno,
+		    "fcntl(F_GETFL) failed"));
+		return (errno);
+	}
+	/*
+	 * We make socket non-blocking so we can handle connection timeout
+	 * manually.
+	 */
+	flags |= O_NONBLOCK;
+	if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+		KEEP_ERRNO(pjdlog_common(LOG_DEBUG, 1, errno,
+		    "fcntl(F_SETFL, O_NONBLOCK) failed"));
+		return (errno);
+	}
+
+	if (connect(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+	    sizeof(tctx->tc_sin)) == 0) {
+		if (timeout == -1)
+			return (0);
+		error = 0;
+		goto done;
+	}
+	if (errno != EINPROGRESS) {
+		error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno, "connect() failed");
+		goto done;
+	}
+	if (timeout == -1)
+		return (0);
+	return (tcp4_connect_wait(ctx, timeout));
+done:
+	flags &= ~O_NONBLOCK;
+	if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+		if (error == 0)
+			error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno,
+		    "fcntl(F_SETFL, ~O_NONBLOCK) failed");
+	}
+	return (error);
+}
+
+static int
+tcp4_connect_wait(void *ctx, int timeout)
+{
+	struct tcp4_ctx *tctx = ctx;
+	struct timeval tv;
+	fd_set fdset;
+	socklen_t esize;
+	int error, flags, ret;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+	PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_CLIENT);
+	PJDLOG_ASSERT(tctx->tc_fd >= 0);
+	PJDLOG_ASSERT(timeout >= 0);
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+again:
+	FD_ZERO(&fdset);
+	FD_SET(tctx->tc_fd, &fdset);
+	ret = select(tctx->tc_fd + 1, NULL, &fdset, NULL, &tv);
+	if (ret == 0) {
+		error = ETIMEDOUT;
+		goto done;
+	} else if (ret == -1) {
+		if (errno == EINTR)
+			goto again;
+		error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno, "select() failed");
+		goto done;
+	}
+	PJDLOG_ASSERT(ret > 0);
+	PJDLOG_ASSERT(FD_ISSET(tctx->tc_fd, &fdset));
+	esize = sizeof(error);
+	if (getsockopt(tctx->tc_fd, SOL_SOCKET, SO_ERROR, &error,
+	    &esize) == -1) {
+		error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno,
+		    "getsockopt(SO_ERROR) failed");
+		goto done;
+	}
+	if (error != 0) {
+		pjdlog_common(LOG_DEBUG, 1, error,
+		    "getsockopt(SO_ERROR) returned error");
+		goto done;
+	}
+	error = 0;
+done:
+	flags = fcntl(tctx->tc_fd, F_GETFL);
+	if (flags == -1) {
+		if (error == 0)
+			error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno, "fcntl(F_GETFL) failed");
+		return (error);
+	}
+	flags &= ~O_NONBLOCK;
+	if (fcntl(tctx->tc_fd, F_SETFL, flags) == -1) {
+		if (error == 0)
+			error = errno;
+		pjdlog_common(LOG_DEBUG, 1, errno,
+		    "fcntl(F_SETFL, ~O_NONBLOCK) failed");
+	}
+	return (error);
+}
+
+static int
+tcp4_server(const char *addr, void **ctxp)
+{
+	struct tcp4_ctx *tctx;
+	int ret, val;
+
+	ret = tcp4_setup_new(addr, TCP4_SIDE_SERVER_LISTEN, ctxp);
+	if (ret != 0)
+		return (ret);
+
+	tctx = *ctxp;
+
+	val = 1;
+	/* Ignore failure. */
+	(void)setsockopt(tctx->tc_fd, SOL_SOCKET, SO_REUSEADDR, &val,
+	   sizeof(val));
+
+	PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+
+	if (bind(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+	    sizeof(tctx->tc_sin)) < 0) {
+		ret = errno;
+		tcp4_close(tctx);
+		return (ret);
+	}
+	if (listen(tctx->tc_fd, 8) < 0) {
+		ret = errno;
+		tcp4_close(tctx);
+		return (ret);
+	}
+
+	return (0);
+}
+
+static int
+tcp4_accept(void *ctx, void **newctxp)
+{
+	struct tcp4_ctx *tctx = ctx;
+	struct tcp4_ctx *newtctx;
+	socklen_t fromlen;
+	int ret;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+	PJDLOG_ASSERT(tctx->tc_side == TCP4_SIDE_SERVER_LISTEN);
+	PJDLOG_ASSERT(tctx->tc_fd >= 0);
+	PJDLOG_ASSERT(tctx->tc_sin.sin_family != AF_UNSPEC);
+
+	newtctx = malloc(sizeof(*newtctx));
+	if (newtctx == NULL)
+		return (errno);
+
+	fromlen = sizeof(tctx->tc_sin);
+	newtctx->tc_fd = accept(tctx->tc_fd, (struct sockaddr *)&tctx->tc_sin,
+	    &fromlen);
+	if (newtctx->tc_fd < 0) {
+		ret = errno;
+		free(newtctx);
+		return (ret);
+	}
+
+	newtctx->tc_side = TCP4_SIDE_SERVER_WORK;
+	newtctx->tc_magic = TCP4_CTX_MAGIC;
+	*newctxp = newtctx;
+
+	return (0);
+}
+
+static int
+tcp4_wrap(int fd, bool client, void **ctxp)
+{
+
+	return (tcp4_setup_wrap(fd,
+	    client ? TCP4_SIDE_CLIENT : TCP4_SIDE_SERVER_WORK, ctxp));
+}
+
+static int
+tcp4_send(void *ctx, const unsigned char *data, size_t size, int fd)
+{
+	struct tcp4_ctx *tctx = ctx;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+	PJDLOG_ASSERT(tctx->tc_fd >= 0);
+	PJDLOG_ASSERT(fd == -1);
+
+	return (proto_common_send(tctx->tc_fd, data, size, -1));
+}
+
+static int
+tcp4_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
+{
+	struct tcp4_ctx *tctx = ctx;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+	PJDLOG_ASSERT(tctx->tc_fd >= 0);
+	PJDLOG_ASSERT(fdp == NULL);
+
+	return (proto_common_recv(tctx->tc_fd, data, size, NULL));
+}
+
+static int
+tcp4_descriptor(const void *ctx)
+{
+	const struct tcp4_ctx *tctx = ctx;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+	return (tctx->tc_fd);
+}
+
+static bool
+tcp4_address_match(const void *ctx, const char *addr)
+{
+	const struct tcp4_ctx *tctx = ctx;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+	in_addr_t ip1, ip2;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+	if (tcp4_addr(addr, PROTO_TCP4_DEFAULT_PORT, &sin) != 0)
+		return (false);
+	ip1 = sin.sin_addr.s_addr;
+
+	sinlen = sizeof(sin);
+	if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0)
+		return (false);
+	ip2 = sin.sin_addr.s_addr;
+
+	return (ip1 == ip2);
+}
+
+static void
+tcp4_local_address(const void *ctx, char *addr, size_t size)
+{
+	const struct tcp4_ctx *tctx = ctx;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+	sinlen = sizeof(sin);
+	if (getsockname(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) {
+		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+		return;
+	}
+	PJDLOG_VERIFY(snprintf(addr, size, "tcp4://%S", &sin) < (ssize_t)size);
+}
+
+static void
+tcp4_remote_address(const void *ctx, char *addr, size_t size)
+{
+	const struct tcp4_ctx *tctx = ctx;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+	sinlen = sizeof(sin);
+	if (getpeername(tctx->tc_fd, (struct sockaddr *)&sin, &sinlen) < 0) {
+		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
+		return;
+	}
+	PJDLOG_VERIFY(snprintf(addr, size, "tcp4://%S", &sin) < (ssize_t)size);
+}
+
+static void
+tcp4_close(void *ctx)
+{
+	struct tcp4_ctx *tctx = ctx;
+
+	PJDLOG_ASSERT(tctx != NULL);
+	PJDLOG_ASSERT(tctx->tc_magic == TCP4_CTX_MAGIC);
+
+	if (tctx->tc_fd >= 0)
+		close(tctx->tc_fd);
+	tctx->tc_magic = 0;
+	free(tctx);
+}
+
+static struct proto tcp4_proto = {
+	.prt_name = "tcp4",
+	.prt_client = tcp4_client,
+	.prt_connect = tcp4_connect,
+	.prt_connect_wait = tcp4_connect_wait,
+	.prt_server = tcp4_server,
+	.prt_accept = tcp4_accept,
+	.prt_wrap = tcp4_wrap,
+	.prt_send = tcp4_send,
+	.prt_recv = tcp4_recv,
+	.prt_descriptor = tcp4_descriptor,
+	.prt_address_match = tcp4_address_match,
+	.prt_local_address = tcp4_local_address,
+	.prt_remote_address = tcp4_remote_address,
+	.prt_close = tcp4_close
+};
+
+static __constructor void
+tcp4_ctor(void)
+{
+
+	proto_register(&tcp4_proto, true);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105201106.p4KB6Ir4081224>