diff options
| author | Vijay Bellur <vijay@gluster.com> | 2010-06-28 02:49:46 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2010-06-28 22:20:45 -0700 | 
| commit | 0da2a6d08cc8fc2315742d010c8a8cab38ef75bb (patch) | |
| tree | eed93284ad3826ac7401c9f9540b6afe9a68c2cc /rpc/rpc-transport | |
| parent | 2c5c3cedc096c36ef9d004ffa0cdb5324d2915e6 (diff) | |
Move rpc to top-level
Signed-off-by: Vijay Bellur <vijay@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 875 (Implement a new protocol to provide proper backward/forward compatibility)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=875
Diffstat (limited to 'rpc/rpc-transport')
| -rw-r--r-- | rpc/rpc-transport/Makefile.am | 1 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/Makefile.am | 1 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/src/Makefile.am | 15 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/src/name.c | 737 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/src/name.h | 44 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/src/socket.c | 2308 | ||||
| -rw-r--r-- | rpc/rpc-transport/socket/src/socket.h | 190 | 
7 files changed, 3296 insertions, 0 deletions
diff --git a/rpc/rpc-transport/Makefile.am b/rpc/rpc-transport/Makefile.am new file mode 100644 index 00000000000..7dd9f026cfc --- /dev/null +++ b/rpc/rpc-transport/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = socket diff --git a/rpc/rpc-transport/socket/Makefile.am b/rpc/rpc-transport/socket/Makefile.am new file mode 100644 index 00000000000..f963effea22 --- /dev/null +++ b/rpc/rpc-transport/socket/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src
\ No newline at end of file diff --git a/rpc/rpc-transport/socket/src/Makefile.am b/rpc/rpc-transport/socket/src/Makefile.am new file mode 100644 index 00000000000..46a3e12378b --- /dev/null +++ b/rpc/rpc-transport/socket/src/Makefile.am @@ -0,0 +1,15 @@ +noinst_HEADERS = socket.h name.h + +rpctransport_LTLIBRARIES = socket.la +rpctransportdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport + +socket_la_LDFLAGS = -module -avoidversion + +socket_la_SOURCES = socket.c name.c +socket_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ +	-I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src/ \ +	-I$(top_srcdir)/xlators/protocol/lib/src/ -shared -nostartfiles $(GF_CFLAGS) + +CLEANFILES = *~ diff --git a/rpc/rpc-transport/socket/src/name.c b/rpc/rpc-transport/socket/src/name.c new file mode 100644 index 00000000000..763fa3dd09b --- /dev/null +++ b/rpc/rpc-transport/socket/src/name.c @@ -0,0 +1,737 @@ +/* +  Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <errno.h> +#include <netdb.h> +#include <string.h> + +#ifdef CLIENT_PORT_CEILING +#undef CLIENT_PORT_CEILING +#endif + +#define CLIENT_PORT_CEILING 1024 + +#ifndef AF_INET_SDP +#define AF_INET_SDP 27 +#endif + +#include "rpc-transport.h" +#include "socket.h" + +int32_t +gf_resolve_ip6 (const char *hostname, +                uint16_t port, +                int family, +                void **dnscache, +                struct addrinfo **addr_info); + +static int32_t +af_inet_bind_to_port_lt_ceiling (int fd, struct sockaddr *sockaddr, +                                 socklen_t sockaddr_len, int ceiling) +{ +        int32_t ret = -1; +        /*  struct sockaddr_in sin = {0, }; */ +        uint16_t port = ceiling - 1; + +        while (port) +        { +                switch (sockaddr->sa_family) +                { +                case AF_INET6: +                        ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons (port); +                        break; + +                case AF_INET_SDP: +                case AF_INET: +                        ((struct sockaddr_in *)sockaddr)->sin_port = htons (port); +                        break; +                } + +                ret = bind (fd, sockaddr, sockaddr_len); + +                if (ret == 0) +                        break; + +                if (ret == -1 && errno == EACCES) +                        break; + +                port--; +        } + +        return ret; +} + +static int32_t +af_unix_client_bind (rpc_transport_t *this, +                     struct sockaddr *sockaddr, +                     socklen_t sockaddr_len, +                     int sock) +{ +        data_t *path_data = NULL; +        struct sockaddr_un *addr = NULL; +        int32_t ret = 0; + +        path_data = dict_get (this->options, "transport.socket.bind-path"); +        if (path_data) { +                char *path = data_to_str (path_data); +                if (!path || strlen (path) > UNIX_PATH_MAX) { +                        gf_log (this->name, GF_LOG_TRACE, +                                "bind-path not specfied for unix socket, " +                                "letting connect to assign default value"); +                        goto err; +                } + +                addr = (struct sockaddr_un *) sockaddr; +                strcpy (addr->sun_path, path); +                ret = bind (sock, (struct sockaddr *)addr, sockaddr_len); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "cannot bind to unix-domain socket %d (%s)", +                                sock, strerror (errno)); +                        goto err; +                } +        } else { +                gf_log (this->name, GF_LOG_TRACE, +                        "bind-path not specfied for unix socket, " +                        "letting connect to assign default value"); +        } + +err: +        return ret; +} + +int32_t +client_fill_address_family (rpc_transport_t *this, sa_family_t *sa_family) +{ +        data_t  *address_family_data = NULL; +        int32_t  ret                 = -1; + +        if (sa_family == NULL) { +                goto out; +        } + +        address_family_data = dict_get (this->options, +                                        "transport.address-family"); +        if (!address_family_data) { +                data_t *remote_host_data = NULL, *connect_path_data = NULL; +                remote_host_data = dict_get (this->options, "remote-host"); +                connect_path_data = dict_get (this->options, +                                              "transport.socket.connect-path"); + +                if (!(remote_host_data || connect_path_data) || +                    (remote_host_data && connect_path_data)) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "transport.address-family not specified and " +                                "not able to determine the " +                                "same from other options (remote-host:%s and " +                                "transport.unix.connect-path:%s)", +                                data_to_str (remote_host_data), +                                data_to_str (connect_path_data)); +                        goto out; +                } + +                if (remote_host_data) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "address-family not specified, guessing it " +                                "to be inet/inet6"); +                        *sa_family = AF_UNSPEC; +                } else { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "address-family not specified, guessing it " +                                "to be unix"); +                        *sa_family = AF_UNIX; +                } + +        } else { +                char *address_family = data_to_str (address_family_data); +                if (!strcasecmp (address_family, "unix")) { +                        *sa_family = AF_UNIX; +                } else if (!strcasecmp (address_family, "inet")) { +                        *sa_family = AF_INET; +                } else if (!strcasecmp (address_family, "inet6")) { +                        *sa_family = AF_INET6; +                } else if (!strcasecmp (address_family, "inet-sdp")) { +                        *sa_family = AF_INET_SDP; +                } else if (!strcasecmp (address_family, "inet/inet6") +                           || !strcasecmp (address_family, "inet6/inet")) { +                        *sa_family = AF_UNSPEC; +                } else { +                        gf_log (this->name, GF_LOG_ERROR, +                                "unknown address-family (%s) specified", +                                address_family); +                        goto out; +                } +        } + +        ret = 0; + +out: +        return ret; +} + +static int32_t +af_inet_client_get_remote_sockaddr (rpc_transport_t *this, +                                    struct sockaddr *sockaddr, +                                    socklen_t *sockaddr_len) +{ +        dict_t *options = this->options; +        data_t *remote_host_data = NULL; +        data_t *remote_port_data = NULL; +        char *remote_host = NULL; +        uint16_t remote_port = 0; +        struct addrinfo *addr_info = NULL; +        int32_t ret = 0; + +        remote_host_data = dict_get (options, "remote-host"); +        if (remote_host_data == NULL) +        { +                gf_log (this->name, GF_LOG_ERROR, +                        "option remote-host missing in volume %s", this->name); +                ret = -1; +                goto err; +        } + +        remote_host = data_to_str (remote_host_data); +        if (remote_host == NULL) +        { +                gf_log (this->name, GF_LOG_ERROR, +                        "option remote-host has data NULL in volume %s", this->name); +                ret = -1; +                goto err; +        } + +        remote_port_data = dict_get (options, "remote-port"); +        if (remote_port_data == NULL) +        { +                gf_log (this->name, GF_LOG_TRACE, +                        "option remote-port missing in volume %s. Defaulting to %d", +                        this->name, GF_DEFAULT_SOCKET_LISTEN_PORT); + +                remote_port = GF_DEFAULT_SOCKET_LISTEN_PORT; +        } +        else +        { +                remote_port = data_to_uint16 (remote_port_data); +        } + +        if (remote_port == (uint16_t)-1) +        { +                gf_log (this->name, GF_LOG_ERROR, +                        "option remote-port has invalid port in volume %s", +                        this->name); +                ret = -1; +                goto err; +        } + +        /* TODO: gf_resolve is a blocking call. kick in some +           non blocking dns techniques */ +        ret = gf_resolve_ip6 (remote_host, remote_port, +                              sockaddr->sa_family, &this->dnscache, &addr_info); +        if (ret == -1) { +                gf_log (this->name, GF_LOG_ERROR, +                        "DNS resolution failed on host %s", remote_host); +                goto err; +        } + +        memcpy (sockaddr, addr_info->ai_addr, addr_info->ai_addrlen); +        *sockaddr_len = addr_info->ai_addrlen; + +err: +        return ret; +} + +static int32_t +af_unix_client_get_remote_sockaddr (rpc_transport_t *this, +                                    struct sockaddr *sockaddr, +                                    socklen_t *sockaddr_len) +{ +        struct sockaddr_un *sockaddr_un = NULL; +        char *connect_path = NULL; +        data_t *connect_path_data = NULL; +        int32_t ret = 0; + +        connect_path_data = dict_get (this->options, +                                      "transport.socket.connect-path"); +        if (!connect_path_data) { +                gf_log (this->name, GF_LOG_ERROR, +                        "option transport.unix.connect-path not specified for " +                        "address-family unix"); +                ret = -1; +                goto err; +        } + +        connect_path = data_to_str (connect_path_data); +        if (!connect_path) { +                gf_log (this->name, GF_LOG_ERROR, +                        "transport.unix.connect-path is null-string"); +                ret = -1; +                goto err; +        } + +        if (strlen (connect_path) > UNIX_PATH_MAX) { +                gf_log (this->name, GF_LOG_ERROR, +                        "connect-path value length %"GF_PRI_SIZET" > %d octets", +                        strlen (connect_path), UNIX_PATH_MAX); +                ret = -1; +                goto err; +        } + +        gf_log (this->name, GF_LOG_TRACE, +                "using connect-path %s", connect_path); +        sockaddr_un = (struct sockaddr_un *)sockaddr; +        strcpy (sockaddr_un->sun_path, connect_path); +        *sockaddr_len = sizeof (struct sockaddr_un); + +err: +        return ret; +} + +static int32_t +af_unix_server_get_local_sockaddr (rpc_transport_t *this, +                                   struct sockaddr *addr, +                                   socklen_t *addr_len) +{ +        data_t *listen_path_data = NULL; +        char *listen_path = NULL; +        int32_t ret = 0; +        struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr; + + +        listen_path_data = dict_get (this->options, +                                     "transport.socket.listen-path"); +        if (!listen_path_data) { +                gf_log (this->name, GF_LOG_ERROR, +                        "missing option transport.socket.listen-path"); +                ret = -1; +                goto err; +        } + +        listen_path = data_to_str (listen_path_data); + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +        if (strlen (listen_path) > UNIX_PATH_MAX) { +                gf_log (this->name, GF_LOG_ERROR, +                        "option transport.unix.listen-path has value length " +                        "%"GF_PRI_SIZET" > %d", +                        strlen (listen_path), UNIX_PATH_MAX); +                ret = -1; +                goto err; +        } + +        sunaddr->sun_family = AF_UNIX; +        strcpy (sunaddr->sun_path, listen_path); +        *addr_len = sizeof (struct sockaddr_un); + +err: +        return ret; +} + +static int32_t +af_inet_server_get_local_sockaddr (rpc_transport_t *this, +                                   struct sockaddr *addr, +                                   socklen_t *addr_len) +{ +        struct addrinfo hints, *res = 0; +        data_t *listen_port_data = NULL, *listen_host_data = NULL; +        uint16_t listen_port = -1; +        char service[NI_MAXSERV], *listen_host = NULL; +        dict_t *options = NULL; +        int32_t ret = 0; + +        options = this->options; + +        listen_port_data = dict_get (options, "transport.socket.listen-port"); +        listen_host_data = dict_get (options, "transport.socket.bind-address"); + +        if (listen_port_data) +        { +                listen_port = data_to_uint16 (listen_port_data); +        } + +        if (listen_port == (uint16_t) -1) +                listen_port = GF_DEFAULT_SOCKET_LISTEN_PORT; + + +        if (listen_host_data) +        { +                listen_host = data_to_str (listen_host_data); +        } else { +		if (addr->sa_family == AF_INET6) { +			struct sockaddr_in6 *in = (struct sockaddr_in6 *) addr; +			in->sin6_addr = in6addr_any; +			in->sin6_port = htons(listen_port); +			*addr_len = sizeof(struct sockaddr_in6); +                        goto out; +		} else if (addr->sa_family == AF_INET) { +			struct sockaddr_in *in = (struct sockaddr_in *) addr; +			in->sin_addr.s_addr = htonl(INADDR_ANY); +			in->sin_port = htons(listen_port); +			*addr_len = sizeof(struct sockaddr_in); +			goto out; +		} +	} + +        memset (service, 0, sizeof (service)); +        sprintf (service, "%d", listen_port); + +        memset (&hints, 0, sizeof (hints)); +        hints.ai_family = addr->sa_family; +        hints.ai_socktype = SOCK_STREAM; +        hints.ai_flags    = AI_ADDRCONFIG | AI_PASSIVE; + +        ret = getaddrinfo(listen_host, service, &hints, &res); +        if (ret != 0) { +                gf_log (this->name, GF_LOG_ERROR, +                        "getaddrinfo failed for host %s, service %s (%s)", +                        listen_host, service, gai_strerror (ret)); +                ret = -1; +                goto out; +        } + +        memcpy (addr, res->ai_addr, res->ai_addrlen); +        *addr_len = res->ai_addrlen; + +        freeaddrinfo (res); + +out: +        return ret; +} + +int32_t +client_bind (rpc_transport_t *this, +             struct sockaddr *sockaddr, +             socklen_t *sockaddr_len, +             int sock) +{ +        int ret = 0; + +        *sockaddr_len = sizeof (struct sockaddr_in6); +        switch (sockaddr->sa_family) +        { +        case AF_INET_SDP: +        case AF_INET: +                *sockaddr_len = sizeof (struct sockaddr_in); + +        case AF_INET6: +                ret = af_inet_bind_to_port_lt_ceiling (sock, sockaddr, +                                                       *sockaddr_len, CLIENT_PORT_CEILING); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_WARNING, +                                "cannot bind inet socket (%d) to port less than %d (%s)", +                                sock, CLIENT_PORT_CEILING, strerror (errno)); +                        ret = 0; +                } +                break; + +        case AF_UNIX: +                *sockaddr_len = sizeof (struct sockaddr_un); +                ret = af_unix_client_bind (this, (struct sockaddr *)sockaddr, +                                           *sockaddr_len, sock); +                break; + +        default: +                gf_log (this->name, GF_LOG_ERROR, +                        "unknown address family %d", sockaddr->sa_family); +                ret = -1; +                break; +        } + +        return ret; +} + +int32_t +socket_client_get_remote_sockaddr (rpc_transport_t *this, +                                   struct sockaddr *sockaddr, +                                   socklen_t *sockaddr_len, +                                   sa_family_t *sa_family) +{ +        int32_t ret = 0; + +        if ((sockaddr == NULL) || (sockaddr_len == NULL) +            || (sa_family == NULL)) { +                ret = -1; +                goto err; +        } + + +        ret = client_fill_address_family (this, &sockaddr->sa_family); +        if (ret) { +                ret = -1; +                goto err; +        } + +        *sa_family = sockaddr->sa_family; + +        switch (sockaddr->sa_family) +        { +        case AF_INET_SDP: +                sockaddr->sa_family = AF_INET; + +        case AF_INET: +        case AF_INET6: +        case AF_UNSPEC: +                ret = af_inet_client_get_remote_sockaddr (this, sockaddr, +                                                          sockaddr_len); +                break; + +        case AF_UNIX: +                ret = af_unix_client_get_remote_sockaddr (this, sockaddr, +                                                          sockaddr_len); +                break; + +        default: +                gf_log (this->name, GF_LOG_ERROR, +                        "unknown address-family %d", sockaddr->sa_family); +                ret = -1; +        } + +        if (*sa_family == AF_UNSPEC) { +                *sa_family = sockaddr->sa_family; +        } + +err: +        return ret; +} + + +int32_t +server_fill_address_family (rpc_transport_t *this, sa_family_t *sa_family) +{ +        data_t  *address_family_data = NULL; +        int32_t  ret                 = -1; + +        if (sa_family == NULL) { +                goto out; +        } + +        address_family_data = dict_get (this->options, +                                        "transport.address-family"); +        if (address_family_data) { +                char *address_family = NULL; +                address_family = data_to_str (address_family_data); + +                if (!strcasecmp (address_family, "inet")) { +                        *sa_family = AF_INET; +                } else if (!strcasecmp (address_family, "inet6")) { +                        *sa_family = AF_INET6; +                } else if (!strcasecmp (address_family, "inet-sdp")) { +                        *sa_family = AF_INET_SDP; +                } else if (!strcasecmp (address_family, "unix")) { +                        *sa_family = AF_UNIX; +                } else if (!strcasecmp (address_family, "inet/inet6") +                           || !strcasecmp (address_family, "inet6/inet")) { +                        *sa_family = AF_UNSPEC; +                } else { +                        gf_log (this->name, GF_LOG_ERROR, +                                "unknown address family (%s) specified", address_family); +                        goto out; +                } +        } else { +                gf_log (this->name, GF_LOG_DEBUG, +                        "option address-family not specified, defaulting to inet/inet6"); +                *sa_family = AF_UNSPEC; +        } + +        ret = 0; +out: +        return ret; +} + + +int32_t +socket_server_get_local_sockaddr (rpc_transport_t *this, struct sockaddr *addr, +                                  socklen_t *addr_len, sa_family_t *sa_family) +{ +        int32_t ret = -1; + +        if ((addr == NULL) || (addr_len == NULL) || (sa_family == NULL)) { +                goto err; +        } + +        ret = server_fill_address_family (this, &addr->sa_family); +        if (ret == -1) { +                goto err; +        } + +        *sa_family = addr->sa_family; + +        switch (addr->sa_family) +        { +        case AF_INET_SDP: +                addr->sa_family = AF_INET; + +        case AF_INET: +        case AF_INET6: +        case AF_UNSPEC: +                ret = af_inet_server_get_local_sockaddr (this, addr, addr_len); +                break; + +        case AF_UNIX: +                ret = af_unix_server_get_local_sockaddr (this, addr, addr_len); +                break; +        } + +        if (*sa_family == AF_UNSPEC) { +                *sa_family = addr->sa_family; +        } + +err: +        return ret; +} + +int32_t +fill_inet6_inet_identifiers (rpc_transport_t *this, struct sockaddr_storage *addr, +                             int32_t addr_len, char *identifier) +{ +        int32_t ret = 0, tmpaddr_len = 0; +        char service[NI_MAXSERV], host[NI_MAXHOST]; +        struct sockaddr_storage tmpaddr; + +        memset (&tmpaddr, 0, sizeof (tmpaddr)); +        tmpaddr = *addr; +        tmpaddr_len = addr_len; + +        if (((struct sockaddr *) &tmpaddr)->sa_family == AF_INET6) { +                int32_t one_to_four, four_to_eight, twelve_to_sixteen; +                int16_t eight_to_ten, ten_to_twelve; + +                one_to_four = four_to_eight = twelve_to_sixteen = 0; +                eight_to_ten = ten_to_twelve = 0; + +                one_to_four = ((struct sockaddr_in6 *) &tmpaddr)->sin6_addr.s6_addr32[0]; +                four_to_eight = ((struct sockaddr_in6 *) &tmpaddr)->sin6_addr.s6_addr32[1]; +#ifdef GF_SOLARIS_HOST_OS +                eight_to_ten = S6_ADDR16(((struct sockaddr_in6 *) &tmpaddr)->sin6_addr)[4]; +#else +                eight_to_ten = ((struct sockaddr_in6 *) &tmpaddr)->sin6_addr.s6_addr16[4]; +#endif + +#ifdef GF_SOLARIS_HOST_OS +                ten_to_twelve = S6_ADDR16(((struct sockaddr_in6 *) &tmpaddr)->sin6_addr)[5]; +#else +                ten_to_twelve = ((struct sockaddr_in6 *) &tmpaddr)->sin6_addr.s6_addr16[5]; +#endif + +                twelve_to_sixteen = ((struct sockaddr_in6 *) &tmpaddr)->sin6_addr.s6_addr32[3]; + +                /* ipv4 mapped ipv6 address has +                   bits 0-80: 0 +                   bits 80-96: 0xffff +                   bits 96-128: ipv4 address +                */ + +                if (one_to_four == 0 && +                    four_to_eight == 0 && +                    eight_to_ten == 0 && +                    ten_to_twelve == -1) { +                        struct sockaddr_in *in_ptr = (struct sockaddr_in *)&tmpaddr; +                        memset (&tmpaddr, 0, sizeof (tmpaddr)); + +                        in_ptr->sin_family = AF_INET; +                        in_ptr->sin_port = ((struct sockaddr_in6 *)addr)->sin6_port; +                        in_ptr->sin_addr.s_addr = twelve_to_sixteen; +                        tmpaddr_len = sizeof (*in_ptr); +                } +        } + +        ret = getnameinfo ((struct sockaddr *) &tmpaddr, +                           tmpaddr_len, +                           host, sizeof (host), +                           service, sizeof (service), +                           NI_NUMERICHOST | NI_NUMERICSERV); +        if (ret != 0) { +                gf_log (this->name, GF_LOG_ERROR, +                        "getnameinfo failed (%s)", gai_strerror (ret)); +        } + +        sprintf (identifier, "%s:%s", host, service); + +        return ret; +} + +int32_t +get_transport_identifiers (rpc_transport_t *this) +{ +        int32_t ret = 0; +        char is_inet_sdp = 0; + +        switch (((struct sockaddr *) &this->myinfo.sockaddr)->sa_family) +        { +        case AF_INET_SDP: +                is_inet_sdp = 1; +                ((struct sockaddr *) &this->peerinfo.sockaddr)->sa_family = ((struct sockaddr *) &this->myinfo.sockaddr)->sa_family = AF_INET; + +        case AF_INET: +        case AF_INET6: +        { +                ret = fill_inet6_inet_identifiers (this, +                                                   &this->myinfo.sockaddr, +                                                   this->myinfo.sockaddr_len, +                                                   this->myinfo.identifier); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "cannot fill inet/inet6 identifier for server"); +                        goto err; +                } + +                ret = fill_inet6_inet_identifiers (this, +                                                   &this->peerinfo.sockaddr, +                                                   this->peerinfo.sockaddr_len, +                                                   this->peerinfo.identifier); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "cannot fill inet/inet6 identifier for client"); +                        goto err; +                } + +                if (is_inet_sdp) { +                        ((struct sockaddr *) &this->peerinfo.sockaddr)->sa_family = ((struct sockaddr *) &this->myinfo.sockaddr)->sa_family = AF_INET_SDP; +                } +        } +        break; + +        case AF_UNIX: +        { +                struct sockaddr_un *sunaddr = NULL; + +                sunaddr = (struct sockaddr_un *) &this->myinfo.sockaddr; +                strcpy (this->myinfo.identifier, sunaddr->sun_path); + +                sunaddr = (struct sockaddr_un *) &this->peerinfo.sockaddr; +                strcpy (this->peerinfo.identifier, sunaddr->sun_path); +        } +        break; + +        default: +                gf_log (this->name, GF_LOG_ERROR, +                        "unknown address family (%d)", +                        ((struct sockaddr *) &this->myinfo.sockaddr)->sa_family); +                ret = -1; +                break; +        } + +err: +        return ret; +} diff --git a/rpc/rpc-transport/socket/src/name.h b/rpc/rpc-transport/socket/src/name.h new file mode 100644 index 00000000000..6a89d383b65 --- /dev/null +++ b/rpc/rpc-transport/socket/src/name.h @@ -0,0 +1,44 @@ +/* +  Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SOCKET_NAME_H +#define _SOCKET_NAME_H + +#include "compat.h" + +int32_t +client_bind (rpc_transport_t *this, +             struct sockaddr *sockaddr, +             socklen_t *sockaddr_len, +             int sock); + +int32_t +socket_client_get_remote_sockaddr (rpc_transport_t *this, +                                   struct sockaddr *sockaddr, +                                   socklen_t *sockaddr_len, +                                   sa_family_t *sa_family); + +int32_t +socket_server_get_local_sockaddr (rpc_transport_t *this, struct sockaddr *addr, +                                  socklen_t *addr_len, sa_family_t *sa_family); + +int32_t +get_transport_identifiers (rpc_transport_t *this); + +#endif /* _SOCKET_NAME_H */ diff --git a/rpc/rpc-transport/socket/src/socket.c b/rpc/rpc-transport/socket/src/socket.c new file mode 100644 index 00000000000..4ca7121e8af --- /dev/null +++ b/rpc/rpc-transport/socket/src/socket.c @@ -0,0 +1,2308 @@ +/* +  Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "socket.h" +#include "name.h" +#include "dict.h" +#include "rpc-transport.h" +#include "logging.h" +#include "xlator.h" +#include "byte-order.h" +#include "common-utils.h" +#include "compat-errno.h" +#include "protocol-common.h" + +#include "glusterfs-xdr.h" +#include <fcntl.h> +#include <errno.h> +#include <netinet/tcp.h> + +#define GF_LOG_ERRNO(errno) ((errno == ENOTCONN) ? GF_LOG_DEBUG : GF_LOG_ERROR) +#define SA(ptr) ((struct sockaddr *)ptr) + +#define __socket_proto_reset_pending(priv) do {                                \ +                                memset (&priv->incoming.frag.vector, 0,        \ +                                        sizeof (priv->incoming.frag.vector));  \ +                                priv->incoming.frag.pending_vector =           \ +                                        &priv->incoming.frag.vector;           \ +                                priv->incoming.frag.pending_vector->iov_base = \ +                                        priv->incoming.frag.fragcurrent;       \ +                                priv->incoming.pending_vector =                \ +                                        priv->incoming.frag.pending_vector;    \ +        } while (0); + + +#define __socket_proto_update_pending(priv)                                   \ +        do {                                                                  \ +                uint32_t remaining_fragsize = 0;                              \ +                if (priv->incoming.frag.pending_vector->iov_len == 0) {       \ +                        remaining_fragsize = RPC_FRAGSIZE (priv->incoming.fraghdr) \ +                                - priv->incoming.frag.bytes_read;             \ +                                                                              \ +                        priv->incoming.frag.pending_vector->iov_len =         \ +                                remaining_fragsize > priv->incoming.frag.remaining_size \ +                                ? priv->incoming.frag.remaining_size : remaining_fragsize; \ +                                                                              \ +                        priv->incoming.frag.remaining_size -=                 \ +                                priv->incoming.frag.pending_vector->iov_len;  \ +                }                                                             \ +        } while (0); + +#define __socket_proto_update_priv_after_read(priv, ret, bytes_read)          \ +        {                                                                     \ +                priv->incoming.frag.fragcurrent += bytes_read;                \ +                priv->incoming.frag.bytes_read += bytes_read;                 \ +                                                                              \ +                if ((ret > 0) || (priv->incoming.frag.remaining_size != 0)) { \ +                        if (priv->incoming.frag.remaining_size != 0) {        \ +                                __socket_proto_reset_pending (priv);          \ +                        }                                                     \ +                                                                              \ +                        gf_log (this->name, GF_LOG_TRACE, "partial read on non-blocking socket"); \ +                                                                              \ +                        break;                                                \ +                }                                                             \ +        } + +#define __socket_proto_init_pending(priv, size)                                \ +        do {                                                                   \ +                uint32_t remaining_fragsize = 0;                               \ +                remaining_fragsize = RPC_FRAGSIZE (priv->incoming.fraghdr)     \ +                        - priv->incoming.frag.bytes_read;                      \ +                                                                               \ +                __socket_proto_reset_pending (priv);                           \ +                                                                               \ +                priv->incoming.frag.pending_vector->iov_len =                  \ +                        remaining_fragsize > size ? size : remaining_fragsize; \ +                                                                               \ +                priv->incoming.frag.remaining_size =                           \ +                        size - priv->incoming.frag.pending_vector->iov_len;    \ +                                                                               \ +} while (0); + + +/* This will be used in a switch case and breaks from the switch case if all + * the pending data is not read. + */ +#define __socket_proto_read(priv, ret)                                         \ +        {                                                                      \ +                size_t bytes_read = 0;                                         \ +                                                                               \ +                __socket_proto_update_pending (priv);                          \ +                                                                               \ +                ret = __socket_readv (this,                                    \ +                                      priv->incoming.pending_vector, 1,        \ +                                      &priv->incoming.pending_vector,          \ +                                      &priv->incoming.pending_count,           \ +                                      &bytes_read);                            \ +                if (ret == -1) {                                               \ +                        gf_log (this->name, GF_LOG_TRACE,                      \ +                                "reading from socket failed. Error (%s), "     \ +                                "peer (%s)", strerror (errno),                 \ +                                 this->peerinfo.identifier);                   \ +                        break;                                                 \ +                }                                                              \ +                __socket_proto_update_priv_after_read (priv, ret, bytes_read); \ +         } + + +int socket_init (rpc_transport_t *this); + +/* + * return value: + *   0 = success (completed) + *  -1 = error + * > 0 = incomplete + */ + +int +__socket_rwv (rpc_transport_t *this, struct iovec *vector, int count, +              struct iovec **pending_vector, int *pending_count, size_t *bytes, +              int write) +{ +        socket_private_t *priv = NULL; +        int               sock = -1; +        int               ret = -1; +        struct iovec     *opvector = NULL; +        int               opcount = 0; +        int               moved = 0; + +        priv = this->private; +        sock = priv->sock; + +	opvector = vector; +	opcount  = count; + +        if (bytes != NULL) { +                *bytes = 0; +        } + +        while (opcount) { +                if (write) { +                        ret = writev (sock, opvector, opcount); + +                        if (ret == 0 || (ret == -1 && errno == EAGAIN)) { +                                /* done for now */ +                                break; +                        } +                } else { +                        ret = readv (sock, opvector, opcount); +                        if (ret == -1 && errno == EAGAIN) { +                                /* done for now */ +                                break; +                        } +                } + +                if (ret == 0) { +                        /* Mostly due to 'umount' in client */ + +                        gf_log (this->name, GF_LOG_TRACE, +                                "EOF from peer %s", this->peerinfo.identifier); +                        opcount = -1; +                        errno = ENOTCONN; +                        break; +                } +                if (ret == -1) { +                        if (errno == EINTR) +                                continue; + +                        gf_log (this->name, GF_LOG_TRACE, +                                "%s failed (%s)", write ? "writev" : "readv", +                                strerror (errno)); +                        opcount = -1; +                        break; +                } + +                if (bytes != NULL) { +                        *bytes += ret; +                } + +                moved = 0; + +                while (moved < ret) { +                        if ((ret - moved) >= opvector[0].iov_len) { +                                moved += opvector[0].iov_len; +                                opvector++; +                                opcount--; +                        } else { +                                opvector[0].iov_len -= (ret - moved); +                                opvector[0].iov_base += (ret - moved); +                                moved += (ret - moved); +                        } +                        while (opcount && !opvector[0].iov_len) { +                                opvector++; +                                opcount--; +                        } +                } +        } + +        if (pending_vector) +                *pending_vector = opvector; + +        if (pending_count) +                *pending_count = opcount; + +        return opcount; +} + + +int +__socket_readv (rpc_transport_t *this, struct iovec *vector, int count, +                struct iovec **pending_vector, int *pending_count, +                size_t *bytes) +{ +        int ret = -1; + +        ret = __socket_rwv (this, vector, count, +			    pending_vector, pending_count, bytes, 0); + +        return ret; +} + + +int +__socket_writev (rpc_transport_t *this, struct iovec *vector, int count, +                 struct iovec **pending_vector, int *pending_count) +{ +        int ret = -1; + +        ret = __socket_rwv (this, vector, count, +			    pending_vector, pending_count, NULL, 1); + +        return ret; +} + + +int +__socket_disconnect (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; + +        priv = this->private; + +        if (priv->sock != -1) { +                ret = shutdown (priv->sock, SHUT_RDWR); +                priv->connected = -1; +                gf_log (this->name, GF_LOG_TRACE, +                        "shutdown() returned %d. set connection state to -1", +                        ret); +        } + +        return ret; +} + + +int +__socket_server_bind (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; +	int               opt = 1; + +	priv = this->private; + +        ret = setsockopt (priv->sock, SOL_SOCKET, SO_REUSEADDR, +			  &opt, sizeof (opt)); + +        if (ret == -1) { +                gf_log (this->name, GF_LOG_ERROR, +                        "setsockopt() for SO_REUSEADDR failed (%s)", +                        strerror (errno)); +        } + +        ret = bind (priv->sock, (struct sockaddr *)&this->myinfo.sockaddr, +		    this->myinfo.sockaddr_len); + +        if (ret == -1) { +                gf_log (this->name, GF_LOG_ERROR, +                        "binding to %s failed: %s", +                        this->myinfo.identifier, strerror (errno)); +                if (errno == EADDRINUSE) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "Port is already in use"); +                } +        } + +        return ret; +} + + +int +__socket_nonblock (int fd) +{ +        int flags = 0; +        int ret = -1; + +        flags = fcntl (fd, F_GETFL); + +        if (flags != -1) +                ret = fcntl (fd, F_SETFL, flags | O_NONBLOCK); + +        return ret; +} + + +int +__socket_nodelay (int fd) +{ +        int     on = 1; +        int     ret = -1; + +        ret = setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, +			  &on, sizeof (on)); +        if (!ret) +                gf_log ("", GF_LOG_TRACE, +                        "NODELAY enabled for socket %d", fd); + +        return ret; +} + +int +__socket_connect_finish (int fd) +{ +        int       ret = -1; +        int       optval = 0; +        socklen_t optlen = sizeof (int); + +        ret = getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen); + +        if (ret == 0 && optval) { +                errno = optval; +                ret = -1; +        } + +        return ret; +} + + +void +__socket_reset (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; + +        priv = this->private; + +        /* TODO: use mem-pool on incoming data */ + +        if (priv->incoming.iobuf) { +                iobuf_unref (priv->incoming.iobuf); +        } + +        if (priv->incoming.vectoriob) { +                iobuf_unref (priv->incoming.vectoriob); +        } + +        memset (&priv->incoming, 0, sizeof (priv->incoming)); + +        event_unregister (this->ctx->event_pool, priv->sock, priv->idx); + +        close (priv->sock); +        priv->sock = -1; +        priv->idx = -1; +        priv->connected = -1; +} + + +struct ioq * +__socket_ioq_new (rpc_transport_t *this, rpc_transport_msg_t *msg) +{ +        socket_private_t *priv  = NULL; +        struct ioq       *entry = NULL; +        int               count = 0; + +        priv = this->private; + +        /* TODO: use mem-pool */ +        entry = GF_CALLOC (1, sizeof (*entry), gf_common_mt_ioq); +        if (!entry) +                return NULL; + +        count = msg->rpchdrcount + msg->proghdrcount + msg->progpayloadcount; + +        assert (count <= MAX_IOVEC); + +        if (msg->rpchdr != NULL) { +                memcpy (&entry->vector[0], msg->rpchdr, +                        sizeof (struct iovec) * msg->rpchdrcount); +                entry->count += msg->rpchdrcount; +        } + +        if (msg->proghdr != NULL) { +                memcpy (&entry->vector[entry->count], msg->proghdr, +                        sizeof (struct iovec) * msg->proghdrcount); +                entry->count += msg->proghdrcount; +        } + +        if (msg->progpayload != NULL) { +                memcpy (&entry->vector[entry->count], msg->progpayload, +                        sizeof (struct iovec) * msg->progpayloadcount); +                entry->count += msg->progpayloadcount; +        } + +        entry->pending_vector = entry->vector; +        entry->pending_count  = entry->count; + +        if (msg->iobref != NULL) +                entry->iobref = iobref_ref (msg->iobref); + +        INIT_LIST_HEAD (&entry->list); + +        return entry; +} + + +void +__socket_ioq_entry_free (struct ioq *entry) +{ +        list_del_init (&entry->list); +        if (entry->iobref) +                iobref_unref (entry->iobref); + +        /* TODO: use mem-pool */ +        GF_FREE (entry); +} + + +void +__socket_ioq_flush (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        struct ioq       *entry = NULL; + +        priv = this->private; + +        while (!list_empty (&priv->ioq)) { +                entry = priv->ioq_next; +                __socket_ioq_entry_free (entry); +        } + +        return; +} + + +int +__socket_ioq_churn_entry (rpc_transport_t *this, struct ioq *entry) +{ +        int ret = -1; + +        ret = __socket_writev (this, entry->pending_vector, +			       entry->pending_count, +                               &entry->pending_vector, +			       &entry->pending_count); + +        if (ret == 0) { +                /* current entry was completely written */ +                assert (entry->pending_count == 0); +                __socket_ioq_entry_free (entry); +        } + +        return ret; +} + + +int +__socket_ioq_churn (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = 0; +        struct ioq       *entry = NULL; + +        priv = this->private; + +        while (!list_empty (&priv->ioq)) { +                /* pick next entry */ +                entry = priv->ioq_next; + +                ret = __socket_ioq_churn_entry (this, entry); + +                if (ret != 0) +                        break; +        } + +        if (list_empty (&priv->ioq)) { +                /* all pending writes done, not interested in POLLOUT */ +                priv->idx = event_select_on (this->ctx->event_pool, +					     priv->sock, priv->idx, -1, 0); +        } + +        return ret; +} + + +int +socket_event_poll_err (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; + +        priv = this->private; + +        pthread_mutex_lock (&priv->lock); +        { +                __socket_ioq_flush (this); +                __socket_reset (this); +        } +        pthread_mutex_unlock (&priv->lock); + +        rpc_transport_notify (this, RPC_TRANSPORT_DISCONNECT, this); + +        return ret; +} + + +int +socket_event_poll_out (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; + +        priv = this->private; + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->connected == 1) { +                        ret = __socket_ioq_churn (this); + +                        if (ret == -1) { +                                __socket_disconnect (this); +                        } +                } +        } +        pthread_mutex_unlock (&priv->lock); + +        ret = rpc_transport_notify (this, RPC_TRANSPORT_MSG_SENT, NULL); + +        return ret; +} + + +inline int +__socket_read_simple_msg (rpc_transport_t *this) +{ +        socket_private_t *priv           = NULL; +        int               ret            = 0; +        uint32_t          remaining_size = 0; +        size_t            bytes_read     = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.simple_state) { + +        case SP_STATE_SIMPLE_MSG_INIT: +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                __socket_proto_init_pending (priv, remaining_size); + +                priv->incoming.frag.simple_state = +                        SP_STATE_READING_SIMPLE_MSG; + +                /* fall through */ + +        case SP_STATE_READING_SIMPLE_MSG: +                ret = 0; + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if (remaining_size > 0) { +                        ret = __socket_readv (this, +                                              priv->incoming.pending_vector, 1, +                                              &priv->incoming.pending_vector, +                                              &priv->incoming.pending_count, +                                              &bytes_read); +                } + +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_TRACE, +                                "reading from socket failed. Error (%s), " +                                "peer (%s)", strerror (errno), +                                this->peerinfo.identifier); +                        break; +                } + +                priv->incoming.frag.bytes_read += bytes_read; +                priv->incoming.frag.fragcurrent += bytes_read; + +                if (ret > 0) { +                        gf_log (this->name, GF_LOG_TRACE, +                                "partial read on non-blocking socket."); +                        break; +                } + +                if (ret == 0) { +                        priv->incoming.frag.simple_state +                                =  SP_STATE_SIMPLE_MSG_INIT; +                } +        } + +        return ret; +} + + +inline int +__socket_read_simple_request (rpc_transport_t *this) +{ +        return __socket_read_simple_msg (this); +} + + +#define rpc_cred_addr(buf) (buf + RPC_MSGTYPE_SIZE + RPC_CALL_BODY_SIZE - 4) + +#define rpc_verf_addr(fragcurrent) (fragcurrent - 4) + + +inline int +__socket_read_vectored_request (rpc_transport_t *this) +{ +        socket_private_t *priv                   = NULL; +        int               ret                    = 0; +        uint32_t          credlen                = 0, verflen = 0; +        char             *addr                   = NULL; +        struct iobuf     *iobuf                  = NULL; +        uint32_t          remaining_size         = 0; +        uint32_t          gluster_write_proc_len = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.call_body.request.vector_state) { +        case SP_STATE_VECTORED_REQUEST_INIT: +                addr = rpc_cred_addr (iobuf_ptr (priv->incoming.iobuf)); + +                /* also read verf flavour and verflen */ +                credlen = ntoh32 (*((uint32_t *)addr)) +                        +  RPC_AUTH_FLAVOUR_N_LENGTH_SIZE; + +                __socket_proto_init_pending (priv, credlen); + +                priv->incoming.frag.call_body.request.vector_state = +                        SP_STATE_READING_CREDBYTES; + +                /* fall through */ + +        case SP_STATE_READING_CREDBYTES: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.request.vector_state = +                        SP_STATE_READ_CREDBYTES; + +                /* fall through */ + +        case SP_STATE_READ_CREDBYTES: +                addr = rpc_verf_addr (priv->incoming.frag.fragcurrent); + +                /* FIXME: Also handle procedures other than glusterfs-write +                 * here +                 */ +                /* also read proc-header */ +                gluster_write_proc_len = sizeof (gfs3_write_req); + +                verflen = ntoh32 (*((uint32_t *)addr)) +                        + gluster_write_proc_len; + +                __socket_proto_init_pending (priv, verflen); + +                priv->incoming.frag.call_body.request.vector_state +                        = SP_STATE_READING_VERFBYTES; + +                /* fall through */ + +        case SP_STATE_READING_VERFBYTES: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.request.vector_state = +                        SP_STATE_READ_VERFBYTES; + +                /* fall through */ + +        case SP_STATE_READ_VERFBYTES: +                if (priv->incoming.vectoriob == NULL) { +                        iobuf = iobuf_get (this->ctx->iobuf_pool); +                        if (!iobuf) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "unable to allocate IO buffer " +                                        "for peer %s", +                                        this->peerinfo.identifier); +                                ret = -1; +                                break; +                        } + +                        priv->incoming.vectoriob = iobuf; +                        priv->incoming.frag.fragcurrent = iobuf_ptr (iobuf); +                } + +                priv->incoming.frag.call_body.request.vector_state = +                        SP_STATE_READING_PROG; + +                /* fall through */ + +        case SP_STATE_READING_PROG: +                /* now read the remaining rpc msg into buffer pointed by +                 * fragcurrent +                 */ + +                ret = __socket_read_simple_msg (this); + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if ((ret == -1) +                    || ((ret == 0) +                        && (remaining_size == 0) +                        && RPC_LASTFRAG (priv->incoming.fraghdr))) { +                        priv->incoming.frag.call_body.request.vector_state +                                = SP_STATE_VECTORED_REQUEST_INIT; +                        priv->incoming.vectoriob_size +                                = (unsigned long)priv->incoming.frag.fragcurrent +                                - (unsigned long)iobuf_ptr (priv->incoming.vectoriob); +                } +                break; +        } + +        return ret; +} + + +#define rpc_msgtype_addr(buf) (buf + 4) + +#define rpc_prognum_addr(buf) (buf + RPC_MSGTYPE_SIZE + 4) + +#define rpc_procnum_addr(buf) (buf + RPC_MSGTYPE_SIZE + 12) + + +inline int +__socket_read_request (rpc_transport_t *this) +{ +        socket_private_t *priv               = NULL; +        uint32_t          prognum            = 0, procnum = 0; +        uint32_t          remaining_size     = 0; +        int               ret                = -1; +        char             *buf                = NULL; + +        priv = this->private; + +        switch (priv->incoming.frag.call_body.request.header_state) { + +        case SP_STATE_REQUEST_HEADER_INIT: + +                __socket_proto_init_pending (priv, RPC_CALL_BODY_SIZE); + +                priv->incoming.frag.call_body.request.header_state +                        = SP_STATE_READING_RPCHDR1; + +                /* fall through */ + +        case SP_STATE_READING_RPCHDR1: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.request.header_state = +                        SP_STATE_READ_RPCHDR1; + +                /* fall through */ + +        case SP_STATE_READ_RPCHDR1: +                buf = rpc_prognum_addr (iobuf_ptr (priv->incoming.iobuf)); +                prognum = ntoh32 (*((uint32_t *)buf)); + +                buf = rpc_procnum_addr (iobuf_ptr (priv->incoming.iobuf)); +                procnum = ntoh32 (*((uint32_t *)buf)); + +                if ((prognum == GLUSTER3_1_FOP_PROGRAM) +                    && (procnum == GF_FOP_WRITE)) { +                        ret = __socket_read_vectored_request (this); +                } else { +                        ret = __socket_read_simple_request (this); +                } + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if ((ret == -1) +                    || ((ret == 0) +                        && (remaining_size == 0) +                        && (RPC_LASTFRAG (priv->incoming.fraghdr)))) { +                        priv->incoming.frag.call_body.request.header_state = +                                SP_STATE_REQUEST_HEADER_INIT; +                } + +                break; +        } + +        return ret; +} + + +inline int +__socket_read_accepted_successful_reply (rpc_transport_t *this) +{ +        socket_private_t *priv                     = NULL; +        int               ret                      = 0; +        struct iobuf     *iobuf                    = NULL; +        uint32_t          gluster_read_rsp_hdr_len = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.call_body.reply.accepted_success_state) { + +        case SP_STATE_ACCEPTED_SUCCESS_REPLY_INIT: +                gluster_read_rsp_hdr_len = sizeof (gfs3_read_rsp); + +                __socket_proto_init_pending (priv, gluster_read_rsp_hdr_len); + +                priv->incoming.frag.call_body.reply.accepted_success_state +                        = SP_STATE_READING_PROC_HEADER; + +                /* fall through */ + +        case SP_STATE_READING_PROC_HEADER: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.reply.accepted_success_state +                        = SP_STATE_READ_PROC_HEADER; + +                /* fall through */ + +        case SP_STATE_READ_PROC_HEADER: +                if (priv->incoming.vectoriob == NULL) { +                        iobuf = iobuf_get (this->ctx->iobuf_pool); +                        if (iobuf == NULL) { +                                ret = -1; +                                goto out; +                        } + +                        priv->incoming.vectoriob = iobuf; +                } + +                priv->incoming.frag.fragcurrent +                        = iobuf_ptr (priv->incoming.vectoriob); + +                /* now read the entire remaining msg into new iobuf */ +                ret = __socket_read_simple_msg (this); +                if ((ret == -1) +                    || ((ret == 0) +                        && RPC_LASTFRAG (priv->incoming.fraghdr))) { +                        priv->incoming.frag.call_body.reply.accepted_success_state +                                = SP_STATE_ACCEPTED_SUCCESS_REPLY_INIT; +                } + +                break; +        } + +out: +        return ret; +} + +#define rpc_reply_verflen_addr(fragcurrent) ((char *)fragcurrent - 4) +#define rpc_reply_accept_status_addr(fragcurrent) ((char *)fragcurrent - 4) + +inline int +__socket_read_accepted_reply (rpc_transport_t *this) +{ +        socket_private_t *priv           = NULL; +        int               ret            = -1; +        char             *buf            = NULL; +        uint32_t          verflen        = 0, len = 0; +        uint32_t          remaining_size = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.call_body.reply.accepted_state) { + +        case SP_STATE_ACCEPTED_REPLY_INIT: +                __socket_proto_init_pending (priv, +                                             RPC_AUTH_FLAVOUR_N_LENGTH_SIZE); + +                priv->incoming.frag.call_body.reply.accepted_state +                        = SP_STATE_READING_REPLY_VERFLEN; + +                /* fall through */ + +        case SP_STATE_READING_REPLY_VERFLEN: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.reply.accepted_state +                        = SP_STATE_READ_REPLY_VERFLEN; + +                /* fall through */ + +        case SP_STATE_READ_REPLY_VERFLEN: +                buf = rpc_reply_verflen_addr (priv->incoming.frag.fragcurrent); + +                verflen = ntoh32 (*((uint32_t *) buf)); + +                /* also read accept status along with verf data */ +                len = verflen + RPC_ACCEPT_STATUS_LEN; + +                __socket_proto_init_pending (priv, len); + +                priv->incoming.frag.call_body.reply.accepted_state +                        = SP_STATE_READING_REPLY_VERFBYTES; + +                /* fall through */ + +        case SP_STATE_READING_REPLY_VERFBYTES: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.call_body.reply.accepted_state +                        = SP_STATE_READ_REPLY_VERFBYTES; + +                buf = rpc_reply_accept_status_addr (priv->incoming.frag.fragcurrent); + +                priv->incoming.frag.call_body.reply.accept_status +                        = ntoh32 (*(uint32_t *) buf); + +                /* fall through */ + +        case SP_STATE_READ_REPLY_VERFBYTES: + +                if (priv->incoming.frag.call_body.reply.accept_status +                    == SUCCESS) { +                        ret = __socket_read_accepted_successful_reply (this); +                } else { +                        /* read entire remaining msg into buffer pointed to by +                         * fragcurrent +                         */ +                        ret = __socket_read_simple_msg (this); +                } + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if ((ret == -1) +                    || ((ret == 0) +                        && (remaining_size == 0) +                        && (RPC_LASTFRAG (priv->incoming.fraghdr)))) { +                        priv->incoming.frag.call_body.reply.accepted_state +                                = SP_STATE_ACCEPTED_REPLY_INIT; +                } + +                break; +        } + +        return ret; +} + + +inline int +__socket_read_denied_reply (rpc_transport_t *this) +{ +        return __socket_read_simple_msg (this); +} + + +#define rpc_reply_status_addr(fragcurrent) ((char *)fragcurrent - 4) + + +inline int +__socket_read_vectored_reply (rpc_transport_t *this) +{ +        socket_private_t *priv           = NULL; +        int               ret            = 0; +        char             *buf            = NULL; +        uint32_t          remaining_size = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.call_body.reply.status_state) { + +        case SP_STATE_ACCEPTED_REPLY_INIT: +                __socket_proto_init_pending (priv, RPC_REPLY_STATUS_SIZE); + +                priv->incoming.frag.call_body.reply.status_state +                        = SP_STATE_READING_REPLY_STATUS; + +                /* fall through */ + +        case SP_STATE_READING_REPLY_STATUS: +                __socket_proto_read (priv, ret); + +                buf = rpc_reply_status_addr (priv->incoming.frag.fragcurrent); + +                priv->incoming.frag.call_body.reply.accept_status +                        = ntoh32 (*((uint32_t *) buf)); + +                priv->incoming.frag.call_body.reply.status_state +                        = SP_STATE_READ_REPLY_STATUS; + +                /* fall through */ + +        case SP_STATE_READ_REPLY_STATUS: +                if (priv->incoming.frag.call_body.reply.accept_status +                    == MSG_ACCEPTED) { +                        ret = __socket_read_accepted_reply (this); +                } else { +                        ret = __socket_read_denied_reply (this); +                } + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if ((ret == -1) +                    || ((ret == 0) +                        && (remaining_size == 0) +                        && (RPC_LASTFRAG (priv->incoming.fraghdr)))) { +                        priv->incoming.frag.call_body.reply.status_state +                                = SP_STATE_ACCEPTED_REPLY_INIT; +                } +                break; +        } + +        return ret; +} + + +inline int +__socket_read_simple_reply (rpc_transport_t *this) +{ +        return __socket_read_simple_msg (this); +} + +#define rpc_xid_addr(buf) (buf) + +inline int +__socket_read_reply (rpc_transport_t *this) +{ +        socket_private_t   *priv         = NULL; +        char               *buf          = NULL; +        int32_t             ret          = -1; +        rpc_request_info_t *request_info = NULL; + +        priv = this->private; + +        buf = rpc_xid_addr (iobuf_ptr (priv->incoming.iobuf)); + +        request_info = GF_CALLOC (1, sizeof (*request_info), gf_common_mt_rpc_trans_reqinfo_t); +        if (request_info == NULL) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                goto out; +        } + +        priv->incoming.request_info = request_info; + +        request_info->xid = ntoh32 (*((uint32_t *) buf)); + +        /* release priv->lock, so as to avoid deadlock b/w conn->lock and +         * priv->lock, since we are doing an upcall here. +         */ +        pthread_mutex_unlock (&priv->lock); +        { +                ret = rpc_transport_notify (this, RPC_TRANSPORT_MAP_XID_REQUEST, +                                            priv->incoming.request_info); +        } +        pthread_mutex_lock (&priv->lock); + +        if (ret == -1) { +                goto out; +        } + +        if ((request_info->prognum == GLUSTER3_1_FOP_PROGRAM) +            && (request_info->procnum == GF_FOP_READ)) { +                if (request_info->rsp.rspbuf != NULL) { +                        priv->incoming.vectoriob +                                = iobuf_ref (request_info->rsp.rspbuf); +                } + +                ret = __socket_read_vectored_reply (this); +        } else { +                ret = __socket_read_simple_reply (this); +        } +out: +        return ret; +} + + +/* returns the number of bytes yet to be read in a fragment */ +inline int +__socket_read_frag (rpc_transport_t *this) +{ +        socket_private_t *priv           = NULL; +        int32_t           ret            = 0; +        char             *buf            = NULL; +        uint32_t          remaining_size = 0; + +        priv = this->private; + +        switch (priv->incoming.frag.state) { +        case SP_STATE_NADA: +                __socket_proto_init_pending (priv, RPC_MSGTYPE_SIZE); + +                priv->incoming.frag.state = SP_STATE_READING_MSGTYPE; + +                /* fall through */ + +        case SP_STATE_READING_MSGTYPE: +                __socket_proto_read (priv, ret); + +                priv->incoming.frag.state = SP_STATE_READ_MSGTYPE; +                /* fall through */ + +        case SP_STATE_READ_MSGTYPE: +                buf = rpc_msgtype_addr (iobuf_ptr (priv->incoming.iobuf)); +                priv->incoming.msg_type = ntoh32 (*((uint32_t *)buf)); + +                if (priv->incoming.msg_type == CALL) { +                        ret = __socket_read_request (this); +                } else if (priv->incoming.msg_type == REPLY) { +                        ret = __socket_read_reply (this); +                } else { +                        gf_log ("rpc", GF_LOG_ERROR, +                                "wrong MSG-TYPE (%d) received", +                                priv->incoming.msg_type); +                        ret = -1; +                } + +                remaining_size = RPC_FRAGSIZE (priv->incoming.fraghdr) +                        - priv->incoming.frag.bytes_read; + +                if ((ret == -1) +                    || ((ret == 0) +                        && (remaining_size == 0) +                        && (RPC_LASTFRAG (priv->incoming.fraghdr)))) { +                        priv->incoming.frag.state = SP_STATE_NADA; +                } + +                break; +        } + +        return ret; +} + + +inline +void __socket_reset_priv (socket_private_t *priv) +{ +        if (priv->incoming.iobuf) { +                iobuf_unref (priv->incoming.iobuf); +                priv->incoming.iobuf = NULL; +        } + +        if (priv->incoming.vectoriob) { +                iobuf_unref (priv->incoming.vectoriob); +                priv->incoming.vectoriob = NULL; +        } +} + + +int +__socket_proto_state_machine (rpc_transport_t *this, +                              rpc_transport_pollin_t **pollin) +{ +        int               ret   = -1; +        socket_private_t *priv  = NULL; +        struct iobuf     *iobuf = NULL; + +        priv = this->private; +        while (priv->incoming.record_state != SP_STATE_COMPLETE) { +                switch (priv->incoming.record_state) { + +                case SP_STATE_NADA: +                        iobuf = iobuf_get (this->ctx->iobuf_pool); +                        if (!iobuf) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "unable to allocate IO buffer " +                                        "for peer %s", +                                        this->peerinfo.identifier); +                                ret = -ENOMEM; +                                goto out; +                        } + +                        priv->incoming.iobuf = iobuf; +                        priv->incoming.iobuf_size = 0; +                        priv->incoming.vectoriob_size = 0; + +                        priv->incoming.pending_vector = priv->incoming.vector; +                        priv->incoming.pending_vector->iov_base = +                                &priv->incoming.fraghdr; + +                        priv->incoming.frag.fragcurrent = iobuf_ptr (iobuf); +                        priv->incoming.pending_vector->iov_len  = +                                sizeof (priv->incoming.fraghdr); + +                        priv->incoming.record_state = SP_STATE_READING_FRAGHDR; + +                        /* fall through */ + +                case SP_STATE_READING_FRAGHDR: +                        ret = __socket_readv (this, +                                              priv->incoming.pending_vector, 1, +                                              &priv->incoming.pending_vector, +                                              &priv->incoming.pending_count, +                                              NULL); +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_TRACE, +                                        "reading from socket failed. Error (%s), " +                                        "peer (%s)", strerror (errno), +                                        this->peerinfo.identifier); +                                goto out; +                        } + +                        if (ret > 0) { +                                gf_log (this->name, GF_LOG_TRACE, "partial " +                                        "fragment header read"); +                                goto out; +                        } + +                        if (ret == 0) { +                                priv->incoming.record_state = +                                        SP_STATE_READ_FRAGHDR; +                        } +                        /* fall through */ + +                case SP_STATE_READ_FRAGHDR: + +                        priv->incoming.fraghdr = ntoh32 (priv->incoming.fraghdr); +                        priv->incoming.record_state = SP_STATE_READING_FRAG; +                        priv->incoming.total_bytes_read +                                += RPC_FRAGSIZE(priv->incoming.fraghdr); +                        /* fall through */ + +                case SP_STATE_READING_FRAG: +                        ret = __socket_read_frag (this); + +                        if ((ret == -1) +                            || (priv->incoming.frag.bytes_read != +                                RPC_FRAGSIZE (priv->incoming.fraghdr))) { +                                goto out; +                        } + +                        priv->incoming.frag.bytes_read = 0; + +                        if (!RPC_LASTFRAG (priv->incoming.fraghdr)) { +                                priv->incoming.record_state = +                                        SP_STATE_READING_FRAGHDR; +                                break; +                        } + +                        /* we've read the entire rpc record, notify the +                         * upper layers. +                         */ +                        if (pollin != NULL) { +                                priv->incoming.iobuf_size +                                        = priv->incoming.total_bytes_read +                                        - priv->incoming.vectoriob_size; + +                                *pollin = rpc_transport_pollin_alloc (this, +                                                                      priv->incoming.iobuf, +                                                                      priv->incoming.iobuf_size, +                                                                      priv->incoming.vectoriob, +                                                                      priv->incoming.vectoriob_size, +                                                                      priv->incoming.request_info); +                                if (*pollin == NULL) { +                                        ret = -1; +                                        goto out; +                                } + +                                priv->incoming.request_info = NULL; +                        } +                        priv->incoming.record_state = SP_STATE_COMPLETE; +                        break; + +                case SP_STATE_COMPLETE: +                        /* control should not reach here */ +                        gf_log (this->name, GF_LOG_DEBUG, "control reached to " +                                "SP_STATE_COMPLETE, which should not have " +                                "happened"); +                        break; +                } +        } + +        if (priv->incoming.record_state == SP_STATE_COMPLETE) { +                priv->incoming.record_state = SP_STATE_NADA; +                __socket_reset_priv (priv); +        } + +out: +        if ((ret == -1) && (errno == EAGAIN)) { +                ret = 0; +        } +        return ret; +} + + +int +socket_proto_state_machine (rpc_transport_t *this, +                            rpc_transport_pollin_t **pollin) +{ +        socket_private_t *priv = NULL; +	int               ret = 0; + +	priv = this->private; + +	pthread_mutex_lock (&priv->lock); +	{ +		ret = __socket_proto_state_machine (this, pollin); +	} +        pthread_mutex_unlock (&priv->lock); + +	return ret; +} + + +int +socket_event_poll_in (rpc_transport_t *this) +{ +        int                     ret    = -1; +        rpc_transport_pollin_t *pollin = NULL; + +        ret = socket_proto_state_machine (this, &pollin); + +        if (pollin != NULL) { +                ret = rpc_transport_notify (this, RPC_TRANSPORT_MSG_RECEIVED, +                                            pollin); + +                rpc_transport_pollin_destroy (pollin); +        } + +        return ret; +} + + +int +socket_connect_finish (rpc_transport_t *this) +{ +        int                   ret        = -1; +        socket_private_t     *priv       = NULL; +        rpc_transport_event_t event      = 0; +        char                  notify_rpc = 0; + +        priv = this->private; + +        pthread_mutex_lock (&priv->lock); +        { +		if (priv->connected) +			goto unlock; + +		ret = __socket_connect_finish (priv->sock); + +		if (ret == -1 && errno == EINPROGRESS) +			ret = 1; + +		if (ret == -1 && errno != EINPROGRESS) { +			if (!priv->connect_finish_log) { +				gf_log (this->name, GF_LOG_ERROR, +					"connection to %s failed (%s)", +                                        this->peerinfo.identifier, +					strerror (errno)); +				priv->connect_finish_log = 1; +			} +			__socket_disconnect (this); +			notify_rpc = 1; +			event = RPC_TRANSPORT_DISCONNECT; +			goto unlock; +		} + +		if (ret == 0) { +			notify_rpc = 1; + +			this->myinfo.sockaddr_len = +				sizeof (this->myinfo.sockaddr); + +			ret = getsockname (priv->sock, +					   SA (&this->myinfo.sockaddr), +					   &this->myinfo.sockaddr_len); +			if (ret == -1) { +				gf_log (this->name, GF_LOG_DEBUG, +					"getsockname on (%d) failed (%s)", +					priv->sock, strerror (errno)); +				__socket_disconnect (this); +				event = GF_EVENT_POLLERR; +				goto unlock; +			} + +			priv->connected = 1; +			priv->connect_finish_log = 0; +			event = RPC_TRANSPORT_CONNECT; +			get_transport_identifiers (this); +		} +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +        if (notify_rpc) { +                rpc_transport_notify (this, event, this); +        } + +        return 0; +} + + +/* reads rpc_requests during pollin */ +int +socket_event_handler (int fd, int idx, void *data, +                      int poll_in, int poll_out, int poll_err) +{ +        rpc_transport_t      *this = NULL; +        socket_private_t *priv = NULL; +        int               ret = 0; + +        this = data; +        priv = this->private; + +        pthread_mutex_lock (&priv->lock); +        { +                priv->idx = idx; +        } +        pthread_mutex_unlock (&priv->lock); + +        if (!priv->connected) { +                ret = socket_connect_finish (this); +        } + +        if (!ret && poll_out) { +                ret = socket_event_poll_out (this); +        } + +        if (!ret && poll_in) { +                ret = socket_event_poll_in (this); +        } + +        if ((ret < 0) || poll_err) { +                gf_log ("transport", GF_LOG_TRACE, "disconnecting now"); +                socket_event_poll_err (this); +                rpc_transport_unref (this); +        } + +        return 0; +} + + +int +socket_server_event_handler (int fd, int idx, void *data, +                             int poll_in, int poll_out, int poll_err) +{ +        rpc_transport_t             *this = NULL; +        socket_private_t        *priv = NULL; +        int                      ret = 0; +        int                      new_sock = -1; +        rpc_transport_t             *new_trans = NULL; +        struct sockaddr_storage  new_sockaddr = {0, }; +        socklen_t                addrlen = sizeof (new_sockaddr); +        socket_private_t        *new_priv = NULL; +	glusterfs_ctx_t         *ctx = NULL; + +        this = data; +        priv = this->private; +	ctx  = this->ctx; + +        pthread_mutex_lock (&priv->lock); +        { +                priv->idx = idx; + +                if (poll_in) { +                        new_sock = accept (priv->sock, SA (&new_sockaddr), +					   &addrlen); + +                        if (new_sock == -1) +                                goto unlock; + +                        if (!priv->bio) { +                                ret = __socket_nonblock (new_sock); + +                                if (ret == -1) { +                                        gf_log (this->name, GF_LOG_DEBUG, +                                                "NBIO on %d failed (%s)", +                                                new_sock, strerror (errno)); + +                                        close (new_sock); +                                        goto unlock; +                                } +                        } + +                        if (priv->nodelay) { +                                ret = __socket_nodelay (new_sock); +                                if (ret == -1) { +                                        gf_log (this->name, GF_LOG_ERROR, +                                                "setsockopt() failed for " +                                                "NODELAY (%s)", +                                                strerror (errno)); +                                } +                        } + +                        new_trans = GF_CALLOC (1, sizeof (*new_trans), +                                               gf_common_mt_rpc_trans_t); +                        new_trans->fini = this->fini; +                        new_trans->name = gf_strdup (this->name); + +                        memcpy (&new_trans->peerinfo.sockaddr, &new_sockaddr, +				addrlen); +                        new_trans->peerinfo.sockaddr_len = addrlen; + +                        new_trans->myinfo.sockaddr_len = +				sizeof (new_trans->myinfo.sockaddr); + +                        ret = getsockname (new_sock, +                                           SA (&new_trans->myinfo.sockaddr), +                                           &new_trans->myinfo.sockaddr_len); +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                        "getsockname on %d failed (%s)", +                                        new_sock, strerror (errno)); +                                close (new_sock); +                                goto unlock; +                        } + +                        get_transport_identifiers (new_trans); +                        socket_init (new_trans); +                        new_trans->ops = this->ops; +                        new_trans->init = this->init; +                        new_trans->fini = this->fini; +                        new_trans->ctx  = ctx; +                        new_trans->mydata = this->mydata; +                        new_trans->notify = this->notify; +                        new_priv = new_trans->private; + +                        pthread_mutex_lock (&new_priv->lock); +                        { +                                new_priv->sock = new_sock; +                                new_priv->connected = 1; +                                rpc_transport_ref (new_trans); + +                                new_priv->idx = +					event_register (ctx->event_pool, +							new_sock, +							socket_event_handler, +							new_trans, 1, 0); + +                                if (new_priv->idx == -1) +                                        ret = -1; +                        } +                        pthread_mutex_unlock (&new_priv->lock); +                        ret = rpc_transport_notify (this, RPC_TRANSPORT_ACCEPT, new_trans); +                } +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} + + +int +socket_disconnect (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; + +        priv = this->private; + +        pthread_mutex_lock (&priv->lock); +        { +                ret = __socket_disconnect (this); +        } +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} + + +int +socket_connect (rpc_transport_t *this) +{ +        int                      ret = -1; +	int                      sock = -1; +        socket_private_t        *priv = NULL; +        struct sockaddr_storage  sockaddr = {0, }; +        socklen_t                sockaddr_len = 0; +	glusterfs_ctx_t         *ctx = NULL; +        sa_family_t              sa_family = {0, }; + +        priv = this->private; +	ctx = this->ctx; + +        if (!priv) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "connect() called on uninitialized transport"); +                goto err; +        } + +        pthread_mutex_lock (&priv->lock); +        { +                sock = priv->sock; +        } +        pthread_mutex_unlock (&priv->lock); + +        if (sock != -1) { +                gf_log (this->name, GF_LOG_TRACE, +                        "connect () called on transport already connected"); +                ret = 0; +                goto err; +        } + +        ret = socket_client_get_remote_sockaddr (this, SA (&sockaddr), +                                                 &sockaddr_len, &sa_family); +        if (ret == -1) { +                /* logged inside client_get_remote_sockaddr */ +                goto err; +        } + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->sock != -1) { +                        gf_log (this->name, GF_LOG_TRACE, +                                "connect() -- already connected"); +                        goto unlock; +                } + +                memcpy (&this->peerinfo.sockaddr, &sockaddr, sockaddr_len); +                this->peerinfo.sockaddr_len = sockaddr_len; + +                priv->sock = socket (sa_family, SOCK_STREAM, 0); +                if (priv->sock == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "socket creation failed (%s)", +				strerror (errno)); +                        goto unlock; +                } + +                /* Cant help if setting socket options fails. We can continue +                 * working nonetheless. +                 */ +                if (setsockopt (priv->sock, SOL_SOCKET, SO_RCVBUF, +                                &priv->windowsize, +                                sizeof (priv->windowsize)) < 0) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "setting receive window size failed: %d: %d: " +                                "%s", priv->sock, priv->windowsize, +                                strerror (errno)); +                } + +                if (setsockopt (priv->sock, SOL_SOCKET, SO_SNDBUF, +                                &priv->windowsize, +                                sizeof (priv->windowsize)) < 0) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "setting send window size failed: %d: %d: " +                                "%s", priv->sock, priv->windowsize, +                                strerror (errno)); +                } + + +                if (priv->nodelay && priv->lowlat) { +                        ret = __socket_nodelay (priv->sock); +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "setsockopt() failed for NODELAY (%s)", +                                        strerror (errno)); +                        } +                } + +                if (!priv->bio) { +                        ret = __socket_nonblock (priv->sock); + +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "NBIO on %d failed (%s)", +                                        priv->sock, strerror (errno)); +                                close (priv->sock); +                                priv->sock = -1; +                                goto unlock; +                        } +                } + +                SA (&this->myinfo.sockaddr)->sa_family = +			SA (&this->peerinfo.sockaddr)->sa_family; + +                ret = client_bind (this, SA (&this->myinfo.sockaddr), +				   &this->myinfo.sockaddr_len, priv->sock); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_WARNING, +                                "client bind failed: %s", strerror (errno)); +                        close (priv->sock); +                        priv->sock = -1; +                        goto unlock; +                } + +                ret = connect (priv->sock, SA (&this->peerinfo.sockaddr), +			       this->peerinfo.sockaddr_len); + +                if (ret == -1 && errno != EINPROGRESS) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "connection attempt failed (%s)", +				strerror (errno)); +                        close (priv->sock); +                        priv->sock = -1; +                        goto unlock; +                } + +                priv->connected = 0; + +                rpc_transport_ref (this); + +                priv->idx = event_register (ctx->event_pool, priv->sock, +                                            socket_event_handler, this, 1, 1); +                if (priv->idx == -1) +                        ret = -1; +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +err: +        return ret; +} + + +int +socket_listen (rpc_transport_t *this) +{ +        socket_private_t *       priv = NULL; +        int                      ret = -1; +	int                      sock = -1; +        struct sockaddr_storage  sockaddr; +        socklen_t                sockaddr_len; +        peer_info_t             *myinfo = NULL; +	glusterfs_ctx_t         *ctx = NULL; +        sa_family_t              sa_family = {0, }; + +	priv   = this->private; +	myinfo = &this->myinfo; +	ctx    = this->ctx; + +        pthread_mutex_lock (&priv->lock); +        { +                sock = priv->sock; +        } +        pthread_mutex_unlock (&priv->lock); + +        if (sock != -1)  { +                gf_log (this->name, GF_LOG_DEBUG, +                        "alreading listening"); +                return ret; +        } + +        ret = socket_server_get_local_sockaddr (this, SA (&sockaddr), +                                                &sockaddr_len, &sa_family); +        if (ret == -1) { +                return ret; +        } + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->sock != -1) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "already listening"); +                        goto unlock; +                } + +                memcpy (&myinfo->sockaddr, &sockaddr, sockaddr_len); +                myinfo->sockaddr_len = sockaddr_len; + +                priv->sock = socket (sa_family, SOCK_STREAM, 0); + +                if (priv->sock == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "socket creation failed (%s)", +				strerror (errno)); +                        goto unlock; +                } + +                /* Cant help if setting socket options fails. We can continue +                 * working nonetheless. +                 */ +                if (setsockopt (priv->sock, SOL_SOCKET, SO_RCVBUF, +                                &priv->windowsize, +                                sizeof (priv->windowsize)) < 0) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "setting receive window size failed: %d: %d: " +                                "%s", priv->sock, priv->windowsize, +                                strerror (errno)); +                } + +                if (setsockopt (priv->sock, SOL_SOCKET, SO_SNDBUF, +                                &priv->windowsize, +                                sizeof (priv->windowsize)) < 0) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "setting send window size failed: %d: %d: " +                                "%s", priv->sock, priv->windowsize, +                                strerror (errno)); +                } + +                if (priv->nodelay) { +                        ret = __socket_nodelay (priv->sock); +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "setsockopt() failed for NODELAY (%s)", +                                        strerror (errno)); +                        } +                } + +                if (!priv->bio) { +                        ret = __socket_nonblock (priv->sock); + +                        if (ret == -1) { +                                gf_log (this->name, GF_LOG_ERROR, +                                        "NBIO on %d failed (%s)", +                                        priv->sock, strerror (errno)); +                                close (priv->sock); +                                priv->sock = -1; +                                goto unlock; +                        } +                } + +                ret = __socket_server_bind (this); + +                if (ret == -1) { +                        /* logged inside __socket_server_bind() */ +                        close (priv->sock); +                        priv->sock = -1; +                        goto unlock; +                } + +                ret = listen (priv->sock, 10); + +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "could not set socket %d to listen mode (%s)", +				priv->sock, strerror (errno)); +                        close (priv->sock); +                        priv->sock = -1; +                        goto unlock; +                } + +                rpc_transport_ref (this); + +                priv->idx = event_register (ctx->event_pool, priv->sock, +                                            socket_server_event_handler, +					    this, 1, 0); + +                if (priv->idx == -1) { +                        gf_log (this->name, GF_LOG_DEBUG, +                                "could not register socket %d with events", +				priv->sock); +                        ret = -1; +                        close (priv->sock); +                        priv->sock = -1; +                        goto unlock; +                } +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} + + +/* TODO: implement per transfer limit */ +#if 0 +int +socket_submit (rpc_transport_t *this, char *buf, int len, +               struct iovec *vector, int count, +               struct iobref *iobref) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; +        char              need_poll_out = 0; +        char              need_append = 1; +        struct ioq       *entry = NULL; +	glusterfs_ctx_t  *ctx = NULL; + +        priv = this->private; +	ctx  = this->ctx; + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->connected != 1) { +                        if (!priv->submit_log && !priv->connect_finish_log) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                        "not connected (priv->connected = %d)", +                                        priv->connected); +                                priv->submit_log = 1; +                        } +                        goto unlock; +                } + +                priv->submit_log = 0; +                entry = __socket_ioq_new (this, buf, len, vector, count, iobref); +                if (!entry) +                        goto unlock; + +                if (list_empty (&priv->ioq)) { +                        ret = __socket_ioq_churn_entry (this, entry); + +                        if (ret == 0) +                                need_append = 0; + +                        if (ret > 0) +                                need_poll_out = 1; +                } + +                if (need_append) { +                        list_add_tail (&entry->list, &priv->ioq); +                        ret = 0; +                } + +                if (need_poll_out) { +                        /* first entry to wait. continue writing on POLLOUT */ +                        priv->idx = event_select_on (ctx->event_pool, +						     priv->sock, +                                                     priv->idx, -1, 1); +                } +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} +#endif + + +int32_t +socket_submit_request (rpc_transport_t *this, rpc_transport_req_t *req) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; +        char              need_poll_out = 0; +        char              need_append = 1; +        struct ioq       *entry = NULL; +	glusterfs_ctx_t  *ctx = NULL; + +        priv = this->private; +	ctx  = this->ctx; + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->connected != 1) { +                        if (!priv->submit_log && !priv->connect_finish_log) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                        "not connected (priv->connected = %d)", +                                        priv->connected); +                                priv->submit_log = 1; +                        } +                        goto unlock; +                } + +                priv->submit_log = 0; +                entry = __socket_ioq_new (this, &req->msg); +                if (!entry) +                        goto unlock; + +                if (list_empty (&priv->ioq)) { +                        ret = __socket_ioq_churn_entry (this, entry); + +                        if (ret == 0) +                                need_append = 0; + +                        if (ret > 0) +                                need_poll_out = 1; +                } + +                if (need_append) { +                        list_add_tail (&entry->list, &priv->ioq); +                        ret = 0; +                } + +                if (need_poll_out) { +                        /* first entry to wait. continue writing on POLLOUT */ +                        priv->idx = event_select_on (ctx->event_pool, +						     priv->sock, +                                                     priv->idx, -1, 1); +                } +        } +unlock: +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} + + +int32_t +socket_submit_reply (rpc_transport_t *this, rpc_transport_reply_t *reply) +{ +        socket_private_t *priv = NULL; +        int               ret = -1; +        char              need_poll_out = 0; +        char              need_append = 1; +        struct ioq       *entry = NULL; +	glusterfs_ctx_t  *ctx = NULL; + +        priv = this->private; +	ctx  = this->ctx; + +        pthread_mutex_lock (&priv->lock); +        { +                if (priv->connected != 1) { +                        if (!priv->submit_log && !priv->connect_finish_log) { +                                gf_log (this->name, GF_LOG_DEBUG, +                                        "not connected (priv->connected = %d)", +                                        priv->connected); +                                priv->submit_log = 1; +                        } +                        goto unlock; +                } +                priv->submit_log = 0; +                entry = __socket_ioq_new (this, &reply->msg); +                if (!entry) +                        goto unlock; +                if (list_empty (&priv->ioq)) { +                        ret = __socket_ioq_churn_entry (this, entry); + +                        if (ret == 0) +                                need_append = 0; + +                        if (ret > 0) +                                need_poll_out = 1; +                } + +                if (need_append) { +                        list_add_tail (&entry->list, &priv->ioq); +                        ret = 0; +                } + +                if (need_poll_out) { +                        /* first entry to wait. continue writing on POLLOUT */ +                        priv->idx = event_select_on (ctx->event_pool, +						     priv->sock, +                                                     priv->idx, -1, 1); +                } +        } + +unlock: +        pthread_mutex_unlock (&priv->lock); + +        return ret; +} + + +int32_t +socket_getpeername (rpc_transport_t *this, char *hostname, int hostlen) +{ +        int32_t ret = -1; + +        if ((this == NULL) || (hostname == NULL)) { +                goto out; +        } + +        if (hostlen < (strlen (this->peerinfo.identifier) + 1)) { +                goto out; +        } + +        strcpy (hostname, this->peerinfo.identifier); +        ret = 0; +out: +        return ret; +} + + +int32_t +socket_getpeeraddr (rpc_transport_t *this, char *peeraddr, int addrlen, +                    struct sockaddr *sa, socklen_t salen) +{ +        int32_t ret = -1; + +        if ((this == NULL) || (sa == NULL)) { +                goto out; +        } + +        *sa = *((struct sockaddr *)&this->peerinfo.sockaddr); + +        if (peeraddr != NULL) { +                ret = socket_getpeername (this, peeraddr, addrlen); +        } + +out: +        return ret; +} + + +int32_t +socket_getmyname (rpc_transport_t *this, char *hostname, int hostlen) +{ +        int32_t ret = -1; + +        if ((this == NULL) || (hostname == NULL)) { +                goto out; +        } + +        if (hostlen < (strlen (this->myinfo.identifier) + 1)) { +                goto out; +        } + +        strcpy (hostname, this->myinfo.identifier); +        ret = 0; +out: +        return ret; +} + + +int32_t +socket_getmyaddr (rpc_transport_t *this, char *myaddr, int addrlen, +                  struct sockaddr *sa, socklen_t salen) +{ +        int32_t ret = -1; + +        if ((this == NULL) || (sa == NULL)) { +                goto out; +        } + +        *sa = *((struct sockaddr *)&this->myinfo.sockaddr); + +        if (myaddr != NULL) { +                ret = socket_getmyname (this, myaddr, addrlen); +        } + +out: +        return ret; +} + + +struct rpc_transport_ops tops = { +        .listen             = socket_listen, +        .connect            = socket_connect, +        .disconnect         = socket_disconnect, +        .submit_request     = socket_submit_request, +        .submit_reply       = socket_submit_reply, +        .get_peername       = socket_getpeername, +        .get_peeraddr       = socket_getpeeraddr, +        .get_myname         = socket_getmyname, +        .get_myaddr         = socket_getmyaddr +}; + + +int +socket_init (rpc_transport_t *this) +{ +        socket_private_t *priv = NULL; +        gf_boolean_t      tmp_bool = 0; +        uint64_t          windowsize = GF_DEFAULT_SOCKET_WINDOW_SIZE; +        char             *optstr = NULL; + +        if (this->private) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "double init attempted"); +                return -1; +        } + +        priv = GF_CALLOC (1, sizeof (*priv), gf_common_mt_socket_private_t); +        if (!priv) { +                gf_log (this->name, GF_LOG_ERROR, +                        "calloc (1, %"GF_PRI_SIZET") returned NULL", +			sizeof (*priv)); +                return -1; +        } + +        pthread_mutex_init (&priv->lock, NULL); + +        priv->sock = -1; +        priv->idx = -1; +        priv->connected = -1; + +        INIT_LIST_HEAD (&priv->ioq); + +        if (dict_get (this->options, "non-blocking-io")) { +                optstr = data_to_str (dict_get (this->options, +                                                "non-blocking-io")); + +                if (gf_string2boolean (optstr, &tmp_bool) == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "'non-blocking-io' takes only boolean options," +				" not taking any action"); +                        tmp_bool = 1; +                } +                priv->bio = 0; +                if (!tmp_bool) { +                        priv->bio = 1; +                        gf_log (this->name, GF_LOG_WARNING, +                                "disabling non-blocking IO"); +                } +        } + +        optstr = NULL; + +        // By default, we enable NODELAY +        priv->nodelay = 1; +        if (dict_get (this->options, "transport.socket.nodelay")) { +                optstr = data_to_str (dict_get (this->options, +                                                "transport.socket.nodelay")); + +                if (gf_string2boolean (optstr, &tmp_bool) == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "'transport.socket.nodelay' takes only " +                                "boolean options, not taking any action"); +                        tmp_bool = 1; +                } +                if (!tmp_bool) { +                        priv->nodelay = 0; +                        gf_log (this->name, GF_LOG_DEBUG, +                                "disabling nodelay"); +                } +        } + + +        optstr = NULL; +        if (dict_get_str (this->options, "transport.window-size", +                          &optstr) == 0) { +                if (gf_string2bytesize (optstr, &windowsize) != 0) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "invalid number format: %s", optstr); +                        return -1; +                } +        } + +        optstr = NULL; + +        if (dict_get_str (this->options, "transport.socket.lowlat", +                          &optstr) == 0) { +                priv->lowlat = 1; +        } + +        priv->windowsize = (int)windowsize; +        this->private = priv; + +        return 0; +} + + +void +fini (rpc_transport_t *this) +{ +        socket_private_t *priv = this->private; + +        gf_log (this->name, GF_LOG_TRACE, +                "transport %p destroyed", this); + +        pthread_mutex_destroy (&priv->lock); + +        GF_FREE (this->name); +        GF_FREE (priv); +} + + +int32_t +init (rpc_transport_t *this) +{ +        int ret = -1; + +        ret = socket_init (this); + +        if (ret == -1) { +                gf_log (this->name, GF_LOG_DEBUG, "socket_init() failed"); +        } + +        return ret; +} + +struct volume_options options[] = { +        { .key   = {"remote-port", +                    "transport.remote-port", +                    "transport.socket.remote-port"}, +          .type  = GF_OPTION_TYPE_INT +        }, +        { .key   = {"transport.socket.listen-port", "listen-port"}, +          .type  = GF_OPTION_TYPE_INT +        }, +        { .key   = {"transport.socket.bind-address", "bind-address" }, +          .type  = GF_OPTION_TYPE_INTERNET_ADDRESS +        }, +        { .key   = {"transport.socket.connect-path", "connect-path"}, +          .type  = GF_OPTION_TYPE_ANY +        }, +        { .key   = {"transport.socket.bind-path", "bind-path"}, +          .type  = GF_OPTION_TYPE_ANY +        }, +        { .key   = {"transport.socket.listen-path", "listen-path"}, +          .type  = GF_OPTION_TYPE_ANY +        }, +        { .key   = { "transport.address-family", +                     "address-family" }, +          .value = {"inet", "inet6", "inet/inet6", "inet6/inet", +                    "unix", "inet-sdp" }, +          .type  = GF_OPTION_TYPE_STR +        }, + +        { .key   = {"non-blocking-io"}, +          .type  = GF_OPTION_TYPE_BOOL +        }, +        { .key   = {"transport.window-size"}, +          .type  = GF_OPTION_TYPE_SIZET, +          .min   = GF_MIN_SOCKET_WINDOW_SIZE, +          .max   = GF_MAX_SOCKET_WINDOW_SIZE, +        }, +        { .key   = {"transport.socket.nodelay"}, +          .type  = GF_OPTION_TYPE_BOOL +        }, +        { .key   = {"transport.socket.lowlat"}, +          .type  = GF_OPTION_TYPE_BOOL +        }, +        { .key = {NULL} } +}; diff --git a/rpc/rpc-transport/socket/src/socket.h b/rpc/rpc-transport/socket/src/socket.h new file mode 100644 index 00000000000..aa31ee2a7ef --- /dev/null +++ b/rpc/rpc-transport/socket/src/socket.h @@ -0,0 +1,190 @@ +/* +  Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SOCKET_H +#define _SOCKET_H + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "event.h" +#include "rpc-transport.h" +#include "logging.h" +#include "dict.h" +#include "mem-pool.h" + +#ifndef MAX_IOVEC +#define MAX_IOVEC 16 +#endif /* MAX_IOVEC */ + +#define GF_DEFAULT_SOCKET_LISTEN_PORT 6969 + +/* This is the size set through setsockopt for + * both the TCP receive window size and the + * send buffer size. + * Till the time iobuf size becomes configurable, this size is set to include + * two iobufs + the GlusterFS protocol headers. + * Linux allows us to over-ride the max values for the system. + * Should we over-ride them? Because if we set a value larger than the default + * setsockopt will fail. Having larger values might be beneficial for + * IB links. + */ +#define GF_DEFAULT_SOCKET_WINDOW_SIZE   (512 * GF_UNIT_KB) +#define GF_MAX_SOCKET_WINDOW_SIZE       (1 * GF_UNIT_MB) +#define GF_MIN_SOCKET_WINDOW_SIZE       (128 * GF_UNIT_KB) + +typedef enum { +        SP_STATE_NADA = 0, +        SP_STATE_COMPLETE, +        SP_STATE_READING_FRAGHDR, +        SP_STATE_READ_FRAGHDR, +        SP_STATE_READING_FRAG, +} sp_rpcrecord_state_t; + +typedef enum { +        SP_STATE_RPCFRAG_INIT, +        SP_STATE_READING_MSGTYPE, +        SP_STATE_READ_MSGTYPE, +} sp_rpcfrag_state_t; + +typedef enum { +        SP_STATE_SIMPLE_MSG_INIT, +        SP_STATE_READING_SIMPLE_MSG, +} sp_rpcfrag_simple_msg_state_t; + +typedef enum { +        SP_STATE_VECTORED_REQUEST_INIT, +        SP_STATE_READING_CREDBYTES, +        SP_STATE_READ_CREDBYTES,        /* read credential data. */ +        SP_STATE_READING_VERFBYTES, +        SP_STATE_READ_VERFBYTES,        /* read verifier data */ +        SP_STATE_READING_PROG, +} sp_rpcfrag_vectored_request_state_t; + +typedef enum { +        SP_STATE_REQUEST_HEADER_INIT, +        SP_STATE_READING_RPCHDR1, +        SP_STATE_READ_RPCHDR1,     /* read msg from beginning till and +                                       * including credlen +                                       */ +} sp_rpcfrag_request_header_state_t; + +struct ioq { +        union { +                struct list_head list; +                struct { +                        struct ioq    *next; +                        struct ioq    *prev; +                }; +        }; + +        struct iovec       vector[MAX_IOVEC]; +        int                count; +        struct iovec      *pending_vector; +        int                pending_count; +        struct iobref     *iobref; +}; + +typedef struct { +        sp_rpcfrag_request_header_state_t header_state; +        sp_rpcfrag_vectored_request_state_t vector_state; +} sp_rpcfrag_request_state_t; + +typedef enum { +        SP_STATE_VECTORED_REPLY_STATUS_INIT, +        SP_STATE_READING_REPLY_STATUS, +        SP_STATE_READ_REPLY_STATUS, +} sp_rpcfrag_vectored_reply_status_state_t; + +typedef enum { +        SP_STATE_ACCEPTED_SUCCESS_REPLY_INIT, +        SP_STATE_READING_PROC_HEADER, +        SP_STATE_READ_PROC_HEADER, +} sp_rpcfrag_vectored_reply_accepted_success_state_t; + +typedef enum { +        SP_STATE_ACCEPTED_REPLY_INIT, +        SP_STATE_READING_REPLY_VERFLEN, +        SP_STATE_READ_REPLY_VERFLEN, +        SP_STATE_READING_REPLY_VERFBYTES, +        SP_STATE_READ_REPLY_VERFBYTES, +} sp_rpcfrag_vectored_reply_accepted_state_t; + +typedef struct { +        uint32_t accept_status; +        sp_rpcfrag_vectored_reply_status_state_t status_state; +        sp_rpcfrag_vectored_reply_accepted_state_t accepted_state; +        sp_rpcfrag_vectored_reply_accepted_success_state_t accepted_success_state; +} sp_rpcfrag_vectored_reply_state_t; + +typedef struct { +        int32_t                sock; +        int32_t                idx; +        unsigned char          connected; // -1 = not connected. 0 = in progress. 1 = connected +        char                   bio; +        char                   connect_finish_log; +        char                   submit_log; +        union { +                struct list_head     ioq; +                struct { +                        struct ioq        *ioq_next; +                        struct ioq        *ioq_prev; +                }; +        }; +        struct { +                sp_rpcrecord_state_t  record_state; +                struct { +                        char         *fragcurrent; +                        uint32_t      bytes_read; +                        uint32_t      remaining_size; +                        struct iovec  vector; +                        struct iovec *pending_vector; +                        union { +                                sp_rpcfrag_request_state_t        request; +                                sp_rpcfrag_vectored_reply_state_t reply; +                        } call_body; + +                        sp_rpcfrag_simple_msg_state_t     simple_state; +                        sp_rpcfrag_state_t state; +                } frag; +                struct iobuf        *iobuf; +                size_t               iobuf_size; +                struct iovec         vector[2]; +                int                  count; +                struct iobuf        *vectoriob; +                size_t               vectoriob_size; +                rpc_request_info_t  *request_info; +                struct iovec        *pending_vector; +                int                  pending_count; +                uint32_t             fraghdr; +                char                 complete_record; +                msg_type_t           msg_type; +                size_t               total_bytes_read; +        } incoming; +        pthread_mutex_t        lock; +        int                    windowsize; +        char                   lowlat; +        char                   nodelay; +} socket_private_t; + + +#endif  | 
