}
-/**
- * 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.
*
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.
*
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.
*
* \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;
* \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.
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)
{
}
#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
*