]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - net.c
Merge commit 'remotes/fml/master'
[paraslash.git] / net.c
diff --git a/net.c b/net.c
index 3de57f281d7090c1bd5e4d8fbe9c01d8372548cd..076600fc45f2952212835339ac4e991ee0e5edc6 100644 (file)
--- a/net.c
+++ b/net.c
@@ -8,6 +8,18 @@
 
 #include <netdb.h>
 
+/* At least NetBSD needs these. */
+#ifndef AI_V4MAPPED
+#define AI_V4MAPPED 0
+#endif
+#ifndef AI_ALL
+#define AI_ALL 0
+#endif
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0
+#endif
+
+
 #include "para.h"
 #include "error.h"
 #include "net.h"
@@ -72,30 +84,6 @@ void disable_crypt(int fd)
 }
 
 
-/**
- * Initialize a struct sockaddr_in.
- *
- * \param addr A pointer to the struct to be initialized.
- * \param port The port number to use.
- * \param he The address to use.
- *
- * If \a he is null (server mode), \a addr->sin_addr is initialized with \p
- * INADDR_ANY.  Otherwise, the address given by \a he is copied to addr.
- */
-static void init_sockaddr(struct sockaddr_in *addr, int port, const struct hostent *he)
-{
-       /* host byte order */
-       addr->sin_family = AF_INET;
-       /* short, network byte order */
-       addr->sin_port = htons(port);
-       if (he)
-               addr->sin_addr = *((struct in_addr *)he->h_addr);
-       else
-               addr->sin_addr.s_addr = INADDR_ANY;
-       /* zero the rest of the struct */
-       memset(&addr->sin_zero, '\0', 8);
-}
-
 /**
  * Determine the socket type for a given layer-4 protocol.
  *
@@ -265,6 +253,63 @@ int para_listen(unsigned l3type, unsigned l4type, unsigned short port)
        return fd;
 }
 
+/**
+ * Print numeric host and port number (beware - uses static char).
+ * \param sa   The IPv4/IPv6 socket address to use.
+ * \param len  The length of \p sa.
+ *
+ * \sa getnameinfo(3)
+ */
+char *host_and_port(struct sockaddr *sa, socklen_t len)
+{
+       static char     output[NI_MAXHOST + NI_MAXSERV + 2];
+       char            hbuf[NI_MAXHOST],
+                       sbuf[NI_MAXSERV];
+       int             ret;
+
+       ret = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+                         NI_NUMERICHOST | NI_NUMERICSERV);
+       if (ret)        {
+               PARA_WARNING_LOG("hostname lookup error (%s).\n", gai_strerror(ret));
+               sprintf(output, "(unknown)");
+       } else {
+               sprintf(output, "%s#%s", hbuf, sbuf);
+       }
+       return output;
+}
+
+/**
+ * Look up the local or remote side of a connected socket structure.
+ * \param fd           The socket descriptor of the connected socket.
+ * \param getname      Either \fn getsockname() for local, or \fn getpeername() for remote side.
+ *
+ * \return A static character string identifying hostname and port of the chosen side
+ * \sa getsockname(2), getpeername(2)
+ */
+static char *__get_sock_name(int fd, int (*getname)(int, struct sockaddr*, socklen_t *))
+{
+       struct sockaddr_storage   ss;
+       socklen_t                 sslen = sizeof(ss);
+
+       if (getname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
+               static char *dont_know = "(don't know)";
+               PARA_ERROR_LOG("can not determine address from fd %d: %s\n", fd, strerror(errno));
+               return dont_know;
+       }
+
+       return host_and_port((struct sockaddr *)&ss, sslen);
+}
+
+char  *local_name(int sockfd)
+{
+       return __get_sock_name(sockfd, getsockname);
+}
+
+char *remote_name(int sockfd)
+{
+       return __get_sock_name(sockfd, getpeername);
+}
+
 /*
  * Send out a buffer, resend on short writes.
  *
@@ -424,58 +469,6 @@ int recv_buffer(int fd, char *buf, size_t size)
        return n;
 }
 
-/**
- * Establish a tcp connection.
- *
- * \param host Hostname or IPv4 address.
- * \param port The tcp port.
- *
- * \return Negative on errors, a valid file descriptor on success.
- */
-int tcp_connect(char *host, int port)
-{
-       struct sockaddr_in addr;
-       struct hostent *he;
-       int ret, fd;
-
-       PARA_INFO_LOG("getting host info of %s\n", host);
-       /* FIXME: gethostbyname() is obsolete */
-       he = gethostbyname(host);
-       if (!he)
-               return -ERRNO_TO_PARA_ERROR(h_errno);
-       init_sockaddr(&addr, port, he);
-       ret = get_stream_socket(AF_INET);
-       if (ret < 0)
-               return ret;
-       fd = ret;
-       ret = PARA_CONNECT(fd, &addr);
-       if (ret >= 0)
-               return fd;
-       close(fd);
-       return ret;
-}
-
-/**
- * A wrapper around socket(2).
- *
- * \param domain The communication domain that selects the protocol family.
- *
- * Create an IPv4 socket for sequenced, reliable, two-way, connection-based
- * byte streams.
- *
- * \return The socket fd on success, negative on errors.
- *
- * \sa socket(2).
- */
-int get_stream_socket(int domain)
-{
-       int fd = socket(domain, SOCK_STREAM, 0);
-
-       if (fd < 0)
-               return -ERRNO_TO_PARA_ERROR(errno);
-       return fd;
-}
-
 /**
  * Wrapper around the accept system call.
  *
@@ -510,7 +503,7 @@ int para_accept(int fd, void *addr, socklen_t size)
  * \return Positive on success, \p -E_NAME_TOO_LONG if \a name is longer
  * than \p UNIX_PATH_MAX.
  */
