-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
* GPL HEADER START
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see [sun.com URL with a
- * copy of GPLv2].
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*/
/*
#include <libcfs/libcfs.h>
#include <sys/socket.h>
-#ifdef HAVE_NETINET_IN_H
+#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <netinet/tcp.h>
*/
int
-libcfs_sock_listen (int *sockp, __u32 local_ip, int local_port, int backlog)
+libcfs_sock_listen (cfs_socket_t **sockp,
+ __u32 local_ip, int local_port, int backlog)
{
- int rc;
- int option;
- struct sockaddr_in locaddr;
-
- *sockp = socket(AF_INET, SOCK_STREAM, 0);
- if (*sockp < 0) {
- rc = -errno;
- CERROR("socket() failed: errno==%d\n", errno);
- return rc;
- }
-
- option = 1;
- if ( setsockopt(*sockp, SOL_SOCKET, SO_REUSEADDR,
- (char *)&option, sizeof (option)) ) {
- rc = -errno;
- CERROR("setsockopt(SO_REUSEADDR) failed: errno==%d\n", errno);
- goto failed;
- }
+ int rc;
+ int fatal;
- if (local_ip != 0 || local_port != 0) {
- memset(&locaddr, 0, sizeof(locaddr));
- locaddr.sin_family = AF_INET;
- locaddr.sin_port = htons(local_port);
- locaddr.sin_addr.s_addr = (local_ip == 0) ?
- INADDR_ANY : htonl(local_ip);
-
- if ( bind(*sockp, (struct sockaddr *)&locaddr, sizeof(locaddr)) ) {
- rc = -errno;
- if ( errno == -EADDRINUSE )
- CDEBUG(D_NET, "Port %d already in use\n",
- local_port);
- else
- CERROR("bind() to port %d failed: errno==%d\n",
- local_port, errno);
- goto failed;
- }
- }
+ rc = libcfs_sock_create(sockp, &fatal, local_ip, local_port);
+ if (rc != 0)
+ return rc;
- if ( listen(*sockp, backlog) ) {
+ if ( listen((*sockp)->s_fd, backlog) ) {
rc = -errno;
CERROR("listen() with backlog==%d failed: errno==%d\n",
backlog, errno);
goto failed;
}
-
+
return 0;
failed:
- close(*sockp);
+ libcfs_sock_release(*sockp);
return rc;
}
+void
+libcfs_sock_release (cfs_socket_t *sock)
+{
+ close(sock->s_fd);
+ LIBCFS_FREE(sock, sizeof(cfs_socket_t));
+}
+
int
-libcfs_sock_accept (int *newsockp, int sock, __u32 *peer_ip, int *peer_port)
+libcfs_sock_accept (cfs_socket_t **newsockp, cfs_socket_t *sock)
{
struct sockaddr_in accaddr;
- socklen_t accaddr_len = sizeof(struct sockaddr_in);
+ socklen_t accaddr_len = sizeof(struct sockaddr_in);
- *newsockp = accept(sock, (struct sockaddr *)&accaddr, &accaddr_len);
+ LIBCFS_ALLOC(*newsockp, sizeof(cfs_socket_t));
+ if (*newsockp == NULL) {
+ CERROR ("Can't alloc memory for cfs_socket_t\n");
+ return -ENOMEM;
+ }
- if ( *newsockp < 0 ) {
- CERROR("accept() failed: errno==%d\n", errno);
- return -errno;
+ (*newsockp)->s_fd = accept(sock->s_fd,
+ (struct sockaddr *)&accaddr, &accaddr_len);
+
+ if ( (*newsockp)->s_fd < 0 ) {
+ int rc = -errno;
+ CERROR("accept() failed: errno==%d\n", -rc);
+ LIBCFS_FREE(*newsockp, sizeof(cfs_socket_t));
+ return rc;
}
- *peer_ip = ntohl(accaddr.sin_addr.s_addr);
- *peer_port = ntohs(accaddr.sin_port);
-
return 0;
}
int
-libcfs_sock_read (int sock, void *buffer, int nob, int timeout)
+libcfs_sock_read (cfs_socket_t *sock, void *buffer, int nob, int timeout)
{
- int rc;
+ int rc;
struct pollfd pfd;
- cfs_time_t start_time = cfs_time_current();
+ cfs_time_t start_time = cfs_time_current();
- pfd.fd = sock;
+ pfd.fd = sock->s_fd;
pfd.events = POLLIN;
pfd.revents = 0;
/* poll(2) measures timeout in msec */
timeout *= 1000;
-
+
while (nob != 0 && timeout > 0) {
cfs_time_t current_time;
return -ETIMEDOUT;
if ((pfd.revents & POLLIN) == 0)
return -EIO;
-
- rc = read(sock, buffer, nob);
+
+ rc = read(sock->s_fd, buffer, nob);
if (rc < 0)
return -errno;
if (rc == 0)
return -EIO;
-
+
buffer = ((char *)buffer) + rc;
nob -= rc;
current_time = cfs_time_current();
- timeout -= cfs_duration_sec(cfs_time_sub(cfs_time_current(),
- start_time));
+ timeout -= 1000 *
+ cfs_duration_sec(cfs_time_sub(current_time,
+ start_time));
+ start_time = current_time;
}
-
+
+ if (nob == 0)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+int
+libcfs_sock_write (cfs_socket_t *sock, void *buffer, int nob, int timeout)
+{
+ int rc;
+ struct pollfd pfd;
+ cfs_time_t start_time = cfs_time_current();
+
+ pfd.fd = sock->s_fd;
+ pfd.events = POLLOUT;
+ pfd.revents = 0;
+
+ /* poll(2) measures timeout in msec */
+ timeout *= 1000;
+
+ while (nob != 0 && timeout > 0) {
+ cfs_time_t current_time;
+
+ rc = poll(&pfd, 1, timeout);
+ if (rc < 0)
+ return -errno;
+ if (rc == 0)
+ return -ETIMEDOUT;
+ if ((pfd.revents & POLLOUT) == 0)
+ return -EIO;
+
+ rc = write(sock->s_fd, buffer, nob);
+ if (rc < 0)
+ return -errno;
+ if (rc == 0)
+ return -EIO;
+
+ buffer = ((char *)buffer) + rc;
+ nob -= rc;
+
+ current_time = cfs_time_current();
+ timeout -= 1000 *
+ cfs_duration_sec(cfs_time_sub(current_time,
+ start_time));
+ start_time = current_time;
+ }
+
if (nob == 0)
return 0;
else
/* Just try to connect to localhost to wake up entity that are
* sleeping in accept() */
void
-libcfs_sock_abort_accept(__u16 port)
+libcfs_sock_abort_accept(cfs_socket_t *sock)
{
int fd, rc;
+ struct sockaddr_in remaddr;
struct sockaddr_in locaddr;
+ socklen_t alen = sizeof(struct sockaddr_in);
+
+ rc = getsockname(sock->s_fd, (struct sockaddr *)&remaddr, &alen);
+ if ( rc != 0 ) {
+ CERROR("getsockname() failed: errno==%d\n", errno);
+ return;
+ }
memset(&locaddr, 0, sizeof(locaddr));
locaddr.sin_family = AF_INET;
- locaddr.sin_port = htons(port);
+ locaddr.sin_port = remaddr.sin_port;
locaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
fd = socket(AF_INET, SOCK_STREAM, 0);
if ( fd < 0 ) {
CERROR("socket() failed: errno==%d\n", errno);
return;
- }
-
+ }
+
rc = connect(fd, (struct sockaddr *)&locaddr, sizeof(locaddr));
if ( rc != 0 ) {
if ( errno != ECONNREFUSED )
CERROR("connect() failed: errno==%d\n", errno);
else
- CDEBUG(D_NET, "Nobody to wake up at %d\n", port);
+ CDEBUG(D_NET, "Nobody to wake up at %d\n",
+ ntohs(remaddr.sin_port));
}
-
+
close(fd);
}
-/*
- * Network functions of common use
- */
-
int
-libcfs_getpeername(int sock_fd, __u32 *ipaddr_p, __u16 *port_p)
+libcfs_sock_getaddr(cfs_socket_t *sock, int remote, __u32 *ip, int *port)
{
int rc;
struct sockaddr_in peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
- rc = getpeername(sock_fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
+ LASSERT(remote == 1);
+
+ rc = getpeername(sock->s_fd,
+ (struct sockaddr *)&peer_addr, &peer_addr_len);
if (rc != 0)
return -errno;
-
- if (ipaddr_p != NULL)
- *ipaddr_p = ntohl(peer_addr.sin_addr.s_addr);
- if (port_p != NULL)
- *port_p = ntohs(peer_addr.sin_port);
- return 0;
+ if (ip != NULL)
+ *ip = ntohl(peer_addr.sin_addr.s_addr);
+ if (port != NULL)
+ *port = ntohs(peer_addr.sin_port);
+
+ return rc;
}
+/*
+ * Network functions of common use
+ */
+
int
-libcfs_socketpair(int *fdp)
+libcfs_socketpair(cfs_socket_t **sockp)
{
- int rc, i;
-
+ int rc, i, fdp[2];
+
+ LIBCFS_ALLOC(sockp[0], sizeof(cfs_socket_t));
+ if (sockp[0] == NULL) {
+ CERROR ("Can't alloc memory for cfs_socket_t (1)\n");
+ return -ENOMEM;
+ }
+
+ LIBCFS_ALLOC(sockp[1], sizeof(cfs_socket_t));
+ if (sockp[1] == NULL) {
+ CERROR ("Can't alloc memory for cfs_socket_t (2)\n");
+ LIBCFS_FREE(sockp[0], sizeof(cfs_socket_t));
+ return -ENOMEM;
+ }
+
rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fdp);
if (rc != 0) {
rc = -errno;
CERROR ("Cannot create socket pair\n");
+ LIBCFS_FREE(sockp[0], sizeof(cfs_socket_t));
+ LIBCFS_FREE(sockp[1], sizeof(cfs_socket_t));
return rc;
}
-
+
+ sockp[0]->s_fd = fdp[0];
+ sockp[1]->s_fd = fdp[1];
+
for (i = 0; i < 2; i++) {
- rc = libcfs_fcntl_nonblock(fdp[i]);
+ rc = libcfs_fcntl_nonblock(sockp[i]);
if (rc) {
- close(fdp[0]);
- close(fdp[1]);
+ libcfs_sock_release(sockp[0]);
+ libcfs_sock_release(sockp[1]);
return rc;
}
}
-
+
return 0;
}
int
-libcfs_fcntl_nonblock(int fd)
+libcfs_fcntl_nonblock(cfs_socket_t *sock)
{
int rc, flags;
-
- flags = fcntl(fd, F_GETFL, 0);
+
+ flags = fcntl(sock->s_fd, F_GETFL, 0);
if (flags == -1) {
rc = -errno;
CERROR ("Cannot get socket flags\n");
return rc;
}
-
- rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ rc = fcntl(sock->s_fd, F_SETFL, flags | O_NONBLOCK);
if (rc != 0) {
rc = -errno;
CERROR ("Cannot set socket flags\n");
return rc;
}
-
+
return 0;
}
int
-libcfs_sock_set_nagle(int fd, int nagle)
+libcfs_sock_set_nagle(cfs_socket_t *sock, int nagle)
{
int rc;
int option = nagle ? 0 : 1;
#if defined(__sun__) || defined(__sun)
- rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
+ rc = setsockopt(sock->s_fd,
+ IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
#else
- rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
+ rc = setsockopt(sock->s_fd,
+ SOL_TCP, TCP_NODELAY, &option, sizeof(option));
#endif
if (rc != 0) {
}
int
-libcfs_sock_set_bufsiz(int fd, int bufsiz)
+libcfs_sock_set_bufsiz(cfs_socket_t *sock, int bufsiz)
{
int rc, option;
-
+
LASSERT (bufsiz != 0);
option = bufsiz;
- rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &option, sizeof(option));
+ rc = setsockopt(sock->s_fd,
+ SOL_SOCKET, SO_SNDBUF, &option, sizeof(option));
if (rc != 0) {
rc = -errno;
CERROR ("Cannot set SNDBUF socket option\n");
}
option = bufsiz;
- rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &option, sizeof(option));
+ rc = setsockopt(sock->s_fd,
+ SOL_SOCKET, SO_RCVBUF, &option, sizeof(option));
if (rc != 0) {
rc = -errno;
CERROR ("Cannot set RCVBUF socket option\n");
}
int
-libcfs_sock_create(int *fdp)
+libcfs_sock_bind(cfs_socket_t *sock, __u32 ip, __u16 port)
{
- int rc, fd, option;
+ int rc;
+ struct sockaddr_in locaddr;
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd < 0) {
- rc = -errno;
- CERROR ("Cannot create socket\n");
- return rc;
- }
+ if (ip == 0 && port == 0)
+ return 0;
- option = 1;
- rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- &option, sizeof(option));
+ memset(&locaddr, 0, sizeof(locaddr));
+ locaddr.sin_family = AF_INET;
+ locaddr.sin_addr.s_addr = (ip == 0) ? INADDR_ANY : htonl(ip);
+ locaddr.sin_port = htons(port);
+
+ rc = bind(sock->s_fd, (struct sockaddr *)&locaddr, sizeof(locaddr));
if (rc != 0) {
rc = -errno;
- CERROR ("Cannot set SO_REUSEADDR for socket\n");
- close(fd);
+ CERROR("Cannot bind to %d.%d.%d.%d %d: %d\n",
+ HIPQUAD(ip), port, rc);
return rc;
- }
-
- *fdp = fd;
+ }
+
return 0;
}
int
-libcfs_sock_bind_to_port(int fd, __u16 port)
+libcfs_sock_create(cfs_socket_t **sockp, int *fatal,
+ __u32 local_ip, int local_port)
{
- int rc;
- struct sockaddr_in locaddr;
+ int rc, fd, option;
- memset(&locaddr, 0, sizeof(locaddr));
- locaddr.sin_family = AF_INET;
- locaddr.sin_addr.s_addr = INADDR_ANY;
- locaddr.sin_port = htons(port);
+ *fatal = 1;
+
+ LIBCFS_ALLOC(*sockp, sizeof(cfs_socket_t));
+ if (*sockp == NULL) {
+ CERROR("Can't alloc memory for cfs_socket_t\n");
+ return -ENOMEM;
+ }
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ rc = -errno;
+ CERROR("Cannot create socket: %d\n", rc);
+ LIBCFS_FREE(*sockp, sizeof(cfs_socket_t));
+ return rc;
+ }
+
+ (*sockp)->s_fd = fd;
- rc = bind(fd, (struct sockaddr *)&locaddr, sizeof(locaddr));
+ option = 1;
+ rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ &option, sizeof(option));
if (rc != 0) {
rc = -errno;
- CERROR ("Cannot bind to port %d\n", port);
+ CERROR("Cannot set SO_REUSEADDR for socket: %d\n", rc);
+ libcfs_sock_release(*sockp);
return rc;
}
- return 0;
+ rc = libcfs_sock_bind(*sockp, local_ip, local_port);
+ if (rc != 0) {
+ *fatal = 0;
+ libcfs_sock_release(*sockp);
+ }
+
+ return rc;
}
int
-libcfs_sock_connect(int fd, __u32 ip, __u16 port)
+libcfs_sock_connect(cfs_socket_t *sock, __u32 ip, __u16 port)
{
int rc;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(ip);
addr.sin_port = htons(port);
-
- rc = connect(fd, (struct sockaddr *)&addr,
+
+ rc = connect(sock->s_fd, (struct sockaddr *)&addr,
sizeof(struct sockaddr_in));
if(rc != 0 && errno != EINPROGRESS) {
/* NB: EPIPE and ECONNRESET are considered as non-fatal
* because:
* 1) it still makes sense to continue reading &&
- * 2) anyway, poll() will set up POLLHUP|POLLERR flags */
-int libcfs_sock_writev(int fd, const struct iovec *vector, int count)
+ * 2) anyway, poll() will set up POLLHUP|POLLERR flags */
+int
+libcfs_sock_writev(cfs_socket_t *sock, const struct iovec *vector, int count)
{
int rc;
-
- rc = syscall(SYS_writev, fd, vector, count);
-
- if (rc == 0) /* write nothing */
+
+ rc = syscall(SYS_writev, sock->s_fd, vector, count);
+
+ if (rc == 0) /* write nothing */
return 0;
-
+
if (rc < 0) {
if (errno == EAGAIN || /* write nothing */
errno == EPIPE || /* non-fatal error */
return rc;
}
-int libcfs_sock_readv(int fd, const struct iovec *vector, int count)
+int
+libcfs_sock_readv(cfs_socket_t *sock, const struct iovec *vector, int count)
{
int rc;
-
- rc = syscall(SYS_readv, fd, vector, count);
-
- if (rc == 0) /* EOF */
+
+ rc = syscall(SYS_readv, sock->s_fd, vector, count);
+
+ if (rc == 0) /* EOF */
return -EIO;
-
+
if (rc < 0) {
if (errno == EAGAIN) /* read nothing */
return 0;