X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=libcfs%2Flibcfs%2Fuser-tcpip.c;h=4477f13f3281319e0bd5dc2a3e8f808de5ccd7cb;hb=ed5f9719db5b82e05fee4654b4d4fbbb104d178f;hp=a78dddeab6a363decf47d75f4e4db010467f3c41;hpb=6869932b552ac705f411de3362f01bd50c1f6f7d;p=fs%2Flustre-release.git diff --git a/libcfs/libcfs/user-tcpip.c b/libcfs/libcfs/user-tcpip.c index a78ddde..4477f13 100644 --- a/libcfs/libcfs/user-tcpip.c +++ b/libcfs/libcfs/user-tcpip.c @@ -1,6 +1,4 @@ -/* -*- 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. @@ -26,7 +24,7 @@ * 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. */ /* @@ -39,7 +37,7 @@ #include #include -#ifdef HAVE_NETINET_IN_H +#ifdef HAVE_NETINET_IN_H #include #endif #include @@ -238,93 +236,76 @@ libcfs_ipif_enumerate (char ***namesp) */ 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; @@ -335,21 +316,70 @@ libcfs_sock_read (int sock, void *buffer, int nob, int timeout) 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 @@ -359,112 +389,144 @@ libcfs_sock_read (int sock, void *buffer, int nob, int timeout) /* 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) { @@ -477,14 +539,15 @@ libcfs_sock_set_nagle(int fd, int nagle) } 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"); @@ -492,7 +555,8 @@ libcfs_sock_set_bufsiz(int fd, int bufsiz) } 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"); @@ -503,54 +567,75 @@ libcfs_sock_set_bufsiz(int fd, int bufsiz) } 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; @@ -559,8 +644,8 @@ libcfs_sock_connect(int fd, __u32 ip, __u16 port) 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) { @@ -577,16 +662,17 @@ libcfs_sock_connect(int fd, __u32 ip, __u16 port) /* 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 */ @@ -599,15 +685,16 @@ int libcfs_sock_writev(int fd, const struct iovec *vector, int count) 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;