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);
+}
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to