-int init_unix_addr(struct sockaddr_un *u, const char *name)
+static int init_unix_addr(struct sockaddr_un *u, const char *name)
 {
        if (strlen(name) >= UNIX_PATH_MAX)
                return -E_NAME_TOO_LONG;
@@ -527,7 +520,7 @@ int init_unix_addr(struct sockaddr_un *u, const char *name)
  * \param unix_addr Pointer to the \p AF_UNIX socket structure.
  * \param mode The desired mode of the socket.
  *
- * This functions creates a local socket for sequenced, reliable,
+ * This function creates a local socket for sequenced, reliable,
  * two-way, connection-based byte streams.
  *
  * \return The file descriptor, on success, negative on errors.
@@ -562,6 +555,39 @@ err:
        return ret;
 }
 
+/**
+ * Prepare, create, and connect to a Unix domain socket for local communication.
+ *
+ * \param name The socket pathname.
+ *
+ * This function creates a local socket for sequenced, reliable, two-way,
+ * connection-based byte streams.
+ *
+ * \return The file descriptor, on success, negative on errors.
+ *
+ * \sa create_local_socket(), unix(7), connect(2)
+ */
+int create_remote_socket(const char *name)
+{
+       struct sockaddr_un unix_addr;
+       int fd, ret;
+
+       ret = init_unix_addr(&unix_addr, name);
+       if (ret < 0)
+               return ret;
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0)
+               return -ERRNO_TO_PARA_ERROR(errno);
+       if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) == -1) {
+               ret = -ERRNO_TO_PARA_ERROR(errno);
+               goto err;
+       }
+       return fd;
+err:
+       close(fd);
+       return ret;
+}
+
 #ifndef HAVE_UCRED
 ssize_t send_cred_buffer(int sock, char *buf)
 {
@@ -679,50 +705,6 @@ int recv_cred_buffer(int fd, char *buf, size_t size)
 }
 #endif /* HAVE_UCRED */
 
-/**
- * Create a tcp socket, bind it and listen on the given port.
- *
- * \param port The tcp port to listen on.
- *
- * \return The file descriptor of the created socket, negative on errors.
- *
- * \sa get_stream_socket()
- * \sa setsockopt(2)
- * \sa bind(2)
- * \sa listen(2)
- */
-int tcp_listen(int port)
-{
-       struct sockaddr_in my_addr;
-       int fd, ret = get_stream_socket(AF_INET);
-
-       if (ret < 0)
-               return ret;
-       fd = ret;
-       ret = 1;
-       ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int));
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       init_sockaddr(&my_addr, port, NULL);
-       ret = bind(fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       ret = listen(fd, BACKLOG);
-       if (ret < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       PARA_INFO_LOG("listening on port %d, fd %d\n", port, fd);
-       return fd;
-err:
-       close(fd);
-       return ret;
-}
-
 /**
  * receive a buffer and check for a pattern
  *