diff options
Diffstat (limited to 'rpc/rpc-lib/src')
| -rw-r--r-- | rpc/rpc-lib/src/Makefile.am | 14 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/auth-glusterfs.c | 290 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/auth-null.c | 25 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/auth-unix.c | 25 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/protocol-common.h | 261 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-clnt.c | 1110 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-clnt.h | 184 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-common.c | 115 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-drc.c | 872 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-drc.h | 104 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-transport.c | 1164 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpc-transport.h | 208 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc-auth.c | 219 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc-common.h | 89 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc.c | 2592 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc.h | 290 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/xdr-common.h | 94 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/xdr-rpc.c | 101 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/xdr-rpc.h | 41 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/xdr-rpcclnt.c | 50 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/xdr-rpcclnt.h | 25 |
21 files changed, 4636 insertions, 3237 deletions
diff --git a/rpc/rpc-lib/src/Makefile.am b/rpc/rpc-lib/src/Makefile.am index 9e37797bd..f19c3c8a4 100644 --- a/rpc/rpc-lib/src/Makefile.am +++ b/rpc/rpc-lib/src/Makefile.am @@ -1,17 +1,19 @@ lib_LTLIBRARIES = libgfrpc.la -libgfrpc_la_LDFLAGS = -module -avoidversion libgfrpc_la_SOURCES = auth-unix.c rpcsvc-auth.c rpcsvc.c auth-null.c \ rpc-transport.c xdr-rpc.c xdr-rpcclnt.c rpc-clnt.c auth-glusterfs.c \ - rpc-common.c + rpc-drc.c + libgfrpc_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la noinst_HEADERS = rpcsvc.h rpc-transport.h xdr-common.h xdr-rpc.h xdr-rpcclnt.h \ - rpc-clnt.h rpcsvc-common.h protocol-common.h + rpc-clnt.h rpcsvc-common.h protocol-common.h rpc-drc.h -AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ - -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) \ +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ -I$(top_srcdir)/rpc/xdr/src \ - -DRPC_TRANSPORTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport\" + -DRPC_TRANSPORTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport\" \ + -I$(top_srcdir)/contrib/rbtree + +AM_CFLAGS = -Wall $(GF_CFLAGS) CLEANFILES = *~ diff --git a/rpc/rpc-lib/src/auth-glusterfs.c b/rpc/rpc-lib/src/auth-glusterfs.c index c6736a1d3..db488434c 100644 --- a/rpc/rpc-lib/src/auth-glusterfs.c +++ b/rpc/rpc-lib/src/auth-glusterfs.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ @@ -29,94 +20,9 @@ #include "dict.h" #include "xdr-rpc.h" #include "xdr-common.h" +#include "rpc-common-xdr.h" -bool_t -xdr_auth_glusterfs_parms (XDR *xdrs, auth_glusterfs_parms *objp) -{ - register int32_t *buf; - - int i; - - if (xdrs->x_op == XDR_ENCODE) { - if (!xdr_u_quad_t (xdrs, &objp->lk_owner)) - return FALSE; - buf = XDR_INLINE (xdrs, (4 + 16 )* BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_int (xdrs, &objp->pid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->uid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->gid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->ngrps)) - return FALSE; - if (!xdr_vector (xdrs, (char *)objp->groups, 16, - sizeof (u_int), (xdrproc_t) xdr_u_int)) - return FALSE; - } else { - IXDR_PUT_U_LONG(buf, objp->pid); - IXDR_PUT_U_LONG(buf, objp->uid); - IXDR_PUT_U_LONG(buf, objp->gid); - IXDR_PUT_U_LONG(buf, objp->ngrps); - { - register u_int *genp; - - for (i = 0, genp = objp->groups; - i < 16; ++i) { - IXDR_PUT_U_LONG(buf, *genp++); - } - } - } - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - if (!xdr_u_quad_t (xdrs, &objp->lk_owner)) - return FALSE; - buf = XDR_INLINE (xdrs, (4 + 16 )* BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_int (xdrs, &objp->pid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->uid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->gid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->ngrps)) - return FALSE; - if (!xdr_vector (xdrs, (char *)objp->groups, 16, - sizeof (u_int), (xdrproc_t) xdr_u_int)) - return FALSE; - } else { - objp->pid = IXDR_GET_U_LONG(buf); - objp->uid = IXDR_GET_U_LONG(buf); - objp->gid = IXDR_GET_U_LONG(buf); - objp->ngrps = IXDR_GET_U_LONG(buf); - { - register u_int *genp; - - for (i = 0, genp = objp->groups; - i < 16; ++i) { - *genp++ = IXDR_GET_U_LONG(buf); - } - } - } - return TRUE; - } - - if (!xdr_u_quad_t (xdrs, &objp->lk_owner)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->pid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->uid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->gid)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->ngrps)) - return FALSE; - if (!xdr_vector (xdrs, (char *)objp->groups, 16, - sizeof (u_int), (xdrproc_t) xdr_u_int)) - return FALSE; - return TRUE; -} - +/* V1 */ ssize_t xdr_to_glusterfs_auth (char *buf, struct auth_glusterfs_parms *req) @@ -130,6 +36,8 @@ xdr_to_glusterfs_auth (char *buf, struct auth_glusterfs_parms *req) xdrmem_create (&xdr, buf, sizeof (struct auth_glusterfs_parms), XDR_DECODE); if (!xdr_auth_glusterfs_parms (&xdr, req)) { + gf_log ("", GF_LOG_WARNING, + "failed to decode glusterfs parameters"); ret = -1; goto ret; } @@ -144,7 +52,7 @@ auth_glusterfs_request_init (rpcsvc_request_t *req, void *priv) { if (!req) return -1; - memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES); + memset (req->verf.authdata, 0, GF_MAX_AUTH_BYTES); req->verf.datalen = 0; req->verf.flavour = AUTH_NULL; @@ -153,14 +61,20 @@ auth_glusterfs_request_init (rpcsvc_request_t *req, void *priv) int auth_glusterfs_authenticate (rpcsvc_request_t *req, void *priv) { - int ret = RPCSVC_AUTH_REJECT; struct auth_glusterfs_parms au = {0,}; + int ret = RPCSVC_AUTH_REJECT; + int j = 0; + int i = 0; + int gidcount = 0; + if (!req) return ret; ret = xdr_to_glusterfs_auth (req->cred.authdata, &au); if (ret == -1) { + gf_log ("", GF_LOG_WARNING, + "failed to decode glusterfs credentials"); ret = RPCSVC_AUTH_REJECT; goto err; } @@ -168,19 +82,51 @@ int auth_glusterfs_authenticate (rpcsvc_request_t *req, void *priv) req->pid = au.pid; req->uid = au.uid; req->gid = au.gid; - req->lk_owner = au.lk_owner; + req->lk_owner.len = 8; + { + for (i = 0; i < req->lk_owner.len; i++, j += 8) + req->lk_owner.data[i] = (char)((au.lk_owner >> j) & 0xff); + } req->auxgidcount = au.ngrps; + if (req->auxgidcount > 16) { + gf_log ("", GF_LOG_WARNING, + "more than 16 aux gids found, failing authentication"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + if (req->auxgidcount > SMALL_GROUP_COUNT) { + req->auxgidlarge = GF_CALLOC(req->auxgidcount, + sizeof(req->auxgids[0]), + gf_common_mt_auxgids); + req->auxgids = req->auxgidlarge; + } else { + req->auxgids = req->auxgidsmall; + } + + if (!req->auxgids) { + gf_log ("auth-glusterfs", GF_LOG_WARNING, + "cannot allocate gid list"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + for (gidcount = 0; gidcount < au.ngrps; ++gidcount) + req->auxgids[gidcount] = au.groups[gidcount]; + + RPC_AUTH_ROOT_SQUASH(req); + gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" - ", gid: %d, owner: %"PRId64, - req->pid, req->uid, req->gid, req->lk_owner); + ", gid: %d, owner: %s", + req->pid, req->uid, req->gid, lkowner_utoa (&req->lk_owner)); ret = RPCSVC_AUTH_ACCEPT; err: return ret; } rpcsvc_auth_ops_t auth_glusterfs_ops = { - .conn_init = NULL, + .transport_init = NULL, .request_init = auth_glusterfs_request_init, .authenticate = auth_glusterfs_authenticate }; @@ -198,3 +144,133 @@ rpcsvc_auth_glusterfs_init (rpcsvc_t *svc, dict_t *options) { return &rpcsvc_auth_glusterfs; } + +/* V2 */ + +ssize_t +xdr_to_glusterfs_auth_v2 (char *buf, struct auth_glusterfs_parms_v2 *req) +{ + XDR xdr; + ssize_t ret = -1; + + if ((!buf) || (!req)) + return -1; + + xdrmem_create (&xdr, buf, GF_MAX_AUTH_BYTES, XDR_DECODE); + if (!xdr_auth_glusterfs_parms_v2 (&xdr, req)) { + gf_log ("", GF_LOG_WARNING, + "failed to decode glusterfs v2 parameters"); + ret = -1; + goto ret; + } + + ret = (((size_t)(&xdr)->x_private) - ((size_t)(&xdr)->x_base)); +ret: + return ret; + +} +int +auth_glusterfs_v2_request_init (rpcsvc_request_t *req, void *priv) +{ + if (!req) + return -1; + memset (req->verf.authdata, 0, GF_MAX_AUTH_BYTES); + req->verf.datalen = 0; + req->verf.flavour = AUTH_NULL; + + return 0; +} + +int auth_glusterfs_v2_authenticate (rpcsvc_request_t *req, void *priv) +{ + struct auth_glusterfs_parms_v2 au = {0,}; + int ret = RPCSVC_AUTH_REJECT; + int i = 0; + + if (!req) + return ret; + + ret = xdr_to_glusterfs_auth_v2 (req->cred.authdata, &au); + if (ret == -1) { + gf_log ("", GF_LOG_WARNING, + "failed to decode glusterfs credentials"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + req->pid = au.pid; + req->uid = au.uid; + req->gid = au.gid; + req->lk_owner.len = au.lk_owner.lk_owner_len; + req->auxgidcount = au.groups.groups_len; + + if (req->auxgidcount > GF_MAX_AUX_GROUPS) { + gf_log ("", GF_LOG_WARNING, + "more than max aux gids found (%d) , truncating it " + "to %d and continuing", au.groups.groups_len, + GF_MAX_AUX_GROUPS); + req->auxgidcount = GF_MAX_AUX_GROUPS; + } + + if (req->lk_owner.len > GF_MAX_LOCK_OWNER_LEN) { + gf_log ("", GF_LOG_WARNING, + "lkowner field > 1k, failing authentication"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + if (req->auxgidcount > SMALL_GROUP_COUNT) { + req->auxgidlarge = GF_CALLOC(req->auxgidcount, + sizeof(req->auxgids[0]), + gf_common_mt_auxgids); + req->auxgids = req->auxgidlarge; + } else { + req->auxgids = req->auxgidsmall; + } + + if (!req->auxgids) { + gf_log ("auth-glusterfs-v2", GF_LOG_WARNING, + "cannot allocate gid list"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + for (i = 0; i < req->auxgidcount; ++i) + req->auxgids[i] = au.groups.groups_val[i]; + + for (i = 0; i < au.lk_owner.lk_owner_len; ++i) + req->lk_owner.data[i] = au.lk_owner.lk_owner_val[i]; + + RPC_AUTH_ROOT_SQUASH(req); + + gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" + ", gid: %d, owner: %s", + req->pid, req->uid, req->gid, lkowner_utoa (&req->lk_owner)); + ret = RPCSVC_AUTH_ACCEPT; +err: + /* TODO: instead use alloca() for these variables */ + free (au.groups.groups_val); + free (au.lk_owner.lk_owner_val); + + return ret; +} + +rpcsvc_auth_ops_t auth_glusterfs_ops_v2 = { + .transport_init = NULL, + .request_init = auth_glusterfs_v2_request_init, + .authenticate = auth_glusterfs_v2_authenticate +}; + +rpcsvc_auth_t rpcsvc_auth_glusterfs_v2 = { + .authname = "AUTH_GLUSTERFS-v2", + .authnum = AUTH_GLUSTERFS_v2, + .authops = &auth_glusterfs_ops_v2, + .authprivate = NULL +}; + + +rpcsvc_auth_t * +rpcsvc_auth_glusterfs_v2_init (rpcsvc_t *svc, dict_t *options) +{ + return &rpcsvc_auth_glusterfs_v2; +} diff --git a/rpc/rpc-lib/src/auth-null.c b/rpc/rpc-lib/src/auth-null.c index a2581a171..ebdcc8ff8 100644 --- a/rpc/rpc-lib/src/auth-null.c +++ b/rpc/rpc-lib/src/auth-null.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ @@ -34,10 +25,10 @@ auth_null_request_init (rpcsvc_request_t *req, void *priv) if (!req) return -1; - memset (req->cred.authdata, 0, RPCSVC_MAX_AUTH_BYTES); + memset (req->cred.authdata, 0, GF_MAX_AUTH_BYTES); req->cred.datalen = 0; - memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES); + memset (req->verf.authdata, 0, GF_MAX_AUTH_BYTES); req->verf.datalen = 0; return 0; @@ -50,7 +41,7 @@ int auth_null_authenticate (rpcsvc_request_t *req, void *priv) } rpcsvc_auth_ops_t auth_null_ops = { - .conn_init = NULL, + .transport_init = NULL, .request_init = auth_null_request_init, .authenticate = auth_null_authenticate }; diff --git a/rpc/rpc-lib/src/auth-unix.c b/rpc/rpc-lib/src/auth-unix.c index aed3c1f9d..fa5f0576e 100644 --- a/rpc/rpc-lib/src/auth-unix.c +++ b/rpc/rpc-lib/src/auth-unix.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ @@ -35,7 +26,7 @@ auth_unix_request_init (rpcsvc_request_t *req, void *priv) { if (!req) return -1; - memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES); + memset (req->verf.authdata, 0, GF_MAX_AUTH_BYTES); req->verf.datalen = 0; req->verf.flavour = AUTH_NULL; @@ -51,9 +42,11 @@ int auth_unix_authenticate (rpcsvc_request_t *req, void *priv) if (!req) return ret; + req->auxgids = req->auxgidsmall; ret = xdr_to_auth_unix_cred (req->cred.authdata, req->cred.datalen, &aup, machname, req->auxgids); if (ret == -1) { + gf_log ("", GF_LOG_WARNING, "failed to decode unix credentials"); ret = RPCSVC_AUTH_REJECT; goto err; } @@ -70,7 +63,7 @@ err: } rpcsvc_auth_ops_t auth_unix_ops = { - .conn_init = NULL, + .transport_init = NULL, .request_init = auth_unix_request_init, .authenticate = auth_unix_authenticate }; diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 7cff79be3..8bef906cc 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2007-2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _PROTOCOL_COMMON_H @@ -64,6 +55,10 @@ enum gf_fop_procnum { GFS3_OP_READDIRP, GFS3_OP_RELEASE, GFS3_OP_RELEASEDIR, + GFS3_OP_FREMOVEXATTR, + GFS3_OP_FALLOCATE, + GFS3_OP_DISCARD, + GFS3_OP_ZEROFILL, GFS3_OP_MAXVALUE, } ; @@ -72,70 +67,198 @@ enum gf_handshake_procnum { GF_HNDSK_SETVOLUME, GF_HNDSK_GETSPEC, GF_HNDSK_PING, + GF_HNDSK_SET_LK_VER, + GF_HNDSK_EVENT_NOTIFY, GF_HNDSK_MAXVALUE, }; -enum gf_mgmt_procnum_ { - GD_MGMT_NULL, /* 0 */ - GD_MGMT_PROBE_QUERY, - GD_MGMT_FRIEND_ADD, - GD_MGMT_CLUSTER_LOCK, - GD_MGMT_CLUSTER_UNLOCK, - GD_MGMT_STAGE_OP, - GD_MGMT_COMMIT_OP, - GD_MGMT_FRIEND_REMOVE, - GD_MGMT_FRIEND_UPDATE, - GD_MGMT_CLI_PROBE, - GD_MGMT_CLI_DEPROBE, - GD_MGMT_CLI_LIST_FRIENDS, - GD_MGMT_CLI_CREATE_VOLUME, - GD_MGMT_CLI_GET_VOLUME, - GD_MGMT_CLI_DELETE_VOLUME, - GD_MGMT_CLI_START_VOLUME, - GD_MGMT_CLI_STOP_VOLUME, - GD_MGMT_CLI_RENAME_VOLUME, - GD_MGMT_CLI_DEFRAG_VOLUME, - GD_MGMT_CLI_SET_VOLUME, - GD_MGMT_CLI_ADD_BRICK, - GD_MGMT_CLI_REMOVE_BRICK, - GD_MGMT_CLI_REPLACE_BRICK, - GD_MGMT_MAXVALUE, +enum gf_pmap_procnum { + GF_PMAP_NULL = 0, + GF_PMAP_PORTBYBRICK, + GF_PMAP_BRICKBYPORT, + GF_PMAP_SIGNUP, + GF_PMAP_SIGNIN, + GF_PMAP_SIGNOUT, + GF_PMAP_MAXVALUE, +}; + +enum gf_pmap_port_type { + GF_PMAP_PORT_FREE = 0, + GF_PMAP_PORT_FOREIGN, + GF_PMAP_PORT_LEASED, + GF_PMAP_PORT_NONE, + GF_PMAP_PORT_BRICKSERVER, +}; +typedef enum gf_pmap_port_type gf_pmap_port_type_t; + +enum gf_probe_resp { + GF_PROBE_SUCCESS, + GF_PROBE_LOCALHOST, + GF_PROBE_FRIEND, + GF_PROBE_ANOTHER_CLUSTER, + GF_PROBE_VOLUME_CONFLICT, + GF_PROBE_SAME_UUID, + GF_PROBE_UNKNOWN_PEER, + GF_PROBE_ADD_FAILED, + GF_PROBE_QUORUM_NOT_MET +}; + +enum gf_deprobe_resp { + GF_DEPROBE_SUCCESS, + GF_DEPROBE_LOCALHOST, + GF_DEPROBE_NOT_FRIEND, + GF_DEPROBE_BRICK_EXIST, + GF_DEPROBE_FRIEND_DOWN, + GF_DEPROBE_QUORUM_NOT_MET, +}; + +enum gf_cbk_procnum { + GF_CBK_NULL = 0, + GF_CBK_FETCHSPEC, + GF_CBK_INO_FLUSH, + GF_CBK_EVENT_NOTIFY, + GF_CBK_MAXVALUE, +}; + +enum gluster_cli_procnum { + GLUSTER_CLI_NULL, /* 0 */ + GLUSTER_CLI_PROBE, + GLUSTER_CLI_DEPROBE, + GLUSTER_CLI_LIST_FRIENDS, + GLUSTER_CLI_CREATE_VOLUME, + GLUSTER_CLI_GET_VOLUME, + GLUSTER_CLI_GET_NEXT_VOLUME, + GLUSTER_CLI_DELETE_VOLUME, + GLUSTER_CLI_START_VOLUME, + GLUSTER_CLI_STOP_VOLUME, + GLUSTER_CLI_RENAME_VOLUME, + GLUSTER_CLI_DEFRAG_VOLUME, + GLUSTER_CLI_SET_VOLUME, + GLUSTER_CLI_ADD_BRICK, + GLUSTER_CLI_REMOVE_BRICK, + GLUSTER_CLI_REPLACE_BRICK, + GLUSTER_CLI_LOG_ROTATE, + GLUSTER_CLI_GETSPEC, + GLUSTER_CLI_PMAP_PORTBYBRICK, + GLUSTER_CLI_SYNC_VOLUME, + GLUSTER_CLI_RESET_VOLUME, + GLUSTER_CLI_FSM_LOG, + GLUSTER_CLI_GSYNC_SET, + GLUSTER_CLI_PROFILE_VOLUME, + GLUSTER_CLI_QUOTA, + GLUSTER_CLI_TOP_VOLUME, + GLUSTER_CLI_GETWD, + GLUSTER_CLI_STATUS_VOLUME, + GLUSTER_CLI_STATUS_ALL, + GLUSTER_CLI_MOUNT, + GLUSTER_CLI_UMOUNT, + GLUSTER_CLI_HEAL_VOLUME, + GLUSTER_CLI_STATEDUMP_VOLUME, + GLUSTER_CLI_LIST_VOLUME, + GLUSTER_CLI_CLRLOCKS_VOLUME, + GLUSTER_CLI_UUID_RESET, + GLUSTER_CLI_UUID_GET, + GLUSTER_CLI_COPY_FILE, + GLUSTER_CLI_SYS_EXEC, + GLUSTER_CLI_SNAP, + GLUSTER_CLI_MAXVALUE, +}; + +enum glusterd_mgmt_procnum { + GLUSTERD_MGMT_NULL, /* 0 */ + GLUSTERD_MGMT_CLUSTER_LOCK, + GLUSTERD_MGMT_CLUSTER_UNLOCK, + GLUSTERD_MGMT_STAGE_OP, + GLUSTERD_MGMT_COMMIT_OP, + GLUSTERD_MGMT_MAXVALUE, }; -typedef enum gf_mgmt_procnum_ gf_mgmt_procnum; - -enum gf_cli_procnum { - GF1_CLI_NULL = GD_MGMT_MAXVALUE+1, /* 0 */ - GF1_CLI_PROBE, - GF1_CLI_DEPROBE, - GF1_CLI_LIST_FRIENDS, - GF1_CLI_CREATE_VOLUME, - GF1_CLI_GET_VOLUME, - GF1_CLI_DELETE_VOLUME, - GF1_CLI_START_VOLUME, - GF1_CLI_STOP_VOLUME, - GF1_CLI_RENAME_VOLUME, - GF1_CLI_DEFRAG_VOLUME, - GF1_CLI_SET_VOLUME, - GF1_CLI_ADD_BRICK, - GF1_CLI_REMOVE_BRICK, - GF1_CLI_REPLACE_BRICK, - GF1_CLI_MAXVALUE, +enum glusterd_friend_procnum { + GLUSTERD_FRIEND_NULL, /* 0 */ + GLUSTERD_PROBE_QUERY, + GLUSTERD_FRIEND_ADD, + GLUSTERD_FRIEND_REMOVE, + GLUSTERD_FRIEND_UPDATE, + GLUSTERD_FRIEND_MAXVALUE, }; -#define GLUSTER3_1_FOP_PROGRAM 1298437 /* Completely random */ -#define GLUSTER3_1_FOP_VERSION 310 /* 3.1.0 */ -#define GLUSTER3_1_FOP_PROCCNT GFS3_OP_MAXVALUE +enum glusterd_brick_procnum { + GLUSTERD_BRICK_NULL, /* 0 */ + GLUSTERD_BRICK_TERMINATE, + GLUSTERD_BRICK_XLATOR_INFO, + GLUSTERD_BRICK_XLATOR_OP, + GLUSTERD_BRICK_STATUS, + GLUSTERD_BRICK_OP, + GLUSTERD_BRICK_XLATOR_DEFRAG, + GLUSTERD_NODE_PROFILE, + GLUSTERD_NODE_STATUS, + GLUSTERD_VOLUME_BARRIER_OP, + GLUSTERD_BRICK_MAXVALUE, +}; + +enum glusterd_mgmt_hndsk_procnum { + GD_MGMT_HNDSK_NULL, + GD_MGMT_HNDSK_VERSIONS, + GD_MGMT_HNDSK_VERSIONS_ACK, + GD_MGMT_HNDSK_MAXVALUE, +}; + +typedef enum { + GF_AFR_OP_INVALID, + GF_AFR_OP_HEAL_INDEX, + GF_AFR_OP_HEAL_FULL, + GF_AFR_OP_INDEX_SUMMARY, + GF_AFR_OP_HEALED_FILES, + GF_AFR_OP_HEAL_FAILED_FILES, + GF_AFR_OP_SPLIT_BRAIN_FILES, + GF_AFR_OP_STATISTICS, + GF_AFR_OP_STATISTICS_HEAL_COUNT, + GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA, +} gf_xl_afr_op_t ; + +enum glusterd_mgmt_v3_procnum { + GLUSTERD_MGMT_V3_NULL, /* 0 */ + GLUSTERD_MGMT_V3_LOCK, + GLUSTERD_MGMT_V3_PRE_VALIDATE, + GLUSTERD_MGMT_V3_BRICK_OP, + GLUSTERD_MGMT_V3_COMMIT, + GLUSTERD_MGMT_V3_POST_VALIDATE, + GLUSTERD_MGMT_V3_UNLOCK, + GLUSTERD_MGMT_V3_MAXVALUE, +}; + +#define GLUSTER_HNDSK_PROGRAM 14398633 /* Completely random */ +#define GLUSTER_HNDSK_VERSION 2 /* 0.0.2 */ + +#define GLUSTER_PMAP_PROGRAM 34123456 +#define GLUSTER_PMAP_VERSION 1 + +#define GLUSTER_CBK_PROGRAM 52743234 /* Completely random */ +#define GLUSTER_CBK_VERSION 1 /* 0.0.1 */ + +#define GLUSTER_FOP_PROGRAM 1298437 /* Completely random */ +#define GLUSTER_FOP_VERSION 330 /* 3.3.0 */ +#define GLUSTER_FOP_PROCCNT GFS3_OP_MAXVALUE + +/* Second version */ +#define GD_MGMT_PROGRAM 1238433 /* Completely random */ +#define GD_MGMT_VERSION 2 /* 0.0.2 */ + +#define GD_FRIEND_PROGRAM 1238437 /* Completely random */ +#define GD_FRIEND_VERSION 2 /* 0.0.2 */ + +#define GLUSTER_CLI_PROGRAM 1238463 /* Completely random */ +#define GLUSTER_CLI_VERSION 2 /* 0.0.2 */ -#define GLUSTERD1_MGMT_PROGRAM 1298433 /* Completely random */ -#define GLUSTERD1_MGMT_VERSION 1 /* 0.0.1 */ -#define GLUSTERD1_MGMT_PROCCNT GD_MGMT_MAXVALUE +#define GD_BRICK_PROGRAM 4867634 /*Completely random*/ +#define GD_BRICK_VERSION 2 -#define GLUSTER3_1_CLI_PROGRAM 1298433 /* Completely random */ -#define GLUSTER3_1_CLI_VERSION 1 /* 0.0.1 */ -#define GLUSTER3_1_CLI_PROCCNT GF1_CLI_MAXVALUE +/* Third version */ +#define GD_MGMT_V3_PROGRAM 2210013 /* Completely random */ +#define GD_MGMT_V3_VERSION 3 -#define GLUSTER_HNDSK_PROGRAM 14398633 /* Completely random */ -#define GLUSTER_HNDSK_VERSION 1 /* 0.0.1 */ +/* OP-VERSION handshake */ +#define GD_MGMT_HNDSK_PROGRAM 1239873 /* Completely random */ +#define GD_MGMT_HNDSK_VERSION 1 #endif /* !_PROTOCOL_COMMON_H */ diff --git a/rpc/rpc-lib/src/rpc-clnt.c b/rpc/rpc-lib/src/rpc-clnt.c index 9b0bfe33d..ac98a5c91 100644 --- a/rpc/rpc-lib/src/rpc-clnt.c +++ b/rpc/rpc-lib/src/rpc-clnt.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ @@ -23,10 +14,19 @@ #include "config.h" #endif +#define RPC_CLNT_DEFAULT_REQUEST_COUNT 512 + #include "rpc-clnt.h" +#include "byte-order.h" #include "xdr-rpcclnt.h" #include "rpc-transport.h" #include "protocol-common.h" +#include "mem-pool.h" +#include "xdr-rpc.h" +#include "rpc-common-xdr.h" + +void +rpc_clnt_reply_deinit (struct rpc_req *req, struct mem_pool *pool); uint64_t rpc_clnt_new_callid (struct rpc_clnt *clnt) @@ -61,33 +61,47 @@ __saved_frames_get_timedout (struct saved_frames *frames, uint32_t timeout, return bailout_frame; } +static int +_is_lock_fop (struct saved_frame *sframe) +{ + int fop = 0; + + if (SFRAME_GET_PROGNUM (sframe) == GLUSTER_FOP_PROGRAM && + SFRAME_GET_PROGVER (sframe) == GLUSTER_FOP_VERSION) + fop = SFRAME_GET_PROCNUM (sframe); + + return ((fop == GFS3_OP_LK) || + (fop == GFS3_OP_INODELK) || + (fop == GFS3_OP_FINODELK) || + (fop == GFS3_OP_ENTRYLK) || + (fop == GFS3_OP_FENTRYLK)); +} struct saved_frame * -__saved_frames_put (struct saved_frames *frames, void *frame, int32_t procnum, - rpc_clnt_prog_t *prog, fop_cbk_fn_t cbk, int64_t callid) +__saved_frames_put (struct saved_frames *frames, void *frame, + struct rpc_req *rpcreq) { struct saved_frame *saved_frame = NULL; - saved_frame = GF_CALLOC (1, sizeof (*saved_frame), - gf_common_mt_rpcclnt_savedframe_t); + saved_frame = mem_get (rpcreq->conn->rpc_clnt->saved_frames_pool); if (!saved_frame) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "out of memory"); goto out; } /* THIS should be saved and set back */ + memset (saved_frame, 0, sizeof (*saved_frame)); INIT_LIST_HEAD (&saved_frame->list); saved_frame->capital_this = THIS; saved_frame->frame = frame; - saved_frame->procnum = procnum; - saved_frame->callid = callid; - saved_frame->prog = prog; - saved_frame->cbkfn = cbk; - + saved_frame->rpcreq = rpcreq; gettimeofday (&saved_frame->saved_at, NULL); - list_add_tail (&saved_frame->list, &frames->sf.list); + if (_is_lock_fop (saved_frame)) + list_add_tail (&saved_frame->list, &frames->lk_sf.list); + else + list_add_tail (&saved_frame->list, &frames->sf.list); + frames->count++; out: @@ -99,9 +113,8 @@ void saved_frames_delete (struct saved_frame *saved_frame, rpc_clnt_connection_t *conn) { - if (!saved_frame || !conn) { - goto out; - } + GF_VALIDATE_OR_GOTO ("rpc-clnt", saved_frame, out); + GF_VALIDATE_OR_GOTO ("rpc-clnt", conn, out); pthread_mutex_lock (&conn->lock); { @@ -110,7 +123,12 @@ saved_frames_delete (struct saved_frame *saved_frame, } pthread_mutex_unlock (&conn->lock); - GF_FREE (saved_frame); + if (saved_frame->rpcreq != NULL) { + rpc_clnt_reply_deinit (saved_frame->rpcreq, + conn->rpc_clnt->reqpool); + } + + mem_put (saved_frame); out: return; } @@ -126,10 +144,8 @@ call_bail (void *data) struct saved_frame *saved_frame = NULL; struct saved_frame *trav = NULL; struct saved_frame *tmp = NULL; - struct tm frame_sent_tm; - char frame_sent[32] = {0,}; - struct timeval timeout = {0,}; - struct rpc_req req; + char frame_sent[256] = {0,}; + struct timespec timeout = {0,}; struct iovec iov = {0,}; GF_VALIDATE_OR_GOTO ("client", data, out); @@ -147,7 +163,7 @@ call_bail (void *data) call-once timer */ if (conn->timer) { timeout.tv_sec = 10; - timeout.tv_usec = 0; + timeout.tv_nsec = 0; gf_timer_call_cancel (clnt->ctx, conn->timer); conn->timer = gf_timer_call_after (clnt->ctx, @@ -156,8 +172,9 @@ call_bail (void *data) (void *) clnt); if (conn->timer == NULL) { - gf_log (conn->trans->name, GF_LOG_DEBUG, - "Cannot create bailout timer"); + gf_log (conn->trans->name, GF_LOG_WARNING, + "Cannot create bailout timer for %s", + conn->trans->peerinfo.identifier); } } @@ -174,21 +191,30 @@ call_bail (void *data) pthread_mutex_unlock (&conn->lock); list_for_each_entry_safe (trav, tmp, &list, list) { - localtime_r (&trav->saved_at.tv_sec, &frame_sent_tm); - strftime (frame_sent, 32, "%Y-%m-%d %H:%M:%S", &frame_sent_tm); + gf_time_fmt (frame_sent, sizeof frame_sent, + trav->saved_at.tv_sec, gf_timefmt_FT); + snprintf (frame_sent + strlen (frame_sent), + 256 - strlen (frame_sent), + ".%"GF_PRI_SUSECONDS, trav->saved_at.tv_usec); gf_log (conn->trans->name, GF_LOG_ERROR, - "bailing out frame type(%s) op(%s(%d)) sent = %s. " - "timeout = %d", - trav->prog->progname, (trav->prog->procnames) ? - trav->prog->procnames[trav->procnum] : "--", - trav->procnum, frame_sent, - conn->frame_timeout); - - trav->cbkfn (&req, &iov, 1, trav->frame); - + "bailing out frame type(%s) op(%s(%d)) xid = 0x%x " + "sent = %s. timeout = %d for %s", + trav->rpcreq->prog->progname, + (trav->rpcreq->prog->procnames) ? + trav->rpcreq->prog->procnames[trav->rpcreq->procnum] : + "--", + trav->rpcreq->procnum, trav->rpcreq->xid, frame_sent, + conn->frame_timeout, conn->trans->peerinfo.identifier); + + clnt = rpc_clnt_ref (clnt); + trav->rpcreq->rpc_status = -1; + trav->rpcreq->cbkfn (trav->rpcreq, &iov, 1, trav->frame); + + rpc_clnt_reply_deinit (trav->rpcreq, clnt->reqpool); + clnt = rpc_clnt_unref (clnt); list_del_init (&trav->list); - GF_FREE (trav); + mem_put (trav); } out: return; @@ -197,17 +223,17 @@ out: /* to be called with conn->lock held */ struct saved_frame * -__save_frame (struct rpc_clnt *rpc_clnt, call_frame_t *frame, int procnum, - rpc_clnt_prog_t *prog, fop_cbk_fn_t cbk, uint64_t callid) +__save_frame (struct rpc_clnt *rpc_clnt, call_frame_t *frame, + struct rpc_req *rpcreq) { rpc_clnt_connection_t *conn = NULL; - struct timeval timeout = {0, }; + struct timespec timeout = {0, }; struct saved_frame *saved_frame = NULL; conn = &rpc_clnt->conn; - saved_frame = __saved_frames_put (conn->saved_frames, frame, - procnum, prog, cbk, callid); + saved_frame = __saved_frames_put (conn->saved_frames, frame, rpcreq); + if (saved_frame == NULL) { goto out; } @@ -215,7 +241,7 @@ __save_frame (struct rpc_clnt *rpc_clnt, call_frame_t *frame, int procnum, /* TODO: make timeout configurable */ if (conn->timer == NULL) { timeout.tv_sec = 10; - timeout.tv_usec = 0; + timeout.tv_nsec = 0; conn->timer = gf_timer_call_after (rpc_clnt->ctx, timeout, call_bail, @@ -235,11 +261,11 @@ saved_frames_new (void) saved_frames = GF_CALLOC (1, sizeof (*saved_frames), gf_common_mt_rpcclnt_savedframe_t); if (!saved_frames) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "out of memory"); return NULL; } INIT_LIST_HEAD (&saved_frames->sf.list); + INIT_LIST_HEAD (&saved_frames->lk_sf.list); return saved_frames; } @@ -258,10 +284,18 @@ __saved_frame_copy (struct saved_frames *frames, int64_t callid, } list_for_each_entry (tmp, &frames->sf.list, list) { - if (tmp->callid == callid) { + if (tmp->rpcreq->xid == callid) { *saved_frame = *tmp; ret = 0; - break; + goto out; + } + } + + list_for_each_entry (tmp, &frames->lk_sf.list, list) { + if (tmp->rpcreq->xid == callid) { + *saved_frame = *tmp; + ret = 0; + goto out; } } @@ -277,14 +311,24 @@ __saved_frame_get (struct saved_frames *frames, int64_t callid) struct saved_frame *tmp = NULL; list_for_each_entry (tmp, &frames->sf.list, list) { - if (tmp->callid == callid) { + if (tmp->rpcreq->xid == callid) { list_del_init (&tmp->list); frames->count--; saved_frame = tmp; - break; + goto out; } } + list_for_each_entry (tmp, &frames->lk_sf.list, list) { + if (tmp->rpcreq->xid == callid) { + list_del_init (&tmp->list); + frames->count--; + saved_frame = tmp; + goto out; + } + } + +out: if (saved_frame) { THIS = saved_frame->capital_this; } @@ -292,40 +336,47 @@ __saved_frame_get (struct saved_frames *frames, int64_t callid) return saved_frame; } + void saved_frames_unwind (struct saved_frames *saved_frames) { struct saved_frame *trav = NULL; struct saved_frame *tmp = NULL; - struct tm *frame_sent_tm = NULL; - char timestr[256] = {0,}; - - struct rpc_req req; + char timestr[1024] = {0,}; struct iovec iov = {0,}; - memset (&req, 0, sizeof (req)); - - req.rpc_status = -1; + list_splice_init (&saved_frames->lk_sf.list, &saved_frames->sf.list); list_for_each_entry_safe (trav, tmp, &saved_frames->sf.list, list) { - frame_sent_tm = localtime (&trav->saved_at.tv_sec); - strftime (timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", - frame_sent_tm); - snprintf (timestr + strlen (timestr), sizeof(timestr) - strlen (timestr), + gf_time_fmt (timestr, sizeof timestr, + trav->saved_at.tv_sec, gf_timefmt_FT); + snprintf (timestr + strlen (timestr), + sizeof(timestr) - strlen (timestr), ".%"GF_PRI_SUSECONDS, trav->saved_at.tv_usec); - gf_log ("rpc-clnt", GF_LOG_ERROR, - "forced unwinding frame type(%s) op(%s(%d)) called at %s", - trav->prog->progname, (trav->prog->procnames) ? - trav->prog->procnames[trav->procnum] : "--", - trav->procnum, timestr); - + if (!trav->rpcreq || !trav->rpcreq->prog) + continue; + + gf_log_callingfn (trav->rpcreq->conn->trans->name, + GF_LOG_ERROR, + "forced unwinding frame type(%s) op(%s(%d)) " + "called at %s (xid=0x%x)", + trav->rpcreq->prog->progname, + ((trav->rpcreq->prog->procnames) ? + trav->rpcreq->prog->procnames[trav->rpcreq->procnum] + : "--"), + trav->rpcreq->procnum, timestr, + trav->rpcreq->xid); saved_frames->count--; - trav->cbkfn (&req, &iov, 1, trav->frame); + trav->rpcreq->rpc_status = -1; + trav->rpcreq->cbkfn (trav->rpcreq, &iov, 1, trav->frame); + + rpc_clnt_reply_deinit (trav->rpcreq, + trav->rpcreq->conn->rpc_clnt->reqpool); list_del_init (&trav->list); - GF_FREE (trav); + mem_put (trav); } } @@ -333,6 +384,9 @@ saved_frames_unwind (struct saved_frames *saved_frames) void saved_frames_destroy (struct saved_frames *frames) { + if (!frames) + return; + saved_frames_unwind (frames); GF_FREE (frames); @@ -344,7 +398,7 @@ rpc_clnt_reconnect (void *trans_ptr) { rpc_transport_t *trans = NULL; rpc_clnt_connection_t *conn = NULL; - struct timeval tv = {0, 0}; + struct timespec ts = {0, 0}; int32_t ret = 0; struct rpc_clnt *clnt = NULL; @@ -363,14 +417,15 @@ rpc_clnt_reconnect (void *trans_ptr) conn->reconnect = 0; if (conn->connected == 0) { - tv.tv_sec = 3; + ts.tv_sec = 3; + ts.tv_nsec = 0; gf_log (trans->name, GF_LOG_TRACE, "attempting reconnect"); - ret = rpc_transport_connect (trans); - + ret = rpc_transport_connect (trans, + conn->config.remote_port); conn->reconnect = - gf_timer_call_after (clnt->ctx, tv, + gf_timer_call_after (clnt->ctx, ts, rpc_clnt_reconnect, trans); } else { @@ -391,7 +446,7 @@ rpc_clnt_reconnect (void *trans_ptr) int rpc_clnt_fill_request_info (struct rpc_clnt *clnt, rpc_request_info_t *info) { - struct saved_frame saved_frame = {{}, 0}; + struct saved_frame saved_frame; int ret = -1; pthread_mutex_lock (&clnt->conn.lock); @@ -402,14 +457,16 @@ rpc_clnt_fill_request_info (struct rpc_clnt *clnt, rpc_request_info_t *info) pthread_mutex_unlock (&clnt->conn.lock); if (ret == -1) { - gf_log ("rpc-clnt", GF_LOG_CRITICAL, "cannot lookup the saved " + gf_log (clnt->conn.trans->name, GF_LOG_CRITICAL, + "cannot lookup the saved " "frame corresponding to xid (%d)", info->xid); goto out; } - info->prognum = saved_frame.prog->prognum; - info->procnum = saved_frame.procnum; - info->progver = saved_frame.prog->progver; + info->prognum = saved_frame.rpcreq->prog->prognum; + info->procnum = saved_frame.rpcreq->procnum; + info->progver = saved_frame.rpcreq->prog->progver; + info->rpc_req = saved_frame.rpcreq; info->rsp = saved_frame.rsp; ret = 0; @@ -417,6 +474,31 @@ out: return ret; } +int +rpc_clnt_reconnect_cleanup (rpc_clnt_connection_t *conn) +{ + struct rpc_clnt *clnt = NULL; + + if (!conn) { + goto out; + } + + clnt = conn->rpc_clnt; + + pthread_mutex_lock (&conn->lock); + { + + if (conn->reconnect) { + gf_timer_call_cancel (clnt->ctx, conn->reconnect); + conn->reconnect = NULL; + } + + } + pthread_mutex_unlock (&conn->lock); + +out: + return 0; +} /* * client_protocol_cleanup - cleanup function @@ -435,7 +517,7 @@ rpc_clnt_connection_cleanup (rpc_clnt_connection_t *conn) clnt = conn->rpc_clnt; - gf_log ("rpc-clnt", GF_LOG_DEBUG, + gf_log (conn->trans->name, GF_LOG_TRACE, "cleaning up state in transport object %p", conn->trans); pthread_mutex_lock (&conn->lock); @@ -449,11 +531,13 @@ rpc_clnt_connection_cleanup (rpc_clnt_connection_t *conn) conn->timer = NULL; } - if (conn->reconnect == NULL) { - /* :O This part is empty.. any thing missing? */ - } - conn->connected = 0; + + if (conn->ping_timer) { + gf_timer_call_cancel (clnt->ctx, conn->ping_timer); + conn->ping_timer = NULL; + conn->ping_started = 0; + } } pthread_mutex_unlock (&conn->lock); @@ -490,9 +574,10 @@ int rpc_clnt_reply_fill (rpc_transport_pollin_t *msg, rpc_clnt_connection_t *conn, struct rpc_msg *replymsg, struct iovec progmsg, - struct rpc_req *req, struct saved_frame *saved_frame) + struct rpc_req *req, + struct saved_frame *saved_frame) { - int ret = -1; + int ret = -1; if ((!conn) || (!replymsg)|| (!req) || (!saved_frame) || (!msg)) { goto out; @@ -504,25 +589,14 @@ rpc_clnt_reply_fill (rpc_transport_pollin_t *msg, req->rpc_status = -1; } - req->xid = rpc_reply_xid (replymsg); - req->prog = saved_frame->prog; - req->procnum = saved_frame->procnum; - req->conn = conn; - req->rsp[0] = progmsg; + req->rsp_iobref = iobref_ref (msg->iobref); if (msg->vectored) { - req->rsp[1].iov_base = iobuf_ptr (msg->data.vector.iobuf2); - req->rsp[1].iov_len = msg->data.vector.size2; - + req->rsp[1] = msg->vector[1]; req->rspcnt = 2; - - req->rsp_prochdr = iobuf_ref (msg->data.vector.iobuf1); - req->rsp_procpayload = iobuf_ref (msg->data.vector.iobuf2); } else { req->rspcnt = 1; - - req->rsp_prochdr = iobuf_ref (msg->data.simple.iobuf); } /* By this time, the data bytes for the auth scheme would have already @@ -544,20 +618,17 @@ out: void -rpc_clnt_reply_deinit (struct rpc_req *req) +rpc_clnt_reply_deinit (struct rpc_req *req, struct mem_pool *pool) { if (!req) { goto out; } - if (req->rsp_prochdr) { - iobuf_unref (req->rsp_prochdr); - } - - if (req->rsp_procpayload) { - iobuf_unref (req->rsp_procpayload); + if (req->rsp_iobref) { + iobref_unref (req->rsp_iobref); } + mem_put (req); out: return; } @@ -574,18 +645,14 @@ rpc_clnt_reply_init (rpc_clnt_connection_t *conn, rpc_transport_pollin_t *msg, size_t msglen = 0; int ret = -1; - if (msg->vectored) { - msgbuf = iobuf_ptr (msg->data.vector.iobuf1); - msglen = msg->data.vector.size1; - } else { - msgbuf = iobuf_ptr (msg->data.simple.iobuf); - msglen = msg->data.simple.size; - } + msgbuf = msg->vector[0].iov_base; + msglen = msg->vector[0].iov_len; ret = xdr_to_rpc_reply (msgbuf, msglen, &rpcmsg, &progmsg, req->verf.authdata); if (ret != 0) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "RPC reply decoding failed"); + gf_log (conn->trans->name, GF_LOG_WARNING, + "RPC reply decoding failed"); goto out; } @@ -595,33 +662,13 @@ rpc_clnt_reply_init (rpc_clnt_connection_t *conn, rpc_transport_pollin_t *msg, goto out; } - gf_log ("rpc-clnt", GF_LOG_TRACE, "RPC XID: %"PRIx64", Program: %s," - " ProgVers: %d, Proc: %d", saved_frame->callid, - saved_frame->prog->progname, saved_frame->prog->progver, - saved_frame->procnum); -/* TODO: */ - /* TODO: AUTH */ - /* The verifier that is sent in a reply is a string that can be used as - * a shorthand in credentials for future transactions. We can opt not to - * use this shorthand, preffering to use the original AUTH_UNIX method - * for authentication (containing all the details for authentication in - * credential itself). Hence it is not mandatory for us to be checking - * the verifier. See Appendix A of rfc-5531 for more details. - */ - - /* - * ret = rpc_authenticate (req); - * if (ret == RPC_AUTH_REJECT) { - * gf_log ("rpc-clnt", GF_LOG_ERROR, "Failed authentication"); - * ret = -1; - * goto out; - * } - */ - - /* If the error is not RPC_MISMATCH, we consider the call as accepted - * since we are not handling authentication failures for now. - */ - req->rpc_status = 0; + gf_log (conn->trans->name, GF_LOG_TRACE, + "received rpc message (RPC XID: 0x%x" + " Program: %s, ProgVers: %d, Proc: %d) from rpc-transport (%s)", + saved_frame->rpcreq->xid, + saved_frame->rpcreq->prog->progname, + saved_frame->rpcreq->prog->progver, + saved_frame->rpcreq->procnum, conn->trans->name); out: if (ret != 0) { @@ -631,52 +678,111 @@ out: return ret; } +int +rpc_clnt_handle_cbk (struct rpc_clnt *clnt, rpc_transport_pollin_t *msg) +{ + char *msgbuf = NULL; + rpcclnt_cb_program_t *program = NULL; + struct rpc_msg rpcmsg; + struct iovec progmsg; /* RPC Program payload */ + size_t msglen = 0; + int found = 0; + int ret = -1; + int procnum = 0; + + msgbuf = msg->vector[0].iov_base; + msglen = msg->vector[0].iov_len; + + clnt = rpc_clnt_ref (clnt); + ret = xdr_to_rpc_call (msgbuf, msglen, &rpcmsg, &progmsg, NULL,NULL); + if (ret == -1) { + gf_log (clnt->conn.trans->name, GF_LOG_WARNING, + "RPC call decoding failed"); + goto out; + } + + gf_log (clnt->conn.trans->name, GF_LOG_TRACE, + "received rpc message (XID: 0x%lx, " + "Ver: %ld, Program: %ld, ProgVers: %ld, Proc: %ld) " + "from rpc-transport (%s)", rpc_call_xid (&rpcmsg), + rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), + rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), + clnt->conn.trans->name); + + procnum = rpc_call_progproc (&rpcmsg); + + pthread_mutex_lock (&clnt->lock); + { + list_for_each_entry (program, &clnt->programs, program) { + if ((program->prognum == rpc_call_program (&rpcmsg)) + && (program->progver + == rpc_call_progver (&rpcmsg))) { + found = 1; + break; + } + } + } + pthread_mutex_unlock (&clnt->lock); + + if (found && (procnum < program->numactors) && + (program->actors[procnum].actor)) { + program->actors[procnum].actor (clnt, program->mydata, + &progmsg); + } + +out: + clnt = rpc_clnt_unref (clnt); + return ret; +} int rpc_clnt_handle_reply (struct rpc_clnt *clnt, rpc_transport_pollin_t *pollin) { rpc_clnt_connection_t *conn = NULL; struct saved_frame *saved_frame = NULL; - rpc_request_info_t *request_info = NULL; int ret = -1; - struct rpc_req req = {0, }; - int cbk_ret = -1; + struct rpc_req *req = NULL; + uint32_t xid = 0; + clnt = rpc_clnt_ref (clnt); conn = &clnt->conn; - request_info = pollin->private; - - saved_frame = lookup_frame (conn, (int64_t)request_info->xid); + xid = ntoh32 (*((uint32_t *)pollin->vector[0].iov_base)); + saved_frame = lookup_frame (conn, xid); if (saved_frame == NULL) { - gf_log ("rpc-clnt", GF_LOG_CRITICAL, "cannot lookup the " - "saved frame for reply with xid (%d), " - "prog-version (%d), prog-num (%d)," - "procnum (%d)", request_info->xid, - request_info->progver, request_info->prognum, - request_info->procnum); + gf_log (conn->trans->name, GF_LOG_ERROR, + "cannot lookup the saved frame for reply with xid (%u)", + xid); + goto out; + } + + req = saved_frame->rpcreq; + if (req == NULL) { + gf_log (conn->trans->name, GF_LOG_ERROR, + "no request with frame for xid (%u)", xid); goto out; } - ret = rpc_clnt_reply_init (conn, pollin, &req, saved_frame); + ret = rpc_clnt_reply_init (conn, pollin, req, saved_frame); if (ret != 0) { - req.rpc_status = -1; - gf_log ("rpc-clnt", GF_LOG_DEBUG, "initialising rpc reply " - "failed"); + req->rpc_status = -1; + gf_log (conn->trans->name, GF_LOG_WARNING, + "initialising rpc reply failed"); } - cbk_ret = saved_frame->cbkfn (&req, req.rsp, req.rspcnt, - saved_frame->frame); + req->cbkfn (req, req->rsp, req->rspcnt, saved_frame->frame); - if (ret == 0) { - rpc_clnt_reply_deinit (&req); + if (req) { + rpc_clnt_reply_deinit (req, conn->rpc_clnt->reqpool); } out: if (saved_frame) { - GF_FREE (saved_frame); + mem_put (saved_frame); } - return cbk_ret; + clnt = rpc_clnt_unref (clnt); + return ret; } @@ -715,36 +821,42 @@ out: return; } +static void +rpc_clnt_destroy (struct rpc_clnt *rpc); int rpc_clnt_notify (rpc_transport_t *trans, void *mydata, rpc_transport_event_t event, void *data, ...) { - rpc_clnt_connection_t *conn = NULL; - struct rpc_clnt *clnt = NULL; - int ret = -1; - rpc_request_info_t *req_info = NULL; - rpc_transport_pollin_t *pollin = NULL; - struct timeval tv = {0, }; + rpc_clnt_connection_t *conn = NULL; + struct rpc_clnt *clnt = NULL; + int ret = -1; + rpc_request_info_t *req_info = NULL; + rpc_transport_pollin_t *pollin = NULL; + struct timespec ts = {0, }; conn = mydata; if (conn == NULL) { goto out; } clnt = conn->rpc_clnt; + if (!clnt) + goto out; switch (event) { case RPC_TRANSPORT_DISCONNECT: { - rpc_clnt_connection_cleanup (&clnt->conn); + rpc_clnt_connection_cleanup (conn); pthread_mutex_lock (&conn->lock); { - if (conn->reconnect == NULL) { - tv.tv_sec = 10; + if (!conn->rpc_clnt->disabled + && (conn->reconnect == NULL)) { + ts.tv_sec = 10; + ts.tv_nsec = 0; conn->reconnect = - gf_timer_call_after (clnt->ctx, tv, + gf_timer_call_after (clnt->ctx, ts, rpc_clnt_reconnect, conn->trans); } @@ -752,15 +864,13 @@ rpc_clnt_notify (rpc_transport_t *trans, void *mydata, pthread_mutex_unlock (&conn->lock); if (clnt->notifyfn) - ret = clnt->notifyfn (clnt, clnt->mydata, RPC_CLNT_DISCONNECT, - NULL); + ret = clnt->notifyfn (clnt, clnt->mydata, + RPC_CLNT_DISCONNECT, NULL); break; } case RPC_TRANSPORT_CLEANUP: - /* this event should not be received on a client for, a - * transport is only disconnected, but never destroyed. - */ + rpc_clnt_destroy (clnt); ret = 0; break; @@ -773,8 +883,17 @@ rpc_clnt_notify (rpc_transport_t *trans, void *mydata, case RPC_TRANSPORT_MSG_RECEIVED: { + pthread_mutex_lock (&conn->lock); + { + gettimeofday (&conn->last_received, NULL); + } + pthread_mutex_unlock (&conn->lock); + pollin = data; - ret = rpc_clnt_handle_reply (clnt, pollin); + if (pollin->is_reply) + ret = rpc_clnt_handle_reply (clnt, pollin); + else + ret = rpc_clnt_handle_cbk (clnt, pollin); /* ret = clnt->notifyfn (clnt, clnt->mydata, RPC_CLNT_MSG, * data); */ @@ -795,8 +914,17 @@ rpc_clnt_notify (rpc_transport_t *trans, void *mydata, case RPC_TRANSPORT_CONNECT: { + /* Every time there is a disconnection, processes + should try to connect to 'glusterd' (ie, default + port) or whichever port given as 'option remote-port' + in volume file. */ + /* Below code makes sure the (re-)configured port lasts + for just one successful attempt */ + conn->config.remote_port = 0; + if (clnt->notifyfn) - ret = clnt->notifyfn (clnt, clnt->mydata, RPC_CLNT_CONNECT, NULL); + ret = clnt->notifyfn (clnt, clnt->mydata, + RPC_CLNT_CONNECT, NULL); break; } @@ -820,7 +948,7 @@ rpc_clnt_connection_deinit (rpc_clnt_connection_t *conn) } -inline int +static inline int rpc_clnt_connection_init (struct rpc_clnt *clnt, glusterfs_ctx_t *ctx, dict_t *options, char *name) { @@ -833,7 +961,7 @@ rpc_clnt_connection_init (struct rpc_clnt *clnt, glusterfs_ctx_t *ctx, ret = dict_get_int32 (options, "frame-timeout", &conn->frame_timeout); if (ret >= 0) { - gf_log (name, GF_LOG_DEBUG, + gf_log (name, GF_LOG_INFO, "setting frame-timeout to %d", conn->frame_timeout); } else { gf_log (name, GF_LOG_DEBUG, @@ -843,8 +971,9 @@ rpc_clnt_connection_init (struct rpc_clnt *clnt, glusterfs_ctx_t *ctx, conn->trans = rpc_transport_load (ctx, options, name); if (!conn->trans) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "loading of new rpc-transport" + gf_log (name, GF_LOG_WARNING, "loading of new rpc-transport" " failed"); + ret = -1; goto out; } @@ -855,7 +984,7 @@ rpc_clnt_connection_init (struct rpc_clnt *clnt, glusterfs_ctx_t *ctx, ret = rpc_transport_register_notify (conn->trans, rpc_clnt_notify, conn); if (ret == -1) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "registering notify failed"); + gf_log (name, GF_LOG_WARNING, "registering notify failed"); rpc_clnt_connection_cleanup (conn); conn = NULL; goto out; @@ -863,50 +992,93 @@ rpc_clnt_connection_init (struct rpc_clnt *clnt, glusterfs_ctx_t *ctx, conn->saved_frames = saved_frames_new (); if (!conn->saved_frames) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "creation of saved_frames " + gf_log (name, GF_LOG_WARNING, "creation of saved_frames " "failed"); rpc_clnt_connection_cleanup (conn); goto out; } - rpc_clnt_reconnect (conn->trans); - ret = 0; out: return ret; } - struct rpc_clnt * -rpc_clnt_init (struct rpc_clnt_config *config, dict_t *options, - glusterfs_ctx_t *ctx, char *name) +rpc_clnt_new (dict_t *options, glusterfs_ctx_t *ctx, char *name, + uint32_t reqpool_size) { int ret = -1; struct rpc_clnt *rpc = NULL; rpc = GF_CALLOC (1, sizeof (*rpc), gf_common_mt_rpcclnt_t); if (!rpc) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "out of memory"); goto out; } pthread_mutex_init (&rpc->lock, NULL); rpc->ctx = ctx; + if (!reqpool_size) + reqpool_size = RPC_CLNT_DEFAULT_REQUEST_COUNT; + + rpc->reqpool = mem_pool_new (struct rpc_req, reqpool_size); + if (rpc->reqpool == NULL) { + pthread_mutex_destroy (&rpc->lock); + GF_FREE (rpc); + rpc = NULL; + goto out; + } + + rpc->saved_frames_pool = mem_pool_new (struct saved_frame, + reqpool_size); + if (rpc->saved_frames_pool == NULL) { + pthread_mutex_destroy (&rpc->lock); + mem_pool_destroy (rpc->reqpool); + GF_FREE (rpc); + rpc = NULL; + goto out; + } + ret = rpc_clnt_connection_init (rpc, ctx, options, name); if (ret == -1) { pthread_mutex_destroy (&rpc->lock); + mem_pool_destroy (rpc->reqpool); + mem_pool_destroy (rpc->saved_frames_pool); GF_FREE (rpc); rpc = NULL; + if (options) + dict_unref (options); goto out; } + + rpc->auth_null = dict_get_str_boolean (options, "auth-null", 0); + + rpc = rpc_clnt_ref (rpc); + INIT_LIST_HEAD (&rpc->programs); + out: return rpc; } int +rpc_clnt_start (struct rpc_clnt *rpc) +{ + struct rpc_clnt_connection *conn = NULL; + + if (!rpc) + return -1; + + conn = &rpc->conn; + + rpc_clnt_reconnect (conn->trans); + + return 0; +} + + +int rpc_clnt_register_notify (struct rpc_clnt *rpc, rpc_clnt_notify_t fn, void *mydata) { @@ -917,7 +1089,7 @@ rpc_clnt_register_notify (struct rpc_clnt *rpc, rpc_clnt_notify_t fn, } ssize_t -xdr_serialize_glusterfs_auth (char *dest, struct auth_glusterfs_parms *au) +xdr_serialize_glusterfs_auth (char *dest, struct auth_glusterfs_parms_v2 *au) { ssize_t ret = -1; XDR xdr; @@ -925,10 +1097,11 @@ xdr_serialize_glusterfs_auth (char *dest, struct auth_glusterfs_parms *au) if ((!dest) || (!au)) return -1; - xdrmem_create (&xdr, dest, 1024, - XDR_ENCODE); + xdrmem_create (&xdr, dest, GF_MAX_AUTH_BYTES, XDR_ENCODE); - if (!xdr_auth_glusterfs_parms (&xdr, au)) { + if (!xdr_auth_glusterfs_parms_v2 (&xdr, au)) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to encode auth glusterfs elements"); ret = -1; goto ret; } @@ -941,12 +1114,11 @@ ret: int -rpc_clnt_fill_request (int prognum, int progver, int procnum, int payload, - uint64_t xid, struct auth_glusterfs_parms *au, - struct rpc_msg *request) +rpc_clnt_fill_request (int prognum, int progver, int procnum, + uint64_t xid, struct auth_glusterfs_parms_v2 *au, + struct rpc_msg *request, char *auth_data) { int ret = -1; - char dest[1024] = {0,}; if (!request) { goto out; @@ -962,19 +1134,26 @@ rpc_clnt_fill_request (int prognum, int progver, int procnum, int payload, request->rm_call.cb_vers = progver; request->rm_call.cb_proc = procnum; - /* TODO: Using AUTH_GLUSTERFS for time-being. Make it modular in - * future so it is easy to plug-in new authentication schemes. + /* TODO: Using AUTH_(GLUSTERFS/NULL) in a kludgy way for time-being. + * Make it modular in future so it is easy to plug-in new + * authentication schemes. */ - ret = xdr_serialize_glusterfs_auth (dest, au); - if (ret == -1) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "cannot encode credentials"); - goto out; - } - - request->rm_call.cb_cred.oa_flavor = AUTH_GLUSTERFS; - request->rm_call.cb_cred.oa_base = dest; - request->rm_call.cb_cred.oa_length = ret; + if (auth_data) { + ret = xdr_serialize_glusterfs_auth (auth_data, au); + if (ret == -1) { + gf_log ("rpc-clnt", GF_LOG_DEBUG, + "cannot encode credentials"); + goto out; + } + request->rm_call.cb_cred.oa_flavor = AUTH_GLUSTERFS_v2; + request->rm_call.cb_cred.oa_base = auth_data; + request->rm_call.cb_cred.oa_length = ret; + } else { + request->rm_call.cb_cred.oa_flavor = AUTH_NULL; + request->rm_call.cb_cred.oa_base = NULL; + request->rm_call.cb_cred.oa_length = 0; + } request->rm_call.cb_verf.oa_flavor = AUTH_NONE; request->rm_call.cb_verf.oa_base = NULL; request->rm_call.cb_verf.oa_length = 0; @@ -985,42 +1164,16 @@ out: } -void -rpc_clnt_set_lastfrag (uint32_t *fragsize) { - (*fragsize) |= 0x80000000U; -} - - -void -rpc_clnt_set_frag_header_size (uint32_t size, char *haddr) -{ - size = htonl (size); - memcpy (haddr, &size, sizeof (size)); -} - - -void -rpc_clnt_set_last_frag_header_size (uint32_t size, char *haddr) -{ - rpc_clnt_set_lastfrag (&size); - rpc_clnt_set_frag_header_size (size, haddr); -} - - struct iovec rpc_clnt_record_build_header (char *recordstart, size_t rlen, struct rpc_msg *request, size_t payload) { struct iovec requesthdr = {0, }; struct iovec txrecord = {0, 0}; - size_t fraglen = 0; int ret = -1; + size_t fraglen = 0; - /* After leaving aside the 4 bytes for the fragment header, lets - * encode the RPC reply structure into the buffer given to us. - */ - ret = rpc_request_to_xdr (request, (recordstart + RPC_FRAGHDR_SIZE), - rlen, &requesthdr); + ret = rpc_request_to_xdr (request, recordstart, rlen, &requesthdr); if (ret == -1) { gf_log ("rpc-clnt", GF_LOG_DEBUG, "Failed to create RPC request"); @@ -1031,16 +1184,7 @@ rpc_clnt_record_build_header (char *recordstart, size_t rlen, gf_log ("rpc-clnt", GF_LOG_TRACE, "Request fraglen %zu, payload: %zu, " "rpc hdr: %zu", fraglen, payload, requesthdr.iov_len); - /* Since we're not spreading RPC records over mutiple fragments - * we just set this fragment as the first and last fragment for this - * record. - */ - rpc_clnt_set_last_frag_header_size (fraglen, recordstart); - /* Even though the RPC record starts at recordstart+RPCSVC_FRAGHDR_SIZE - * we need to transmit the record with the fragment header, which starts - * at recordstart. - */ txrecord.iov_base = recordstart; /* Remember, this is only the vec for the RPC header and does not @@ -1048,7 +1192,7 @@ rpc_clnt_record_build_header (char *recordstart, size_t rlen, * the size of the full fragment. This size is sent in the fragment * header. */ - txrecord.iov_len = RPC_FRAGHDR_SIZE + requesthdr.iov_len; + txrecord.iov_len = requesthdr.iov_len; out: return txrecord; @@ -1057,50 +1201,57 @@ out: struct iobuf * rpc_clnt_record_build_record (struct rpc_clnt *clnt, int prognum, int progver, - int procnum, size_t payload, uint64_t xid, - struct auth_glusterfs_parms *au, struct iovec *recbuf) + int procnum, size_t hdrsize, uint64_t xid, + struct auth_glusterfs_parms_v2 *au, + struct iovec *recbuf) { - struct rpc_msg request = {0, }; - struct iobuf *request_iob = NULL; - char *record = NULL; - struct iovec recordhdr = {0, }; - size_t pagesize = 0; - int ret = -1; + struct rpc_msg request = {0, }; + struct iobuf *request_iob = NULL; + char *record = NULL; + struct iovec recordhdr = {0, }; + size_t pagesize = 0; + int ret = -1; + size_t xdr_size = 0; + char auth_data[GF_MAX_AUTH_BYTES] = {0, }; if ((!clnt) || (!recbuf) || (!au)) { goto out; } + /* Fill the rpc structure and XDR it into the buffer got above. */ + if (clnt->auth_null) + ret = rpc_clnt_fill_request (prognum, progver, procnum, + xid, NULL, &request, NULL); + else + ret = rpc_clnt_fill_request (prognum, progver, procnum, + xid, au, &request, auth_data); + + if (ret == -1) { + gf_log (clnt->conn.trans->name, GF_LOG_WARNING, + "cannot build a rpc-request xid (%"PRIu64")", xid); + goto out; + } + + xdr_size = xdr_sizeof ((xdrproc_t)xdr_callmsg, &request); + /* First, try to get a pointer into the buffer which the RPC * layer can use. */ - request_iob = iobuf_get (clnt->ctx->iobuf_pool); + request_iob = iobuf_get2 (clnt->ctx->iobuf_pool, (xdr_size + hdrsize)); if (!request_iob) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "Failed to get iobuf"); goto out; } - pagesize = ((struct iobuf_pool *)clnt->ctx->iobuf_pool)->page_size; + pagesize = iobuf_pagesize (request_iob); record = iobuf_ptr (request_iob); /* Now we have it. */ - /* Fill the rpc structure and XDR it into the buffer got above. */ - ret = rpc_clnt_fill_request (prognum, progver, procnum, payload, xid, - au, &request); - if (ret == -1) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "cannot build a rpc-request " - "xid (%"PRIu64")", xid); - goto out; - } - recordhdr = rpc_clnt_record_build_header (record, pagesize, &request, - payload); - - //GF_FREE (request.rm_call.cb_cred.oa_base); + hdrsize); if (!recordhdr.iov_base) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "Failed to build record " - " header"); + gf_log (clnt->conn.trans->name, GF_LOG_ERROR, + "Failed to build record header"); iobuf_unref (request_iob); request_iob = NULL; recbuf->iov_base = NULL; @@ -1117,43 +1268,50 @@ out: struct iobuf * rpc_clnt_record (struct rpc_clnt *clnt, call_frame_t *call_frame, - rpc_clnt_prog_t *prog,int procnum, size_t payload_len, + rpc_clnt_prog_t *prog, int procnum, size_t hdrlen, struct iovec *rpchdr, uint64_t callid) { - struct auth_glusterfs_parms au = {0, }; - struct iobuf *request_iob = NULL; + struct auth_glusterfs_parms_v2 au = {0, }; + struct iobuf *request_iob = NULL; + char owner[4] = {0,}; if (!prog || !rpchdr || !call_frame) { goto out; } - au.pid = call_frame->root->pid; - au.uid = call_frame->root->uid; - au.gid = call_frame->root->gid; - au.ngrps = call_frame->root->ngrps; - au.lk_owner = call_frame->root->lk_owner; - if (!au.lk_owner) - au.lk_owner = au.pid; + au.pid = call_frame->root->pid; + au.uid = call_frame->root->uid; + au.gid = call_frame->root->gid; + au.groups.groups_len = call_frame->root->ngrps; + au.lk_owner.lk_owner_len = call_frame->root->lk_owner.len; - gf_log ("", GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" - ", gid: %d, owner: %"PRId64, - au.pid, au.uid, au.gid, au.lk_owner); + if (au.groups.groups_len) + au.groups.groups_val = call_frame->root->groups; - memcpy (au.groups, call_frame->root->groups, 16); + if (call_frame->root->lk_owner.len) + au.lk_owner.lk_owner_val = call_frame->root->lk_owner.data; + else { + owner[0] = (char)(au.pid & 0xff); + owner[1] = (char)((au.pid >> 8) & 0xff); + owner[2] = (char)((au.pid >> 16) & 0xff); + owner[3] = (char)((au.pid >> 24) & 0xff); - //rpc_transport_get_myname (clnt->conn.trans, myname, UNIX_PATH_MAX); - //au.aup_machname = myname; + au.lk_owner.lk_owner_val = owner; + au.lk_owner.lk_owner_len = 4; + } + + gf_log (clnt->conn.trans->name, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" + ", gid: %d, owner: %s", au.pid, au.uid, au.gid, + lkowner_utoa (&call_frame->root->lk_owner)); - /* Assuming the client program would like to speak to the same versioned - * program on server. - */ request_iob = rpc_clnt_record_build_record (clnt, prog->prognum, prog->progver, - procnum, payload_len, + procnum, hdrlen, callid, &au, rpchdr); if (!request_iob) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, "cannot build rpc-record"); + gf_log (clnt->conn.trans->name, GF_LOG_WARNING, + "cannot build rpc-record"); goto out; } @@ -1161,18 +1319,87 @@ out: return request_iob; } +int +rpcclnt_cbk_program_register (struct rpc_clnt *clnt, + rpcclnt_cb_program_t *program, void *mydata) +{ + int ret = -1; + char already_registered = 0; + rpcclnt_cb_program_t *tmp = NULL; + + if (!clnt) + goto out; + + if (program->actors == NULL) + goto out; + + pthread_mutex_lock (&clnt->lock); + { + list_for_each_entry (tmp, &clnt->programs, program) { + if ((program->prognum == tmp->prognum) + && (program->progver == tmp->progver)) { + already_registered = 1; + break; + } + } + } + pthread_mutex_unlock (&clnt->lock); + + if (already_registered) { + gf_log_callingfn (clnt->conn.trans->name, GF_LOG_DEBUG, + "already registered"); + ret = 0; + goto out; + } + + tmp = GF_CALLOC (1, sizeof (*tmp), + gf_common_mt_rpcclnt_cb_program_t); + if (tmp == NULL) { + goto out; + } + + memcpy (tmp, program, sizeof (*tmp)); + INIT_LIST_HEAD (&tmp->program); + + tmp->mydata = mydata; + + pthread_mutex_lock (&clnt->lock); + { + list_add_tail (&tmp->program, &clnt->programs); + } + pthread_mutex_unlock (&clnt->lock); + + ret = 0; + gf_log (clnt->conn.trans->name, GF_LOG_DEBUG, + "New program registered: %s, Num: %d, Ver: %d", + program->progname, program->prognum, + program->progver); + +out: + if (ret == -1) { + gf_log (clnt->conn.trans->name, GF_LOG_ERROR, + "Program registration failed:" + " %s, Num: %d, Ver: %d", program->progname, + program->prognum, program->progver); + } + + return ret; +} + int rpc_clnt_submit (struct rpc_clnt *rpc, rpc_clnt_prog_t *prog, int procnum, fop_cbk_fn_t cbkfn, struct iovec *proghdr, int proghdrcount, struct iovec *progpayload, int progpayloadcount, - struct iobref *iobref, void *frame) + struct iobref *iobref, void *frame, struct iovec *rsphdr, + int rsphdr_count, struct iovec *rsp_payload, + int rsp_payload_count, struct iobref *rsp_iobref) { rpc_clnt_connection_t *conn = NULL; struct iobuf *request_iob = NULL; struct iovec rpchdr = {0,}; - struct rpc_req rpcreq = {0,}; + struct rpc_req *rpcreq = NULL; rpc_transport_req_t req; int ret = -1; int proglen = 0; @@ -1183,12 +1410,23 @@ rpc_clnt_submit (struct rpc_clnt *rpc, rpc_clnt_prog_t *prog, goto out; } + conn = &rpc->conn; + + if (conn->trans == NULL) { + goto out; + } + + rpcreq = mem_get (rpc->reqpool); + if (rpcreq == NULL) { + goto out; + } + + memset (rpcreq, 0, sizeof (*rpcreq)); memset (&req, 0, sizeof (req)); if (!iobref) { iobref = iobref_new (); if (!iobref) { - gf_log ("rpc-clnt", GF_LOG_ERROR, "out of memory"); goto out; } @@ -1197,59 +1435,73 @@ rpc_clnt_submit (struct rpc_clnt *rpc, rpc_clnt_prog_t *prog, callid = rpc_clnt_new_callid (rpc); - conn = &rpc->conn; + rpcreq->prog = prog; + rpcreq->procnum = procnum; + rpcreq->conn = conn; + rpcreq->xid = callid; + rpcreq->cbkfn = cbkfn; - pthread_mutex_lock (&conn->lock); - { - if (conn->connected == 0) { - rpc_transport_connect (conn->trans); - } + ret = -1; - ret = -1; + if (proghdr) { + proglen += iov_length (proghdr, proghdrcount); + } - if (proghdr) { - proglen += iov_length (proghdr, proghdrcount); - } + request_iob = rpc_clnt_record (rpc, frame, prog, + procnum, proglen, + &rpchdr, callid); + if (!request_iob) { + gf_log (conn->trans->name, GF_LOG_WARNING, + "cannot build rpc-record"); + goto out; + } - if (progpayload) { - proglen += iov_length (progpayload, - progpayloadcount); - } + iobref_add (iobref, request_iob); - request_iob = rpc_clnt_record (rpc, frame, prog, - procnum, proglen, - &rpchdr, callid); - if (!request_iob) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, - "cannot build rpc-record"); - goto unlock; - } + req.msg.rpchdr = &rpchdr; + req.msg.rpchdrcount = 1; + req.msg.proghdr = proghdr; + req.msg.proghdrcount = proghdrcount; + req.msg.progpayload = progpayload; + req.msg.progpayloadcount = progpayloadcount; + req.msg.iobref = iobref; - iobref_add (iobref, request_iob); + req.rsp.rsphdr = rsphdr; + req.rsp.rsphdr_count = rsphdr_count; + req.rsp.rsp_payload = rsp_payload; + req.rsp.rsp_payload_count = rsp_payload_count; + req.rsp.rsp_iobref = rsp_iobref; + req.rpc_req = rpcreq; - req.msg.rpchdr = &rpchdr; - req.msg.rpchdrcount = 1; - req.msg.proghdr = proghdr; - req.msg.proghdrcount = proghdrcount; - req.msg.progpayload = progpayload; - req.msg.progpayloadcount = progpayloadcount; - req.msg.iobref = iobref; + pthread_mutex_lock (&conn->lock); + { + if (conn->connected == 0) { + ret = rpc_transport_connect (conn->trans, + conn->config.remote_port); + } ret = rpc_transport_submit_request (rpc->conn.trans, &req); if (ret == -1) { - gf_log ("rpc-clnt", GF_LOG_DEBUG, - "transmission of rpc-request failed"); + gf_log (conn->trans->name, GF_LOG_WARNING, + "failed to submit rpc-request " + "(XID: 0x%x Program: %s, ProgVers: %d, " + "Proc: %d) to rpc-transport (%s)", rpcreq->xid, + rpcreq->prog->progname, rpcreq->prog->progver, + rpcreq->procnum, rpc->conn.trans->name); } if ((ret >= 0) && frame) { - gettimeofday (&conn->last_sent, NULL); /* Save the frame in queue */ - __save_frame (rpc, frame, procnum, prog, cbkfn, callid); - } + __save_frame (rpc, frame, rpcreq); + gf_log ("rpc-clnt", GF_LOG_TRACE, "submitted request " + "(XID: 0x%x Program: %s, ProgVers: %d, " + "Proc: %d) to rpc-transport (%s)", rpcreq->xid, + rpcreq->prog->progname, rpcreq->prog->progver, + rpcreq->procnum, rpc->conn.trans->name); + } } -unlock: pthread_mutex_unlock (&conn->lock); if (ret == -1) { @@ -1259,26 +1511,190 @@ unlock: ret = 0; out: - iobuf_unref (request_iob); + if (request_iob) { + iobuf_unref (request_iob); + } if (new_iobref && iobref) { iobref_unref (iobref); } if (frame && (ret == -1)) { - rpcreq.rpc_status = -1; - cbkfn (&rpcreq, NULL, 0, frame); + if (rpcreq) { + rpcreq->rpc_status = -1; + cbkfn (rpcreq, NULL, 0, frame); + mem_put (rpcreq); + } } return ret; } -void +struct rpc_clnt * +rpc_clnt_ref (struct rpc_clnt *rpc) +{ + if (!rpc) + return NULL; + pthread_mutex_lock (&rpc->lock); + { + rpc->refcount++; + } + pthread_mutex_unlock (&rpc->lock); + return rpc; +} + + +static void +rpc_clnt_trigger_destroy (struct rpc_clnt *rpc) +{ + if (!rpc) + return; + + rpc_clnt_disable (rpc); + rpc_transport_unref (rpc->conn.trans); +} + +static void rpc_clnt_destroy (struct rpc_clnt *rpc) { - rpc_clnt_connection_cleanup (&rpc->conn); + if (!rpc) + return; + + saved_frames_destroy (rpc->conn.saved_frames); pthread_mutex_destroy (&rpc->lock); pthread_mutex_destroy (&rpc->conn.lock); + + /* mem-pool should be destroyed, otherwise, + it will cause huge memory leaks */ + mem_pool_destroy (rpc->reqpool); + mem_pool_destroy (rpc->saved_frames_pool); + GF_FREE (rpc); return; } + +struct rpc_clnt * +rpc_clnt_unref (struct rpc_clnt *rpc) +{ + int count = 0; + + if (!rpc) + return NULL; + pthread_mutex_lock (&rpc->lock); + { + count = --rpc->refcount; + } + pthread_mutex_unlock (&rpc->lock); + if (!count) { + rpc_clnt_trigger_destroy (rpc); + return NULL; + } + return rpc; +} + + +char +rpc_clnt_is_disabled (struct rpc_clnt *rpc) +{ + + rpc_clnt_connection_t *conn = NULL; + char disabled = 0; + + if (!rpc) { + goto out; + } + + conn = &rpc->conn; + + pthread_mutex_lock (&conn->lock); + { + disabled = rpc->disabled; + } + pthread_mutex_unlock (&conn->lock); + +out: + return disabled; +} + +void +rpc_clnt_disable (struct rpc_clnt *rpc) +{ + rpc_clnt_connection_t *conn = NULL; + + if (!rpc) { + goto out; + } + + conn = &rpc->conn; + + pthread_mutex_lock (&conn->lock); + { + rpc->disabled = 1; + + if (conn->timer) { + gf_timer_call_cancel (rpc->ctx, conn->timer); + conn->timer = NULL; + } + + if (conn->reconnect) { + gf_timer_call_cancel (rpc->ctx, conn->reconnect); + conn->reconnect = NULL; + } + conn->connected = 0; + + if (conn->ping_timer) { + gf_timer_call_cancel (rpc->ctx, conn->ping_timer); + conn->ping_timer = NULL; + conn->ping_started = 0; + } + + } + pthread_mutex_unlock (&conn->lock); + + rpc_transport_disconnect (rpc->conn.trans); + +out: + return; +} + + +void +rpc_clnt_reconfig (struct rpc_clnt *rpc, struct rpc_clnt_config *config) +{ + if (config->rpc_timeout) { + if (config->rpc_timeout != rpc->conn.config.rpc_timeout) + gf_log (rpc->conn.trans->name, GF_LOG_INFO, + "changing timeout to %d (from %d)", + config->rpc_timeout, + rpc->conn.config.rpc_timeout); + rpc->conn.config.rpc_timeout = config->rpc_timeout; + } + + if (config->remote_port) { + if (config->remote_port != rpc->conn.config.remote_port) + gf_log (rpc->conn.trans->name, GF_LOG_INFO, + "changing port to %d (from %d)", + config->remote_port, + rpc->conn.config.remote_port); + + rpc->conn.config.remote_port = config->remote_port; + } + + if (config->remote_host) { + if (rpc->conn.config.remote_host) { + if (strcmp (rpc->conn.config.remote_host, + config->remote_host)) + gf_log (rpc->conn.trans->name, GF_LOG_INFO, + "changing hostname to %s (from %s)", + config->remote_host, + rpc->conn.config.remote_host); + FREE (rpc->conn.config.remote_host); + } else { + gf_log (rpc->conn.trans->name, GF_LOG_INFO, + "setting hostname to %s", + config->remote_host); + } + + rpc->conn.config.remote_host = gf_strdup (config->remote_host); + } +} diff --git a/rpc/rpc-lib/src/rpc-clnt.h b/rpc/rpc-lib/src/rpc-clnt.h index efc256cd2..584963ad0 100644 --- a/rpc/rpc-lib/src/rpc-clnt.h +++ b/rpc/rpc-lib/src/rpc-clnt.h @@ -1,24 +1,15 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ -#ifndef _RPC_CLNT_H -#define _RPC_CLNT_H +#ifndef __RPC_CLNT_H +#define __RPC_CLNT_H #include "stack.h" #include "rpc-transport.h" @@ -31,7 +22,10 @@ typedef enum { RPC_CLNT_MSG } rpc_clnt_event_t; -#define AUTH_GLUSTERFS 5 + +#define SFRAME_GET_PROGNUM(sframe) (sframe->rpcreq->prog->prognum) +#define SFRAME_GET_PROGVER(sframe) (sframe->rpcreq->prog->progver) +#define SFRAME_GET_PROCNUM(sframe) (sframe->rpcreq->procnum) struct xptr_clnt; struct rpc_req; @@ -58,16 +52,14 @@ struct saved_frame { void *capital_this; void *frame; struct timeval saved_at; - int32_t procnum; - struct rpc_clnt_program *prog; - fop_cbk_fn_t cbkfn; - uint64_t callid; + struct rpc_req *rpcreq; rpc_transport_rsp_t rsp; }; struct saved_frames { int64_t count; struct saved_frame sf; + struct saved_frame lk_sf; }; @@ -86,28 +78,71 @@ typedef struct rpc_clnt_program { int numproc; } rpc_clnt_prog_t; -#define RPC_MAX_AUTH_BYTES 400 +typedef int (*rpcclnt_cb_fn) (struct rpc_clnt *rpc, void *mydata, void *data); + +/* The descriptor for each procedure/actor that runs + * over the RPC service. + */ +typedef struct rpcclnt_actor_desc { + char procname[32]; + int procnum; + rpcclnt_cb_fn actor; +} rpcclnt_cb_actor_t; + +/* Describes a program and its version along with the function pointers + * required to handle the procedures/actors of each program/version. + * Never changed ever by any thread so no need for a lock. + */ +typedef struct rpcclnt_cb_program { + char progname[32]; + int prognum; + int progver; + rpcclnt_cb_actor_t *actors; /* All procedure handlers */ + int numactors; /* Num actors in actor array */ + + /* Program specific state handed to actors */ + void *private; + + + /* list member to link to list of registered services with rpc_clnt */ + struct list_head program; + + /* Needed for passing back in cb_actor */ + void *mydata; +} rpcclnt_cb_program_t; + + + typedef struct rpc_auth_data { - int flavour; - int datalen; - char authdata[RPC_MAX_AUTH_BYTES]; + int flavour; + int datalen; + char authdata[GF_MAX_AUTH_BYTES]; } rpc_auth_data_t; + +struct rpc_clnt_config { + int rpc_timeout; + int remote_port; + char * remote_host; +}; + + #define rpc_auth_flavour(au) ((au).flavour) struct rpc_clnt_connection { - pthread_mutex_t lock; - rpc_transport_t *trans; - gf_timer_t *reconnect; - gf_timer_t *timer; - gf_timer_t *ping_timer; - struct rpc_clnt *rpc_clnt; - char connected; - struct saved_frames *saved_frames; - int32_t frame_timeout; - struct timeval last_sent; - struct timeval last_received; - int32_t ping_started; + pthread_mutex_t lock; + rpc_transport_t *trans; + struct rpc_clnt_config config; + gf_timer_t *reconnect; + gf_timer_t *timer; + gf_timer_t *ping_timer; + struct rpc_clnt *rpc_clnt; + char connected; + struct saved_frames *saved_frames; + int32_t frame_timeout; + struct timeval last_sent; + struct timeval last_received; + int32_t ping_started; }; typedef struct rpc_clnt_connection rpc_clnt_connection_t; @@ -116,51 +151,96 @@ struct rpc_req { uint32_t xid; struct iovec req[2]; int reqcnt; + struct iobref *req_iobref; struct iovec rsp[2]; int rspcnt; - struct iobuf *rsp_prochdr; - struct iobuf *rsp_procpayload; + struct iobref *rsp_iobref; int rpc_status; rpc_auth_data_t verf; rpc_clnt_prog_t *prog; int procnum; + fop_cbk_fn_t cbkfn; + void *conn_private; }; -struct rpc_clnt { +typedef struct rpc_clnt { pthread_mutex_t lock; rpc_clnt_notify_t notifyfn; rpc_clnt_connection_t conn; void *mydata; uint64_t xid; + + /* list of cb programs registered with rpc-clnt */ + struct list_head programs; + + /* Memory pool for rpc_req_t */ + struct mem_pool *reqpool; + + struct mem_pool *saved_frames_pool; + glusterfs_ctx_t *ctx; -}; + int refcount; + int auth_null; + char disabled; +} rpc_clnt_t; -struct rpc_clnt_config { - int rpc_timeout; - int remote_port; - char * remote_host; -}; +struct rpc_clnt *rpc_clnt_new (dict_t *options, glusterfs_ctx_t *ctx, + char *name, uint32_t reqpool_size); -struct rpc_clnt * rpc_clnt_init (struct rpc_clnt_config *config, - dict_t *options, glusterfs_ctx_t *ctx, - char *name); +int rpc_clnt_start (struct rpc_clnt *rpc); int rpc_clnt_register_notify (struct rpc_clnt *rpc, rpc_clnt_notify_t fn, void *mydata); +/* Some preconditions related to vectors holding responses. + * @rsphdr: should contain pointer to buffer which can hold response header + * and length of the program header. In case of procedures whose + * respnose size is not bounded (eg., glusterfs lookup), the length + * should be equal to size of buffer. + * @rsp_payload: should contain pointer and length of the bu + * + * 1. Both @rsp_hdr and @rsp_payload are optional. + * 2. The user of rpc_clnt_submit, if wants response hdr and payload in its own + * buffers, then it has to populate @rsphdr and @rsp_payload. + * 3. when @rsp_payload is not NULL, @rsphdr should + * also be filled with pointer to buffer to hold header and length + * of the header. + */ + int rpc_clnt_submit (struct rpc_clnt *rpc, rpc_clnt_prog_t *prog, int procnum, fop_cbk_fn_t cbkfn, struct iovec *proghdr, int proghdrcount, struct iovec *progpayload, int progpayloadcount, - struct iobref *iobref, void *frame); + struct iobref *iobref, void *frame, struct iovec *rsphdr, + int rsphdr_count, struct iovec *rsp_payload, + int rsp_payload_count, struct iobref *rsp_iobref); + +struct rpc_clnt * +rpc_clnt_ref (struct rpc_clnt *rpc); -void rpc_clnt_destroy (struct rpc_clnt *rpc); +struct rpc_clnt * +rpc_clnt_unref (struct rpc_clnt *rpc); + +int rpc_clnt_connection_cleanup (rpc_clnt_connection_t *conn); void rpc_clnt_set_connected (rpc_clnt_connection_t *conn); void rpc_clnt_unset_connected (rpc_clnt_connection_t *conn); - void rpc_clnt_reconnect (void *trans_ptr); +void rpc_clnt_reconfig (struct rpc_clnt *rpc, struct rpc_clnt_config *config); + +/* All users of RPC services should use this API to register their + * procedure handlers. + */ +int rpcclnt_cbk_program_register (struct rpc_clnt *svc, + rpcclnt_cb_program_t *program, void *mydata); + +void +rpc_clnt_disable (struct rpc_clnt *rpc); + +char +rpc_clnt_is_disabled (struct rpc_clnt *rpc); + #endif /* !_RPC_CLNT_H */ diff --git a/rpc/rpc-lib/src/rpc-common.c b/rpc/rpc-lib/src/rpc-common.c deleted file mode 100644 index ffd0c8d28..000000000 --- a/rpc/rpc-lib/src/rpc-common.c +++ /dev/null @@ -1,115 +0,0 @@ - -#include "xdr-common.h" - -ssize_t -xdr_serialize_generic (struct iovec outmsg, void *res, xdrproc_t proc) -{ - ssize_t ret = -1; - XDR xdr; - - if ((!outmsg.iov_base) || (!res) || (!proc)) - return -1; - - xdrmem_create (&xdr, outmsg.iov_base, (unsigned int)outmsg.iov_len, - XDR_ENCODE); - - if (!proc (&xdr, res)) { - ret = -1; - goto ret; - } - - ret = xdr_encoded_length (xdr); - -ret: - return ret; -} - - -ssize_t -xdr_to_generic (struct iovec inmsg, void *args, xdrproc_t proc) -{ - XDR xdr; - ssize_t ret = -1; - - if ((!inmsg.iov_base) || (!args) || (!proc)) - return -1; - - xdrmem_create (&xdr, inmsg.iov_base, (unsigned int)inmsg.iov_len, - XDR_DECODE); - - if (!proc (&xdr, args)) { - ret = -1; - goto ret; - } - - ret = xdr_decoded_length (xdr); -ret: - return ret; -} - - -bool_t -xdr_gf_dump_req (XDR *xdrs, gf_dump_req *objp) -{ - if (!xdr_u_quad_t (xdrs, &objp->gfs_id)) - return FALSE; - return TRUE; -} - -bool_t -xdr_gf_prog_detail (XDR *xdrs, gf_prog_detail *objp) -{ - if (!xdr_string (xdrs, &objp->progname, ~0)) - return FALSE; - if (!xdr_u_quad_t (xdrs, &objp->prognum)) - return FALSE; - if (!xdr_u_quad_t (xdrs, &objp->progver)) - return FALSE; - if (!xdr_pointer (xdrs, (char **)&objp->next, sizeof (gf_prog_detail), (xdrproc_t) xdr_gf_prog_detail)) - return FALSE; - return TRUE; -} - -bool_t -xdr_gf_dump_rsp (XDR *xdrs, gf_dump_rsp *objp) -{ - if (!xdr_u_quad_t (xdrs, &objp->gfs_id)) - return FALSE; - if (!xdr_int (xdrs, &objp->op_ret)) - return FALSE; - if (!xdr_int (xdrs, &objp->op_errno)) - return FALSE; - if (!xdr_pointer (xdrs, (char **)&objp->prog, sizeof (gf_prog_detail), (xdrproc_t) xdr_gf_prog_detail)) - return FALSE; - return TRUE; -} - - -ssize_t -xdr_serialize_dump_rsp (struct iovec outmsg, void *rsp) -{ - return xdr_serialize_generic (outmsg, (void *)rsp, - (xdrproc_t)xdr_gf_dump_rsp); -} - -ssize_t -xdr_to_dump_req (struct iovec inmsg, void *args) -{ - return xdr_to_generic (inmsg, (void *)args, - (xdrproc_t)xdr_gf_dump_req); -} - - -ssize_t -xdr_from_dump_req (struct iovec outmsg, void *rsp) -{ - return xdr_serialize_generic (outmsg, (void *)rsp, - (xdrproc_t)xdr_gf_dump_req); -} - -ssize_t -xdr_to_dump_rsp (struct iovec inmsg, void *args) -{ - return xdr_to_generic (inmsg, (void *)args, - (xdrproc_t)xdr_gf_dump_rsp); -} diff --git a/rpc/rpc-lib/src/rpc-drc.c b/rpc/rpc-lib/src/rpc-drc.c new file mode 100644 index 000000000..8181e6aee --- /dev/null +++ b/rpc/rpc-lib/src/rpc-drc.c @@ -0,0 +1,872 @@ +/* + Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpcsvc.h" +#ifndef RPC_DRC_H +#include "rpc-drc.h" +#endif +#include "locking.h" +#include "hashfn.h" +#include "common-utils.h" +#include "statedump.h" +#include "mem-pool.h" + +#include <netinet/in.h> +#include <unistd.h> + +/** + * rpcsvc_drc_op_destroy - Destroys the cached reply + * + * @param drc - the main drc structure + * @param reply - the cached reply to destroy + * @return NULL if reply is destroyed, reply otherwise + */ +static drc_cached_op_t * +rpcsvc_drc_op_destroy (rpcsvc_drc_globals_t *drc, drc_cached_op_t *reply) +{ + GF_ASSERT (drc); + GF_ASSERT (reply); + + if (reply->state == DRC_OP_IN_TRANSIT) + return reply; + + iobref_unref (reply->msg.iobref); + if (reply->msg.rpchdr) + GF_FREE (reply->msg.rpchdr); + if (reply->msg.proghdr) + GF_FREE (reply->msg.proghdr); + if (reply->msg.progpayload) + GF_FREE (reply->msg.progpayload); + + list_del (&reply->global_list); + reply->client->op_count--; + drc->op_count--; + mem_put (reply); + reply = NULL; + + return reply; +} + +/** + * rpcsvc_drc_op_rb_unref - This function is used in rb tree cleanup only + * + * @param reply - the cached reply to unref + * @param drc - the main drc structure + * @return void + */ +static void +rpcsvc_drc_rb_op_destroy (void *reply, void *drc) +{ + rpcsvc_drc_op_destroy (drc, (drc_cached_op_t *)reply); +} + +/** + * rpcsvc_remove_drc_client - Cleanup the drc client + * + * @param client - the drc client to be removed + * @return void + */ +static void +rpcsvc_remove_drc_client (drc_client_t *client) +{ + rb_destroy (client->rbtree, rpcsvc_drc_rb_op_destroy); + list_del (&client->client_list); + GF_FREE (client); +} + +/** + * rpcsvc_client_lookup - Given a sockaddr_storage, find the client if it exists + * + * @param drc - the main drc structure + * @param sockaddr - the network address of the client to be looked up + * @return drc client if it exists, NULL otherwise + */ +static drc_client_t * +rpcsvc_client_lookup (rpcsvc_drc_globals_t *drc, + struct sockaddr_storage *sockaddr) +{ + drc_client_t *client = NULL; + + GF_ASSERT (drc); + GF_ASSERT (sockaddr); + + if (list_empty (&drc->clients_head)) + return NULL; + + list_for_each_entry (client, &drc->clients_head, client_list) { + if (gf_sock_union_equal_addr (&client->sock_union, + (union gf_sock_union *)sockaddr)) + return client; + } + + return NULL; +} + +/** + * drc_compare_reqs - Used by rbtree to determine if incoming req matches with + * an existing node(cached reply) in rbtree + * + * @param item - pointer to the incoming req + * @param rb_node_data - pointer to an rbtree node (cached reply) + * @param param - drc pointer - unused here, but used in *op_destroy + * @return 0 if req matches reply, else (req->xid - reply->xid) + */ +int +drc_compare_reqs (const void *item, const void *rb_node_data, void *param) +{ + int ret = -1; + rpcsvc_request_t *req = NULL; + drc_cached_op_t *reply = NULL; + + GF_ASSERT (item); + GF_ASSERT (rb_node_data); + GF_ASSERT (param); + + req = (rpcsvc_request_t *)item; + reply = (drc_cached_op_t *)rb_node_data; + + ret = req->xid - reply->xid; + if (ret != 0) + return ret; + + if (req->prognum == reply->prognum && + req->procnum == reply->procnum && + req->progver == reply->progversion) + return 0; + + return 1; +} + +/** + * drc_rb_calloc - used by rbtree api to allocate memory for nodes + * + * @param allocator - the libavl_allocator structure used by rbtree + * @param size - not needed by this function + * @return pointer to new cached reply (node in rbtree) + */ +static void * +drc_rb_calloc (struct libavl_allocator *allocator, size_t size) +{ + rpcsvc_drc_globals_t *drc = NULL; + + /* get the drc pointer by simple typecast, since allocator + * is the first member of rpcsvc_drc_globals_t + */ + drc = (rpcsvc_drc_globals_t *)allocator; + + return mem_get (drc->mempool); +} + +/** + * drc_rb_free - used by rbtree api to free a node + * + * @param a - the libavl_allocator structure used by rbtree api + * @param block - node that needs to be freed + * @return void + */ +static void +drc_rb_free (struct libavl_allocator *a, void *block) +{ + mem_put (block); +} + +/** + * drc_init_client_cache - initialize a drc client and its rb tree + * + * @param drc - the main drc structure + * @param client - the drc client to be initialized + * @return 0 on success, -1 on failure + */ +static int +drc_init_client_cache (rpcsvc_drc_globals_t *drc, drc_client_t *client) +{ + GF_ASSERT (drc); + GF_ASSERT (client); + + drc->allocator.libavl_malloc = drc_rb_calloc; + drc->allocator.libavl_free = drc_rb_free; + + client->rbtree = rb_create (drc_compare_reqs, drc, + (struct libavl_allocator *)drc); + if (!client->rbtree) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "rb tree creation failed"); + return -1; + } + + return 0; +} + +/** + * rpcsvc_get_drc_client - find the drc client with given sockaddr, else + * allocate and initialize a new drc client + * + * @param drc - the main drc structure + * @param sockaddr - network address of client + * @return drc client on success, NULL on failure + */ +static drc_client_t * +rpcsvc_get_drc_client (rpcsvc_drc_globals_t *drc, + struct sockaddr_storage *sockaddr) +{ + drc_client_t *client = NULL; + + GF_ASSERT (drc); + GF_ASSERT (sockaddr); + + client = rpcsvc_client_lookup (drc, sockaddr); + if (client) + goto out; + + /* if lookup fails, allocate cache for the new client */ + client = GF_CALLOC (1, sizeof (drc_client_t), + gf_common_mt_drc_client_t); + if (!client) + goto out; + + client->ref = 0; + client->sock_union = (union gf_sock_union)*sockaddr; + client->op_count = 0; + + if (drc_init_client_cache (drc, client)) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, + "initialization of drc client failed"); + GF_FREE (client); + client = NULL; + goto out; + } + drc->client_count++; + + list_add (&client->client_list, &drc->clients_head); + + out: + return client; +} + +/** + * rpcsvc_need_drc - Determine if a request needs DRC service + * + * @param req - incoming request + * @return 1 if DRC is needed for req, 0 otherwise + */ +int +rpcsvc_need_drc (rpcsvc_request_t *req) +{ + rpcsvc_actor_t *actor = NULL; + rpcsvc_drc_globals_t *drc = NULL; + + GF_ASSERT (req); + GF_ASSERT (req->svc); + + drc = req->svc->drc; + + if (!drc || drc->status == DRC_UNINITIATED) + return 0; + + actor = rpcsvc_program_actor (req); + if (!actor) + return 0; + + return (actor->op_type == DRC_NON_IDEMPOTENT + && drc->type != DRC_TYPE_NONE); +} + +/** + * rpcsvc_drc_client_ref - ref the drc client + * + * @param client - the drc client to ref + * @return client + */ +static drc_client_t * +rpcsvc_drc_client_ref (drc_client_t *client) +{ + GF_ASSERT (client); + client->ref++; + return client; +} + +/** + * rpcsvc_drc_client_unref - unref the drc client, and destroy + * the client on last unref + * + * @param drc - the main drc structure + * @param client - the drc client to unref + * @return NULL if it is the last unref, client otherwise + */ +static drc_client_t * +rpcsvc_drc_client_unref (rpcsvc_drc_globals_t *drc, drc_client_t *client) +{ + GF_ASSERT (drc); + GF_ASSERT (client->ref); + + client->ref--; + if (!client->ref) { + drc->client_count--; + rpcsvc_remove_drc_client (client); + client = NULL; + } + + return client; +} + +/** + * rpcsvc_drc_lookup - lookup a request to see if it is already cached + * + * @param req - incoming request + * @return cached reply of req if found, NULL otherwise + */ +drc_cached_op_t * +rpcsvc_drc_lookup (rpcsvc_request_t *req) +{ + drc_client_t *client = NULL; + drc_cached_op_t *reply = NULL; + + GF_ASSERT (req); + + if (!req->trans->drc_client) { + client = rpcsvc_get_drc_client (req->svc->drc, + &req->trans->peerinfo.sockaddr); + if (!client) + goto out; + req->trans->drc_client = client; + } + + client = rpcsvc_drc_client_ref (req->trans->drc_client); + + if (client->op_count == 0) + goto out; + + reply = rb_find (client->rbtree, req); + + out: + if (client) + rpcsvc_drc_client_unref (req->svc->drc, client); + + return reply; +} + +/** + * rpcsvc_send_cached_reply - send the cached reply for the incoming request + * + * @param req - incoming request (which is a duplicate in this case) + * @param reply - the cached reply for req + * @return 0 on successful reply submission, -1 or other non-zero value otherwise + */ +int +rpcsvc_send_cached_reply (rpcsvc_request_t *req, drc_cached_op_t *reply) +{ + int ret = 0; + + GF_ASSERT (req); + GF_ASSERT (reply); + + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "sending cached reply: xid: %d, " + "client: %s", req->xid, req->trans->peerinfo.identifier); + + rpcsvc_drc_client_ref (reply->client); + ret = rpcsvc_transport_submit (req->trans, + reply->msg.rpchdr, reply->msg.rpchdrcount, + reply->msg.proghdr, reply->msg.proghdrcount, + reply->msg.progpayload, reply->msg.progpayloadcount, + reply->msg.iobref, req->trans_private); + rpcsvc_drc_client_unref (req->svc->drc, reply->client); + + return ret; +} + +/** + * rpcsvc_cache_reply - cache the reply for the processed request 'req' + * + * @param req - processed request + * @param iobref - iobref structure of the reply + * @param rpchdr - rpc header of the reply + * @param rpchdrcount - size of rpchdr + * @param proghdr - program header of the reply + * @param proghdrcount - size of proghdr + * @param payload - payload of the reply if any + * @param payloadcount - size of payload + * @return 0 on success, -1 on failure + */ +int +rpcsvc_cache_reply (rpcsvc_request_t *req, struct iobref *iobref, + struct iovec *rpchdr, int rpchdrcount, + struct iovec *proghdr, int proghdrcount, + struct iovec *payload, int payloadcount) +{ + int ret = -1; + drc_cached_op_t *reply = NULL; + + GF_ASSERT (req); + GF_ASSERT (req->reply); + + reply = req->reply; + + reply->state = DRC_OP_CACHED; + + reply->msg.iobref = iobref_ref (iobref); + + reply->msg.rpchdrcount = rpchdrcount; + reply->msg.rpchdr = iov_dup (rpchdr, rpchdrcount); + + reply->msg.proghdrcount = proghdrcount; + reply->msg.proghdr = iov_dup (proghdr, proghdrcount); + + reply->msg.progpayloadcount = payloadcount; + if (payloadcount) + reply->msg.progpayload = iov_dup (payload, payloadcount); + + // rpcsvc_drc_client_unref (req->svc->drc, req->trans->drc_client); + // rpcsvc_drc_op_unref (req->svc->drc, reply); + ret = 0; + + return ret; +} + +/** + * rpcsvc_vacate_drc_entries - free up some percentage of drc cache + * based on the lru factor + * + * @param drc - the main drc structure + * @return void + */ +static void +rpcsvc_vacate_drc_entries (rpcsvc_drc_globals_t *drc) +{ + uint32_t i = 0; + uint32_t n = 0; + drc_cached_op_t *reply = NULL; + drc_cached_op_t *tmp = NULL; + drc_client_t *client = NULL; + + GF_ASSERT (drc); + + n = drc->global_cache_size / drc->lru_factor; + + list_for_each_entry_safe_reverse (reply, tmp, &drc->cache_head, global_list) { + /* Don't delete ops that are in transit */ + if (reply->state == DRC_OP_IN_TRANSIT) + continue; + + client = reply->client; + + (void *)rb_delete (client->rbtree, reply); + + rpcsvc_drc_op_destroy (drc, reply); + rpcsvc_drc_client_unref (drc, client); + i++; + if (i >= n) + break; + } +} + +/** + * rpcsvc_add_op_to_cache - insert the cached op into the client rbtree and drc list + * + * @param drc - the main drc structure + * @param reply - the op to be inserted + * @return 0 on success, -1 on failure + */ +static int +rpcsvc_add_op_to_cache (rpcsvc_drc_globals_t *drc, drc_cached_op_t *reply) +{ + drc_client_t *client = NULL; + drc_cached_op_t **tmp_reply = NULL; + + GF_ASSERT (drc); + GF_ASSERT (reply); + + client = reply->client; + + /* cache is full, free up some space */ + if (drc->op_count >= drc->global_cache_size) + rpcsvc_vacate_drc_entries (drc); + + tmp_reply = (drc_cached_op_t **)rb_probe (client->rbtree, reply); + if (*tmp_reply != reply) { + /* should never happen */ + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "DRC failed to detect duplicates"); + return -1; + } else if (*tmp_reply == NULL) { + /* mem alloc failed */ + return -1; + } + + client->op_count++; + list_add (&reply->global_list, &drc->cache_head); + drc->op_count++; + + return 0; +} + +/** + * rpcsvc_cache_request - cache the in-transition incoming request + * + * @param req - incoming request + * @return 0 on success, -1 on failure + */ +int +rpcsvc_cache_request (rpcsvc_request_t *req) +{ + int ret = -1; + drc_client_t *client = NULL; + drc_cached_op_t *reply = NULL; + rpcsvc_drc_globals_t *drc = NULL; + + GF_ASSERT (req); + + drc = req->svc->drc; + + client = req->trans->drc_client; + if (!client) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc client is NULL"); + goto out; + } + + reply = mem_get (drc->mempool); + if (!reply) + goto out; + + reply->client = rpcsvc_drc_client_ref (client); + reply->xid = req->xid; + reply->prognum = req->prognum; + reply->progversion = req->progver; + reply->procnum = req->procnum; + reply->state = DRC_OP_IN_TRANSIT; + req->reply = reply; + + ret = rpcsvc_add_op_to_cache (drc, reply); + if (ret) { + req->reply = NULL; + rpcsvc_drc_op_destroy (drc, reply); + rpcsvc_drc_client_unref (drc, client); + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Failed to add op to drc cache"); + } + + out: + return ret; +} + +/** + * + * rpcsvc_drc_priv - function which dumps the drc state + * + * @param drc - the main drc structure + * @return 0 on success, -1 on failure + */ +int32_t +rpcsvc_drc_priv (rpcsvc_drc_globals_t *drc) +{ + int i = 0; + char key[GF_DUMP_MAX_BUF_LEN] = {0}; + drc_client_t *client = NULL; + char ip[INET6_ADDRSTRLEN] = {0}; + + if (!drc || drc->status == DRC_UNINITIATED) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "DRC is " + "uninitialized, not dumping its state"); + return 0; + } + + gf_proc_dump_add_section("rpc.drc"); + + if (TRY_LOCK (&drc->lock)) + return -1; + + gf_proc_dump_build_key (key, "drc", "type"); + gf_proc_dump_write (key, "%d", drc->type); + + gf_proc_dump_build_key (key, "drc", "client_count"); + gf_proc_dump_write (key, "%d", drc->client_count); + + gf_proc_dump_build_key (key, "drc", "current_cache_size"); + gf_proc_dump_write (key, "%d", drc->op_count); + + gf_proc_dump_build_key (key, "drc", "max_cache_size"); + gf_proc_dump_write (key, "%d", drc->global_cache_size); + + gf_proc_dump_build_key (key, "drc", "lru_factor"); + gf_proc_dump_write (key, "%d", drc->lru_factor); + + gf_proc_dump_build_key (key, "drc", "duplicate_request_count"); + gf_proc_dump_write (key, "%d", drc->cache_hits); + + gf_proc_dump_build_key (key, "drc", "in_transit_duplicate_requests"); + gf_proc_dump_write (key, "%d", drc->intransit_hits); + + list_for_each_entry (client, &drc->clients_head, client_list) { + gf_proc_dump_build_key (key, "client", "%d.ip-address", i); + memset (ip, 0, INET6_ADDRSTRLEN); + switch (client->sock_union.storage.ss_family) { + case AF_INET: + gf_proc_dump_write (key, "%s", inet_ntop (AF_INET, + &client->sock_union.sin.sin_addr.s_addr, + ip, INET_ADDRSTRLEN)); + break; + case AF_INET6: + gf_proc_dump_write (key, "%s", inet_ntop (AF_INET6, + &client->sock_union.sin6.sin6_addr, + ip, INET6_ADDRSTRLEN)); + break; + default: + gf_proc_dump_write (key, "%s", "N/A"); + } + + gf_proc_dump_build_key (key, "client", "%d.ref_count", i); + gf_proc_dump_write (key, "%d", client->ref); + gf_proc_dump_build_key (key, "client", "%d.op_count", i); + gf_proc_dump_write (key, "%d", client->op_count); + i++; + } + + UNLOCK (&drc->lock); + return 0; +} + +/** + * rpcsvc_drc_notify - function which is notified of RPC transport events + * + * @param svc - pointer to rpcsvc_t structure of the rpc + * @param xl - pointer to the xlator + * @param event - the event which triggered this notify + * @param data - the transport structure + * @return 0 on success, -1 on failure + */ +int +rpcsvc_drc_notify (rpcsvc_t *svc, void *xl, + rpcsvc_event_t event, void *data) +{ + int ret = -1; + rpc_transport_t *trans = NULL; + drc_client_t *client = NULL; + rpcsvc_drc_globals_t *drc = NULL; + + GF_ASSERT (svc); + GF_ASSERT (svc->drc); + GF_ASSERT (data); + + drc = svc->drc; + + if (drc->status == DRC_UNINITIATED || + drc->type == DRC_TYPE_NONE) + return 0; + + LOCK (&drc->lock); + + trans = (rpc_transport_t *)data; + client = rpcsvc_get_drc_client (drc, &trans->peerinfo.sockaddr); + if (!client) + goto out; + + switch (event) { + case RPCSVC_EVENT_ACCEPT: + trans->drc_client = rpcsvc_drc_client_ref (client); + ret = 0; + break; + + case RPCSVC_EVENT_DISCONNECT: + ret = 0; + if (list_empty (&drc->clients_head)) + break; + /* should be the last unref */ + rpcsvc_drc_client_unref (drc, client); + trans->drc_client = NULL; + break; + + default: + break; + } + + out: + UNLOCK (&drc->lock); + return ret; +} + +/** + * rpcsvc_drc_init - Initialize the duplicate request cache service + * + * @param svc - pointer to rpcsvc_t structure of the rpc + * @param options - the options dictionary which configures drc + * @return 0 on success, non-zero integer on failure + */ +int +rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options) +{ + int ret = 0; + uint32_t drc_type = 0; + uint32_t drc_size = 0; + uint32_t drc_factor = 0; + rpcsvc_drc_globals_t *drc = NULL; + static gf_boolean_t drc_inited = _gf_false; + + GF_ASSERT (svc); + GF_ASSERT (options); + + /* Already inited */ + if (drc_inited) + return 0; + + if (!svc->drc) { + drc = GF_CALLOC (1, sizeof (rpcsvc_drc_globals_t), + gf_common_mt_drc_globals_t); + if (!drc) + return -1; + + svc->drc = drc; + LOCK_INIT (&drc->lock); + } else { + drc = svc->drc; + } + + LOCK (&drc->lock); + if (drc->type != DRC_TYPE_NONE) { + ret = 0; + goto out; + } + + /* Toggle DRC on/off, when more drc types(persistent/cluster) + are added, we shouldn't treat this as boolean */ + ret = dict_get_str_boolean (options, "nfs.drc", _gf_true); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_INFO, "drc user options need second look"); + ret = _gf_true; + } + drc->enable_drc = ret; + + if (ret == _gf_false) { + /* drc off */ + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "DRC is off"); + ret = 0; + goto out; + } + + /* Specify type of DRC to be used */ + ret = dict_get_uint32 (options, "nfs.drc-type", &drc_type); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc type not set." + " Continuing with default"); + drc_type = DRC_DEFAULT_TYPE; + } + + drc->type = drc_type; + + /* Set the global cache size (no. of ops to cache) */ + ret = dict_get_uint32 (options, "nfs.drc-size", &drc_size); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc size not set." + " Continuing with default size"); + drc_size = DRC_DEFAULT_CACHE_SIZE; + } + + drc->global_cache_size = drc_size; + + /* Mempool for cached ops */ + drc->mempool = mem_pool_new (drc_cached_op_t, drc->global_cache_size); + if (!drc->mempool) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get mempool for" + " DRC, drc-size: %d", drc->global_cache_size); + ret = -1; + goto out; + } + + /* What percent of cache to be evicted whenever it fills up */ + ret = dict_get_uint32 (options, "nfs.drc-lru-factor", &drc_factor); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc lru factor not set." + " Continuing with policy default"); + drc_factor = DRC_DEFAULT_LRU_FACTOR; + } + + drc->lru_factor = (drc_lru_factor_t) drc_factor; + + INIT_LIST_HEAD (&drc->clients_head); + INIT_LIST_HEAD (&drc->cache_head); + + ret = rpcsvc_register_notify (svc, rpcsvc_drc_notify, THIS); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "registration of drc_notify function failed"); + goto out; + } + + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "drc init successful"); + drc->status = DRC_INITIATED; + drc_inited = _gf_true; + + out: + UNLOCK (&drc->lock); + if (ret == -1) { + if (drc->mempool) { + mem_pool_destroy (drc->mempool); + drc->mempool = NULL; + } + GF_FREE (drc); + svc->drc = NULL; + } + return ret; +} + +int +rpcsvc_drc_reconfigure (rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + gf_boolean_t enable_drc = _gf_false; + rpcsvc_drc_globals_t *drc = NULL; + uint32_t drc_size = 0; + + if ((!svc) || (!options)) + return (-1); + + drc = svc->drc; + /* reconfig for drc-size */ + if (dict_get_uint32 (options, "nfs.drc-size", &drc_size)) + drc_size = DRC_DEFAULT_CACHE_SIZE; + + if (drc->global_cache_size != drc_size) { + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "nfs.drc-size size can not " + "be reconfigured without NFS server restart."); + return (-1); + } + + /* reconfig for nfs.drc */ + ret = dict_get_str_boolean (options, "nfs.drc", _gf_true); + if (ret < 0) { + ret = _gf_true; + } + enable_drc = ret; + + if (drc->enable_drc == enable_drc) + return 0; + + drc->enable_drc = enable_drc; + if (enable_drc) { + if (drc == NULL) + return rpcsvc_drc_init(svc, options); + } else { + if (drc == NULL) + return (0); + + LOCK (&drc->lock); + (void) rpcsvc_unregister_notify (svc, rpcsvc_drc_notify, THIS); + if (drc->mempool) { + mem_pool_destroy (drc->mempool); + drc->mempool = NULL; + } + UNLOCK (&drc->lock); + GF_FREE (drc); + svc->drc = NULL; + } + + return (0); +} diff --git a/rpc/rpc-lib/src/rpc-drc.h b/rpc/rpc-lib/src/rpc-drc.h new file mode 100644 index 000000000..7dfaef978 --- /dev/null +++ b/rpc/rpc-lib/src/rpc-drc.h @@ -0,0 +1,104 @@ +/* + Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef RPC_DRC_H +#define RPC_DRC_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpcsvc-common.h" +#include "rpcsvc.h" +#include "locking.h" +#include "dict.h" +#include "rb.h" + +/* per-client cache structure */ +struct drc_client { + uint32_t ref; + union gf_sock_union sock_union; + /* pointers to the cache */ + struct rb_table *rbtree; + /* no. of ops currently cached */ + uint32_t op_count; + struct list_head client_list; +}; + +struct drc_cached_op { + drc_op_state_t state; + uint32_t xid; + int prognum; + int progversion; + int procnum; + rpc_transport_msg_t msg; + drc_client_t *client; + struct list_head client_list; + struct list_head global_list; + int32_t ref; +}; + +/* global drc definitions */ +enum drc_status { + DRC_UNINITIATED, + DRC_INITIATED +}; +typedef enum drc_status drc_status_t; + +struct drc_globals { + /* allocator must be the first member since + * it is used so in gf_libavl_allocator + */ + struct libavl_allocator allocator; + drc_type_t type; + /* configurable size parameter */ + uint32_t global_cache_size; + drc_lru_factor_t lru_factor; + gf_lock_t lock; + drc_status_t status; + uint32_t op_count; + uint64_t cache_hits; + uint64_t intransit_hits; + struct mem_pool *mempool; + struct list_head cache_head; + uint32_t client_count; + struct list_head clients_head; + gf_boolean_t enable_drc; +}; + +int +rpcsvc_need_drc (rpcsvc_request_t *req); + +drc_cached_op_t * +rpcsvc_drc_lookup (rpcsvc_request_t *req); + +int +rpcsvc_send_cached_reply (rpcsvc_request_t *req, drc_cached_op_t *reply); + +int +rpcsvc_cache_reply (rpcsvc_request_t *req, struct iobref *iobref, + struct iovec *rpchdr, int rpchdrcount, + struct iovec *proghdr, int proghdrcount, + struct iovec *payload, int payloadcount); + +int +rpcsvc_cache_request (rpcsvc_request_t *req); + +int32_t +rpcsvc_drc_priv (rpcsvc_drc_globals_t *drc); + +int +rpcsvc_drc_init (rpcsvc_t *svc, dict_t *options); + +int +rpcsvc_drc_reconfigure (rpcsvc_t *svc, dict_t *options); + +#endif /* RPC_DRC_H */ diff --git a/rpc/rpc-lib/src/rpc-transport.c b/rpc/rpc-lib/src/rpc-transport.c index b77ea2aa5..c24d41084 100644 --- a/rpc/rpc-lib/src/rpc-transport.c +++ b/rpc/rpc-lib/src/rpc-transport.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include <dlfcn.h> @@ -42,604 +33,78 @@ #define GF_OPTION_LIST_EMPTY(_opt) (_opt->value[0] == NULL) #endif -/* RFC 1123 & 952 */ -static char -valid_host_name (char *address, int length) -{ - int i = 0; - char ret = 1; - - if ((length > 75) || (length == 1)) { - ret = 0; - goto out; - } - - if (!isalnum (address[length - 1])) { - ret = 0; - goto out; - } - for (i = 0; i < length; i++) { - if (!isalnum (address[i]) && (address[i] != '.') - && (address[i] != '-')) { - ret = 0; - goto out; - } - } - -out: - return ret; -} - -static char -valid_ipv4_address (char *address, int length) +int +rpc_transport_get_myaddr (rpc_transport_t *this, char *peeraddr, int addrlen, + struct sockaddr_storage *sa, size_t salen) { - int octets = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = strtok_r (tmp, ".", &ptr); - - while (prev != NULL) - { - octets++; - value = strtol (prev, &endptr, 10); - if ((value > 255) || (value < 0) || (endptr != NULL)) { - ret = 0; - goto out; - } + int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", this, out); - prev = strtok_r (NULL, ".", &ptr); - } - - if (octets != 4) { - ret = 0; - } + ret = this->ops->get_myaddr (this, peeraddr, addrlen, sa, salen); out: - GF_FREE (tmp); return ret; } - -static char -valid_ipv6_address (char *address, int length) +int32_t +rpc_transport_get_myname (rpc_transport_t *this, char *hostname, int hostlen) { - int hex_numbers = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = strtok_r (tmp, ":", &ptr); - - while (prev != NULL) - { - hex_numbers++; - value = strtol (prev, &endptr, 16); - if ((value > 0xffff) || (value < 0) - || (endptr != NULL && *endptr != '\0')) { - ret = 0; - goto out; - } - - prev = strtok_r (NULL, ":", &ptr); - } - - if (hex_numbers > 8) { - ret = 0; - } + int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", this, out); + ret = this->ops->get_myname (this, hostname, hostlen); out: - GF_FREE (tmp); return ret; } - -static char -valid_internet_address (char *address) +int32_t +rpc_transport_get_peername (rpc_transport_t *this, char *hostname, int hostlen) { - char ret = 0; - int length = 0; - - if (address == NULL) { - goto out; - } - - length = strlen (address); - if (length == 0) { - goto out; - } - - if (valid_ipv4_address (address, length) - || valid_ipv6_address (address, length) - || valid_host_name (address, length)) { - ret = 1; - } + int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", this, out); + ret = this->ops->get_peername (this, hostname, hostlen); out: return ret; } - int -__volume_option_value_validate (char *name, - data_pair_t *pair, - volume_option_t *opt) +rpc_transport_throttle (rpc_transport_t *this, gf_boolean_t onoff) { - int i = 0; - int ret = -1; - uint64_t input_size = 0; - long long inputll = 0; + int ret = 0; - /* Key is valid, validate the option */ - switch (opt->type) { - case GF_OPTION_TYPE_XLATOR: - break; + if (!this->ops->throttle) + return -ENOSYS; - case GF_OPTION_TYPE_PATH: - { - if (strstr (pair->value->data, "../")) { - gf_log (name, GF_LOG_ERROR, - "invalid path given '%s'", - pair->value->data); - ret = -1; - goto out; - } - - /* Make sure the given path is valid */ - if (pair->value->data[0] != '/') { - gf_log (name, GF_LOG_WARNING, - "option %s %s: '%s' is not an " - "absolute path name", - pair->key, pair->value->data, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INT: - { - /* Check the range */ - if (gf_string2longlong (pair->value->data, - &inputll) != 0) { - gf_log (name, GF_LOG_ERROR, - "invalid number format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((inputll < opt->min) || - (inputll > opt->max)) { - gf_log (name, GF_LOG_WARNING, - "'%lld' in 'option %s %s' is out of " - "range [%"PRId64" - %"PRId64"]", - inputll, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_SIZET: - { - /* Check the range */ - if (gf_string2bytesize (pair->value->data, - &input_size) != 0) { - gf_log (name, GF_LOG_ERROR, - "invalid size format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (name, GF_LOG_ERROR, - "'%"PRId64"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_BOOL: - { - /* Check if the value is one of - '0|1|on|off|no|yes|true|false|enable|disable' */ - gf_boolean_t bool_value; - if (gf_string2boolean (pair->value->data, - &bool_value) != 0) { - gf_log (name, GF_LOG_ERROR, - "option %s %s: '%s' is not a valid " - "boolean value", - pair->key, pair->value->data, - pair->value->data); - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_STR: - { - /* Check if the '*str' is valid */ - if (GF_OPTION_LIST_EMPTY(opt)) { - ret = 0; - goto out; - } - - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { - if (strcasecmp (opt->value[i], - pair->value->data) == 0) { - ret = 0; - break; - } - } - - if ((i == ZR_OPTION_MAX_ARRAY_SIZE) - || ((i < ZR_OPTION_MAX_ARRAY_SIZE) - && (!opt->value[i]))) { - /* enter here only if - * 1. reached end of opt->value array and haven't - * validated input - * OR - * 2. valid input list is less than - * ZR_OPTION_MAX_ARRAY_SIZE and input has not - * matched all possible input values. - */ - char given_array[4096] = {0,}; - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { - strcat (given_array, opt->value[i]); - strcat (given_array, ", "); - } - - gf_log (name, GF_LOG_ERROR, - "option %s %s: '%s' is not valid " - "(possible options are %s)", - pair->key, pair->value->data, - pair->value->data, given_array); - - goto out; - } - } - break; - case GF_OPTION_TYPE_PERCENT: - { - uint32_t percent = 0; + ret = this->ops->throttle (this, onoff); - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) != 0) { - gf_log (name, GF_LOG_ERROR, - "invalid percent format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((percent < 0) || (percent > 100)) { - gf_log (name, GF_LOG_ERROR, - "'%d' in 'option %s %s' is out of " - "range [0 - 100]", - percent, pair->key, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_PERCENT_OR_SIZET: - { - uint32_t percent = 0; - uint64_t input_size = 0; - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) == 0) { - if (percent > 100) { - gf_log (name, GF_LOG_DEBUG, - "value given was greater than 100, " - "assuming this is actually a size"); - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && - (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check " - "required for " - "'option %s %s'", - pair->key, - pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (name, GF_LOG_ERROR, - "'%"PRId64"' in " - "'option %s %s' is out" - " of range [%"PRId64"" - "- %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - // It is a size - ret = 0; - goto out; - } else { - // It's not a percent or size - gf_log (name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - - } - // It is a percent - ret = 0; - goto out; - } else { - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (name, GF_LOG_ERROR, - "'%"PRId64"' in 'option %s %s'" - " is out of range [%"PRId64" -" - " %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - } else { - // It's not a percent or size - gf_log (name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - //It is a size - ret = 0; - goto out; - } - - } - break; - case GF_OPTION_TYPE_TIME: - { - uint32_t input_time = 0; - - /* Check if the value is valid percentage */ - if (gf_string2time (pair->value->data, - &input_time) != 0) { - gf_log (name, - GF_LOG_ERROR, - "invalid time format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - if ((input_time < opt->min) || - (input_time > opt->max)) { - gf_log (name, GF_LOG_ERROR, - "'%"PRIu32"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_time, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_DOUBLE: - { - double input_time = 0.0; - - /* Check if the value is valid double */ - if (gf_string2double (pair->value->data, - &input_time) != 0) { - gf_log (name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if (input_time < 0.0) { - gf_log (name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (name, GF_LOG_DEBUG, - "no range check required for 'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INTERNET_ADDRESS: - { - if (valid_internet_address (pair->value->data)) { - ret = 0; - } - } - break; - case GF_OPTION_TYPE_ANY: - /* NO CHECK */ - ret = 0; - break; - } - -out: - return ret; -} - -/* FIXME: this procedure should be removed from transport */ -int -validate_volume_options (char *name, dict_t *options, volume_option_t *opt) -{ - int i = 0; - int ret = -1; - int index = 0; - volume_option_t *trav = NULL; - data_pair_t *pairs = NULL; - - if (!opt) { - ret = 0; - goto out; - } - - /* First search for not supported options, if any report error */ - pairs = options->members_list; - while (pairs) { - ret = -1; - for (index = 0; - opt[index].key && opt[index].key[0] ; index++) { - trav = &(opt[index]); - for (i = 0 ; - (i < ZR_VOLUME_MAX_NUM_KEY) && - trav->key[i]; i++) { - /* Check if the key is valid */ - if (fnmatch (trav->key[i], - pairs->key, FNM_NOESCAPE) == 0) { - ret = 0; - break; - } - } - if (!ret) { - if (i) { - gf_log (name, GF_LOG_WARNING, - "option '%s' is deprecated, " - "preferred is '%s', continuing" - " with correction", - trav->key[i], trav->key[0]); - /* TODO: some bytes lost */ - pairs->key = gf_strdup (trav->key[0]); - } - break; - } - } - if (!ret) { - ret = __volume_option_value_validate (name, pairs, trav); - if (-1 == ret) { - goto out; - } - } - - pairs = pairs->next; - } - - ret = 0; - out: - return ret; -} - -int32_t -rpc_transport_get_myaddr (rpc_transport_t *this, char *peeraddr, int addrlen, - struct sockaddr *sa, size_t salen) -{ - if (!this) - return -1; - - return this->ops->get_myaddr (this, peeraddr, addrlen, sa, salen); -} - -int32_t -rpc_transport_get_myname (rpc_transport_t *this, char *hostname, int hostlen) -{ - if (!this) - return -1; - - return this->ops->get_myname (this, hostname, hostlen); -} - -int32_t -rpc_transport_get_peername (rpc_transport_t *this, char *hostname, int hostlen) -{ - if (!this) - return -1; - return this->ops->get_peername (this, hostname, hostlen); + return ret; } int32_t rpc_transport_get_peeraddr (rpc_transport_t *this, char *peeraddr, int addrlen, - struct sockaddr *sa, size_t salen) + struct sockaddr_storage *sa, size_t salen) { - if (!this) - return -1; - return this->ops->get_peeraddr (this, peeraddr, addrlen, sa, salen); + int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", this, out); + + ret = this->ops->get_peeraddr (this, peeraddr, addrlen, sa, salen); +out: + return ret; } void rpc_transport_pollin_destroy (rpc_transport_pollin_t *pollin) { - if (!pollin) { - goto out; - } + GF_VALIDATE_OR_GOTO ("rpc", pollin, out); - if (pollin->vectored) { - if (pollin->data.vector.iobuf1) { - iobuf_unref (pollin->data.vector.iobuf1); - } + if (pollin->iobref) { + iobref_unref (pollin->iobref); + } - if (pollin->data.vector.iobuf2) { - iobuf_unref (pollin->data.vector.iobuf2); - } - } else { - if (pollin->data.simple.iobuf) { - iobuf_unref (pollin->data.simple.iobuf); - } + if (pollin->hdr_iobuf) { + iobuf_unref (pollin->hdr_iobuf); } if (pollin->private) { @@ -654,181 +119,32 @@ out: rpc_transport_pollin_t * -rpc_transport_pollin_alloc (rpc_transport_t *this, struct iobuf *iobuf, - size_t size, struct iobuf *vectored_buf, - size_t vectored_size, void *private) +rpc_transport_pollin_alloc (rpc_transport_t *this, struct iovec *vector, + int count, struct iobuf *hdr_iobuf, + struct iobref *iobref, void *private) { rpc_transport_pollin_t *msg = NULL; msg = GF_CALLOC (1, sizeof (*msg), gf_common_mt_rpc_trans_pollin_t); if (!msg) { - gf_log ("rpc-transport", GF_LOG_ERROR, "out of memory"); goto out; } - if (vectored_buf) { + if (count > 1) { msg->vectored = 1; - msg->data.vector.iobuf1 = iobuf_ref (iobuf); - msg->data.vector.size1 = size; - - msg->data.vector.iobuf2 = iobuf_ref (vectored_buf); - msg->data.vector.size2 = vectored_size; - } else { - msg->data.simple.iobuf = iobuf_ref (iobuf); - msg->data.simple.size = size; } + memcpy (msg->vector, vector, count * sizeof (*vector)); + msg->count = count; + msg->iobref = iobref_ref (iobref); msg->private = private; -out: - return msg; -} - - -rpc_transport_pollin_t * -rpc_transport_same_process_pollin_alloc (rpc_transport_t *this, - struct iovec *rpchdr, int rpchdrcount, - struct iovec *proghdr, - int proghdrcount, - struct iovec *progpayload, - int progpayloadcount, - rpc_transport_rsp_t *rsp, - char is_request) -{ - rpc_transport_pollin_t *msg = NULL; - int rpchdrlen = 0, proghdrlen = 0; - int progpayloadlen = 0; - char vectored = 0; - char *hdr = NULL, *progpayloadbuf = NULL; - - if (!rpchdr || !proghdr) { - goto err; - } + if (hdr_iobuf) + msg->hdr_iobuf = iobuf_ref (hdr_iobuf); - msg = GF_CALLOC (1, sizeof (*msg), gf_common_mt_rpc_trans_pollin_t); - if (!msg) { - gf_log ("rpc-transport", GF_LOG_ERROR, "out of memory"); - goto err; - } - - rpchdrlen = iov_length (rpchdr, rpchdrcount); - proghdrlen = iov_length (proghdr, proghdrcount); - - if (progpayload) { - vectored = 1; - progpayloadlen = iov_length (progpayload, progpayloadcount); - } - - /* FIXME: we are assuming rpchdr and proghdr will fit into - * an iobuf (128KB) - */ - if ((rpchdrlen + proghdrlen) > this->ctx->page_size) { - gf_log ("rpc_transport", GF_LOG_DEBUG, "program hdr and rpc" - " hdr together combined (%d) is bigger than " - "iobuf size (%zu)", (rpchdrlen + proghdrlen), - this->ctx->page_size); - goto err; - } - - if (vectored) { - msg->data.vector.iobuf1 = iobuf_get (this->ctx->iobuf_pool); - if (!msg->data.vector.iobuf1) { - gf_log ("rpc_transport", GF_LOG_ERROR, - "out of memory"); - goto err; - } - - msg->data.vector.size1 = rpchdrlen + proghdrlen; - hdr = iobuf_ptr (msg->data.vector.iobuf1); - - if (!is_request && rsp) { - msg->data.vector.iobuf2 = rsp->rspbuf; - progpayloadbuf = rsp->rspvec->iov_base; - } else { - msg->data.vector.iobuf2 = iobuf_get (this->ctx->iobuf_pool); - if (!msg->data.vector.iobuf2) { - gf_log ("rpc_transport", GF_LOG_ERROR, - "out of memory"); - goto err; - } - - progpayloadbuf = iobuf_ptr (msg->data.vector.iobuf2); - } - msg->data.vector.size2 = progpayloadlen; - } else { - if (!is_request && rsp) { - /* FIXME: Assuming rspvec contains only one vector */ - hdr = rsp->rspvec->iov_base; - msg->data.simple.iobuf = rsp->rspbuf; - } else { - msg->data.simple.iobuf = iobuf_get (this->ctx->iobuf_pool); - if (!msg->data.simple.iobuf) { - gf_log ("rpc_transport", GF_LOG_ERROR, - "out of memory"); - goto err; - } - - hdr = iobuf_ptr (msg->data.simple.iobuf); - } - - msg->data.simple.size = rpchdrlen + proghdrlen; - } - - iov_unload (hdr, rpchdr, rpchdrcount); - hdr += rpchdrlen; - iov_unload (hdr, proghdr, proghdrcount); - - if (progpayload) { - iov_unload (progpayloadbuf, progpayload, - progpayloadcount); - } - - if (is_request) { - msg->private = rsp; - } - return msg; -err: - if (msg) { - rpc_transport_pollin_destroy (msg); - } - - return NULL; -} - - -rpc_transport_handover_t * -rpc_transport_handover_alloc (rpc_transport_pollin_t *pollin) -{ - rpc_transport_handover_t *msg = NULL; - - msg = GF_CALLOC (1, sizeof (*msg), gf_common_mt_rpc_trans_handover_t); - if (!msg) { - gf_log ("rpc_transport", GF_LOG_ERROR, "out of memory"); - goto out; - } - - msg->pollin = pollin; - INIT_LIST_HEAD (&msg->list); out: return msg; } -void -rpc_transport_handover_destroy (rpc_transport_handover_t *msg) -{ - if (!msg) { - goto out; - } - - if (msg->pollin) { - rpc_transport_pollin_destroy (msg->pollin); - } - - GF_FREE (msg); - -out: - return; -} - rpc_transport_t * rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) @@ -841,30 +157,35 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) int32_t ret = -1; int8_t is_tcp = 0, is_unix = 0, is_ibsdp = 0; volume_opt_list_t *vol_opt = NULL; + gf_boolean_t bind_insecure = _gf_false; + xlator_t *this = NULL; GF_VALIDATE_OR_GOTO("rpc-transport", options, fail); GF_VALIDATE_OR_GOTO("rpc-transport", ctx, fail); GF_VALIDATE_OR_GOTO("rpc-transport", trans_name, fail); trans = GF_CALLOC (1, sizeof (struct rpc_transport), gf_common_mt_rpc_trans_t); - GF_VALIDATE_OR_GOTO("rpc-transport", trans, fail); + if (!trans) + goto fail; trans->name = gf_strdup (trans_name); - GF_VALIDATE_OR_GOTO ("rpc-transport", trans->name, fail); + if (!trans->name) + goto fail; trans->ctx = ctx; type = str; /* Backward compatibility */ - ret = dict_get_str (options, "transport-type", &type); + ret = dict_get_str (options, "transport-type", &type); if (ret < 0) { ret = dict_set_str (options, "transport-type", "socket"); if (ret < 0) gf_log ("dict", GF_LOG_DEBUG, "setting transport-type failed"); - gf_log ("rpc-transport", GF_LOG_WARNING, - "missing 'option transport-type'. defaulting to " - "\"socket\""); + else + gf_log ("rpc-transport", GF_LOG_DEBUG, + "missing 'option transport-type'. defaulting to " + "\"socket\""); } else { { /* Backword compatibility to handle * /client, @@ -902,6 +223,28 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) } } + /* client-bind-insecure is for clients protocol, and + * bind-insecure for glusterd. Both mutually exclusive + */ + ret = dict_get_str (options, "client-bind-insecure", &type); + if (ret) + ret = dict_get_str (options, "bind-insecure", &type); + if (ret == 0) { + ret = gf_string2boolean (type, &bind_insecure); + if (ret < 0) { + gf_log ("rcp-transport", GF_LOG_WARNING, + "bind-insecure option %s is not a" + " valid bool option", type); + goto fail; + } + if (_gf_true == bind_insecure) + trans->bind_insecure = 1; + else + trans->bind_insecure = 0; + } else { + trans->bind_insecure = 0; + } + ret = dict_get_str (options, "transport-type", &type); if (ret < 0) { gf_log ("rpc-transport", GF_LOG_ERROR, @@ -912,22 +255,24 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) ret = gf_asprintf (&name, "%s/%s.so", RPC_TRANSPORTDIR, type); if (-1 == ret) { - gf_log ("rpc-transport", GF_LOG_ERROR, "asprintf failed"); goto fail; } + gf_log ("rpc-transport", GF_LOG_DEBUG, "attempt to load file %s", name); handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); if (handle == NULL) { gf_log ("rpc-transport", GF_LOG_ERROR, "%s", dlerror ()); - gf_log ("rpc-transport", GF_LOG_ERROR, + gf_log ("rpc-transport", GF_LOG_WARNING, "volume '%s': transport-type '%s' is not valid or " "not found on this machine", trans_name, type); goto fail; } + trans->dl_handle = handle; + trans->ops = dlsym (handle, "tops"); if (trans->ops == NULL) { gf_log ("rpc-transport", GF_LOG_ERROR, @@ -935,43 +280,53 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) goto fail; } - trans->init = dlsym (handle, "init"); + *VOID(&(trans->init)) = dlsym (handle, "init"); if (trans->init == NULL) { gf_log ("rpc-transport", GF_LOG_ERROR, "dlsym (gf_rpc_transport_init) on %s", dlerror ()); goto fail; } - trans->fini = dlsym (handle, "fini"); + *VOID(&(trans->fini)) = dlsym (handle, "fini"); if (trans->fini == NULL) { gf_log ("rpc-transport", GF_LOG_ERROR, "dlsym (gf_rpc_transport_fini) on %s", dlerror ()); goto fail; } + *VOID(&(trans->reconfigure)) = dlsym (handle, "reconfigure"); + if (trans->reconfigure == NULL) { + gf_log ("rpc-transport", GF_LOG_DEBUG, + "dlsym (gf_rpc_transport_reconfigure) on %s", dlerror()); + } + vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), gf_common_mt_volume_opt_list_t); if (!vol_opt) { - gf_log (trans_name, GF_LOG_ERROR, "out of memory"); goto fail; } + this = THIS; vol_opt->given_opt = dlsym (handle, "options"); if (vol_opt->given_opt == NULL) { gf_log ("rpc-transport", GF_LOG_DEBUG, "volume option validation not specified"); } else { - /* FIXME: is adding really needed? */ - /* list_add_tail (&vol_opt->list, &xl->volume_options); */ - if (-1 == - validate_volume_options (trans_name, options, - vol_opt->given_opt)) { + INIT_LIST_HEAD (&vol_opt->list); + list_add_tail (&vol_opt->list, &(this->volume_options)); + if (xlator_options_validate_list (this, options, vol_opt, + NULL)) { gf_log ("rpc-transport", GF_LOG_ERROR, "volume option validation failed"); goto fail; } } + trans->options = options; + + pthread_mutex_init (&trans->lock, NULL); + trans->xl = this; + ret = trans->init (trans); if (ret != 0) { gf_log ("rpc-transport", GF_LOG_ERROR, @@ -979,26 +334,26 @@ rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *trans_name) goto fail; } - trans->options = options; + return_trans = trans; + + GF_FREE (name); - pthread_mutex_init (&trans->lock, NULL); - return_trans = trans; return return_trans; fail: if (trans) { - if (trans->name) { - GF_FREE (trans->name); - } + GF_FREE (trans->name); + + if (trans->dl_handle) + dlclose (trans->dl_handle); GF_FREE (trans); } - if (name) { - GF_FREE (name); - } + GF_FREE (name); - if (vol_opt) { + if (vol_opt && !list_empty (&vol_opt->list)) { + list_del_init (&vol_opt->list); GF_FREE (vol_opt); } @@ -1010,52 +365,6 @@ int32_t rpc_transport_submit_request (rpc_transport_t *this, rpc_transport_req_t *req) { int32_t ret = -1; - rpc_transport_t *peer_trans = NULL; - rpc_transport_pollin_t *pollin = NULL; - rpc_transport_handover_t *handover_msg = NULL; - rpc_transport_rsp_t *rsp = NULL; - - if (this->peer_trans) { - peer_trans = this->peer_trans; - - rsp = GF_CALLOC (1, sizeof (*rsp), gf_common_mt_rpc_trans_rsp_t); - if (!rsp) { - ret = -ENOMEM; - goto fail; - } - - *rsp = req->rsp; - - pollin = rpc_transport_same_process_pollin_alloc (this, req->msg.rpchdr, - req->msg.rpchdrcount, - req->msg.proghdr, - req->msg.proghdrcount, - req->msg.progpayload, - req->msg.progpayloadcount, - rsp, 1); - if (!pollin) { - GF_FREE (rsp); - ret = -ENOMEM; - goto fail; - } - - handover_msg = rpc_transport_handover_alloc (pollin); - if (!handover_msg) { - rpc_transport_pollin_destroy (pollin); - ret = -ENOMEM; - goto fail; - } - - pthread_mutex_lock (&peer_trans->handover.mutex); - { - list_add_tail (&handover_msg->list, - &peer_trans->handover.msgs); - pthread_cond_broadcast (&peer_trans->handover.cond); - } - pthread_mutex_unlock (&peer_trans->handover.mutex); - - return 0; - } GF_VALIDATE_OR_GOTO("rpc_transport", this, fail); GF_VALIDATE_OR_GOTO("rpc_transport", this->ops, fail); @@ -1070,40 +379,6 @@ int32_t rpc_transport_submit_reply (rpc_transport_t *this, rpc_transport_reply_t *reply) { int32_t ret = -1; - rpc_transport_t *peer_trans = NULL; - rpc_transport_pollin_t *pollin = NULL; - rpc_transport_handover_t *handover_msg = NULL; - - if (this->peer_trans) { - peer_trans = this->peer_trans; - - pollin = rpc_transport_same_process_pollin_alloc (this, reply->msg.rpchdr, - reply->msg.rpchdrcount, - reply->msg.proghdr, - reply->msg.proghdrcount, - reply->msg.progpayload, - reply->msg.progpayloadcount, - reply->private, 0); - if (!pollin) { - return -ENOMEM; - } - - handover_msg = rpc_transport_handover_alloc (pollin); - if (!handover_msg) { - rpc_transport_pollin_destroy (pollin); - return -ENOMEM; - } - - pthread_mutex_lock (&peer_trans->handover.mutex); - { - list_add_tail (&handover_msg->list, - &peer_trans->handover.msgs); - pthread_cond_broadcast (&peer_trans->handover.cond); - } - pthread_mutex_unlock (&peer_trans->handover.mutex); - - return 0; - } GF_VALIDATE_OR_GOTO("rpc_transport", this, fail); GF_VALIDATE_OR_GOTO("rpc_transport", this->ops, fail); @@ -1115,13 +390,13 @@ fail: int32_t -rpc_transport_connect (rpc_transport_t *this) +rpc_transport_connect (rpc_transport_t *this, int port) { int ret = -1; GF_VALIDATE_OR_GOTO("rpc_transport", this, fail); - ret = this->ops->connect (this); + ret = this->ops->connect (this, port); fail: return ret; } @@ -1160,9 +435,18 @@ rpc_transport_destroy (rpc_transport_t *this) GF_VALIDATE_OR_GOTO("rpc_transport", this, fail); + if (this->options) + dict_unref (this->options); if (this->fini) this->fini (this); + pthread_mutex_destroy (&this->lock); + + GF_FREE (this->name); + + if (this->dl_handle) + dlclose (this->dl_handle); + GF_FREE (this); fail: return ret; @@ -1198,14 +482,17 @@ rpc_transport_unref (rpc_transport_t *this) pthread_mutex_lock (&this->lock); { - refcount = --this->refcount; + refcount = --this->refcount; } pthread_mutex_unlock (&this->lock); if (refcount == 0) { - /* xlator_notify (this->xl, GF_EVENT_RPC_TRANSPORT_CLEANUP, - this); */ - rpc_transport_destroy (this); + if (this->mydata) + this->notify (this, this->mydata, RPC_TRANSPORT_CLEANUP, + NULL); + this->mydata = NULL; + this->notify = NULL; + rpc_transport_destroy (this); } ret = 0; @@ -1219,83 +506,174 @@ rpc_transport_notify (rpc_transport_t *this, rpc_transport_event_t event, void *data, ...) { int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", this, out); - if (this == NULL) { - goto out; + if (this->notify != NULL) { + ret = this->notify (this, this->mydata, event, data); + } else { + ret = 0; } - - //ret = this->notify (this, this->notify_data, event, data); - ret = this->notify (this, this->mydata, event, data); out: return ret; } -void * -rpc_transport_peerproc (void *trans_data) + +inline int +rpc_transport_register_notify (rpc_transport_t *trans, + rpc_transport_notify_t notify, void *mydata) { - rpc_transport_t *trans = NULL; - rpc_transport_handover_t *msg = NULL; + int32_t ret = -1; + GF_VALIDATE_OR_GOTO ("rpc", trans, out); - trans = trans_data; + trans->notify = notify; + trans->mydata = mydata; - while (1) { - pthread_mutex_lock (&trans->handover.mutex); - { - while (list_empty (&trans->handover.msgs)) - pthread_cond_wait (&trans->handover.cond, - &trans->handover.mutex); + ret = 0; +out: + return ret; +} - msg = list_entry (trans->handover.msgs.next, - rpc_transport_handover_t, list); - list_del_init (&msg->list); - } - pthread_mutex_unlock (&trans->handover.mutex); - rpc_transport_notify (trans, RPC_TRANSPORT_MSG_RECEIVED, msg->pollin); - rpc_transport_handover_destroy (msg); - } -} +//give negative values to skip setting that value +//this function asserts if both the values are negative. +//why call it if you dont set it. +int +rpc_transport_keepalive_options_set (dict_t *options, int32_t interval, + int32_t time) +{ + int ret = -1; + + GF_ASSERT (options); + GF_ASSERT ((interval > 0) || (time > 0)); + + ret = dict_set_int32 (options, + "transport.socket.keepalive-interval", interval); + if (ret) + goto out; + ret = dict_set_int32 (options, + "transport.socket.keepalive-time", time); + if (ret) + goto out; +out: + return ret; +} int -rpc_transport_setpeer (rpc_transport_t *trans, rpc_transport_t *peer_trans) +rpc_transport_unix_options_build (dict_t **options, char *filepath, + int frame_timeout) { - trans->peer_trans = rpc_transport_ref (peer_trans); + dict_t *dict = NULL; + char *fpath = NULL; + int ret = -1; + + GF_ASSERT (filepath); + GF_ASSERT (options); - INIT_LIST_HEAD (&trans->handover.msgs); - pthread_cond_init (&trans->handover.cond, NULL); - pthread_mutex_init (&trans->handover.mutex, NULL); - pthread_create (&trans->handover.thread, NULL, - rpc_transport_peerproc, trans); + dict = dict_new (); + if (!dict) + goto out; - peer_trans->peer_trans = rpc_transport_ref (trans); + fpath = gf_strdup (filepath); + if (!fpath) { + ret = -1; + goto out; + } - INIT_LIST_HEAD (&peer_trans->handover.msgs); - pthread_cond_init (&peer_trans->handover.cond, NULL); - pthread_mutex_init (&peer_trans->handover.mutex, NULL); - pthread_create (&peer_trans->handover.thread, NULL, - rpc_transport_peerproc, peer_trans); + ret = dict_set_dynstr (dict, "transport.socket.connect-path", fpath); + if (ret) + goto out; - return 0; -} + ret = dict_set_str (dict, "transport.address-family", "unix"); + if (ret) + goto out; + ret = dict_set_str (dict, "transport.socket.nodelay", "off"); + if (ret) + goto out; -inline int -rpc_transport_register_notify (rpc_transport_t *trans, - rpc_transport_notify_t notify, void *mydata) + ret = dict_set_str (dict, "transport-type", "socket"); + if (ret) + goto out; + + ret = dict_set_str (dict, "transport.socket.keepalive", "off"); + if (ret) + goto out; + + if (frame_timeout > 0) { + ret = dict_set_int32 (dict, "frame-timeout", frame_timeout); + if (ret) + goto out; + } + + *options = dict; +out: + if (ret) { + GF_FREE (fpath); + if (dict) + dict_unref (dict); + } + return ret; +} + +int +rpc_transport_inet_options_build (dict_t **options, const char *hostname, + int port) { - int ret = -1; + dict_t *dict = NULL; + char *host = NULL; + int ret = -1; + + GF_ASSERT (options); + GF_ASSERT (hostname); + GF_ASSERT (port >= 1024); + + dict = dict_new (); + if (!dict) + goto out; - if (trans == NULL) { + host = gf_strdup ((char*)hostname); + if (!hostname) { + ret = -1; goto out; } - trans->notify = notify; - trans->mydata = mydata; + ret = dict_set_dynstr (dict, "remote-host", host); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to set remote-host with %s", host); + goto out; + } - ret = 0; + ret = dict_set_int32 (dict, "remote-port", port); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to set remote-port with %d", port); + goto out; + } + ret = dict_set_str (dict, "transport.address-family", "inet"); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to set addr-family with inet"); + goto out; + } + + ret = dict_set_str (dict, "transport-type", "socket"); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to set trans-type with socket"); + goto out; + } + + *options = dict; out: + if (ret) { + GF_FREE (host); + if (dict) + dict_unref (dict); + } + return ret; } diff --git a/rpc/rpc-lib/src/rpc-transport.h b/rpc/rpc-lib/src/rpc-transport.h index b3c7985e0..2db9072ae 100644 --- a/rpc/rpc-lib/src/rpc-transport.h +++ b/rpc/rpc-lib/src/rpc-transport.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef __RPC_TRANSPORT_H__ @@ -25,16 +16,30 @@ #include "config.h" #endif + #include <inttypes.h> -#include <rpc/rpc.h> +#ifdef GF_SOLARIS_HOST_OS #include <rpc/auth.h> +#else +#include <rpc/rpc.h> +#endif + #include <rpc/rpc_msg.h> + +#ifndef MAX_IOVEC +#define MAX_IOVEC 16 +#endif + +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif /* AI_ADDRCONFIG */ + /* Given the 4-byte fragment header, returns non-zero if this fragment - * is the last fragment for the RPC record being assemebled. + * is the last fragment for the RPC record being assembled. * RPC Record marking standard defines a 32 bit value as the fragment * header with the MSB signifying whether the fragment is the last - * fragment for the record being asembled. + * fragment for the record being assembled. */ #define RPC_LASTFRAG(fraghdr) ((uint32_t)(fraghdr & 0x80000000U)) @@ -63,9 +68,14 @@ typedef struct rpc_transport rpc_transport_t; #include "rpcsvc-common.h" struct peer_info { - struct sockaddr_storage sockaddr; - socklen_t sockaddr_len; - char identifier[UNIX_PATH_MAX]; + struct sockaddr_storage sockaddr; + socklen_t sockaddr_len; + char identifier[UNIX_PATH_MAX]; + // OP-VERSION of clients + uint32_t max_op_version; + uint32_t min_op_version; + //Volume mounted by client + char volname[1024]; }; typedef struct peer_info peer_info_t; @@ -87,7 +97,7 @@ typedef enum { * reading a single msg, this event may be * delivered more than once. */ - RPC_TRANSPORT_MAP_XID_REQUEST, /* reciever of this event should send + RPC_TRANSPORT_MAP_XID_REQUEST, /* receiver of this event should send * the prognum and procnum corresponding * to xid. */ @@ -108,18 +118,18 @@ struct rpc_transport_msg { typedef struct rpc_transport_msg rpc_transport_msg_t; struct rpc_transport_rsp { - /* as of now, the entire rsp payload is read into rspbuf and hence - * rspcount is always set to one. - */ - struct iovec *rspvec; - int rspcount; - struct iobuf *rspbuf; + struct iovec *rsphdr; + int rsphdr_count; + struct iovec *rsp_payload; + int rsp_payload_count; + struct iobref *rsp_iobref; }; typedef struct rpc_transport_rsp rpc_transport_rsp_t; struct rpc_transport_req { - rpc_transport_msg_t msg; - rpc_transport_rsp_t rsp; + rpc_transport_msg_t msg; + rpc_transport_rsp_t rsp; + struct rpc_req *rpc_req; }; typedef struct rpc_transport_req rpc_transport_req_t; @@ -129,77 +139,82 @@ struct rpc_transport_reply { }; typedef struct rpc_transport_reply rpc_transport_reply_t; +struct rpc_transport_data { + char is_request; + union { + rpc_transport_req_t req; + rpc_transport_reply_t reply; + } data; +}; +typedef struct rpc_transport_data rpc_transport_data_t; + +/* FIXME: prognum, procnum and progver are already present in + * rpc_request, hence these should be removed from request_info + */ struct rpc_request_info { uint32_t xid; int prognum; int progver; int procnum; + void *rpc_req; /* struct rpc_req */ rpc_transport_rsp_t rsp; }; typedef struct rpc_request_info rpc_request_info_t; struct rpc_transport_pollin { - union { - struct vectored { - struct iobuf *iobuf1; - size_t size1; - struct iobuf *iobuf2; - size_t size2; - } vector; - struct simple { - struct iobuf *iobuf; - size_t size; - } simple; - } data; + struct iovec vector[2]; + int count; char vectored; void *private; + struct iobref *iobref; + struct iobuf *hdr_iobuf; + char is_reply; }; typedef struct rpc_transport_pollin rpc_transport_pollin_t; typedef int (*rpc_transport_notify_t) (rpc_transport_t *, void *mydata, rpc_transport_event_t, void *data, ...); + + struct rpc_transport { - struct rpc_transport_ops *ops; - void *private; - void *xl_private; - void *mydata; - pthread_mutex_t lock; - int32_t refcount; + struct rpc_transport_ops *ops; + rpc_transport_t *listener; /* listener transport to which + * request for creation of this + * transport came from. valid only + * on server process. + */ + + void *private; + struct _client_t *xl_private; + void *xl; /* Used for THIS */ + void *mydata; + pthread_mutex_t lock; + int32_t refcount; + + int32_t outstanding_rpc_count; glusterfs_ctx_t *ctx; dict_t *options; char *name; - void *dnscache; - data_t *buf; - int32_t (*init) (rpc_transport_t *this); - void (*fini) (rpc_transport_t *this); + void *dnscache; + void *drc_client; + data_t *buf; + int32_t (*init) (rpc_transport_t *this); + void (*fini) (rpc_transport_t *this); + int (*reconfigure) (rpc_transport_t *this, dict_t *options); rpc_transport_notify_t notify; void *notify_data; - peer_info_t peerinfo; - peer_info_t myinfo; - - rpc_transport_t *peer_trans; - struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - pthread_t thread; - struct list_head msgs; - /* any request/reply will be transformed as pollin data on the - * peer, hence we are building up a pollin data even before - * handing it over to peer rpc_transport. In order to decide whether - * the pollin data is vectored or simple, we follow a simple - * algo i.e., if there is a progpayload in request/reply, its - * considered vectored, otherwise its a simple pollin data. - */ - rpc_transport_pollin_t *msg; - } handover; -}; + peer_info_t peerinfo; + peer_info_t myinfo; -typedef struct { - rpc_transport_pollin_t *pollin; - struct list_head list; -} rpc_transport_handover_t; + uint64_t total_bytes_read; + uint64_t total_bytes_write; + + struct list_head list; + int bind_insecure; + void *dl_handle; /* handle of dlopen() */ +}; struct rpc_transport_ops { /* no need of receive op, msg will be delivered through an event @@ -209,19 +224,20 @@ struct rpc_transport_ops { rpc_transport_req_t *req); int32_t (*submit_reply) (rpc_transport_t *this, rpc_transport_reply_t *reply); - int32_t (*connect) (rpc_transport_t *this); - int32_t (*listen) (rpc_transport_t *this); - int32_t (*disconnect) (rpc_transport_t *this); + int32_t (*connect) (rpc_transport_t *this, int port); + int32_t (*listen) (rpc_transport_t *this); + int32_t (*disconnect) (rpc_transport_t *this); int32_t (*get_peername) (rpc_transport_t *this, char *hostname, int hostlen); int32_t (*get_peeraddr) (rpc_transport_t *this, char *peeraddr, - int addrlen, struct sockaddr *sa, + int addrlen, struct sockaddr_storage *sa, socklen_t sasize); int32_t (*get_myname) (rpc_transport_t *this, char *hostname, int hostlen); int32_t (*get_myaddr) (rpc_transport_t *this, char *peeraddr, - int addrlen, struct sockaddr *sa, + int addrlen, struct sockaddr_storage *sa, socklen_t sasize); + int32_t (*throttle) (rpc_transport_t *this, gf_boolean_t onoff); }; @@ -229,12 +245,15 @@ int32_t rpc_transport_listen (rpc_transport_t *this); int32_t -rpc_transport_connect (rpc_transport_t *this); +rpc_transport_connect (rpc_transport_t *this, int port); int32_t rpc_transport_disconnect (rpc_transport_t *this); int32_t +rpc_transport_destroy (rpc_transport_t *this); + +int32_t rpc_transport_notify (rpc_transport_t *this, rpc_transport_event_t event, void *data, ...); @@ -245,9 +264,6 @@ int32_t rpc_transport_submit_reply (rpc_transport_t *this, rpc_transport_reply_t *reply); -int32_t -rpc_transport_destroy (rpc_transport_t *this); - rpc_transport_t * rpc_transport_load (glusterfs_ctx_t *ctx, dict_t *options, char *name); @@ -258,9 +274,6 @@ int32_t rpc_transport_unref (rpc_transport_t *trans); int -rpc_transport_setpeer (rpc_transport_t *trans, rpc_transport_t *trans_peer); - -int rpc_transport_register_notify (rpc_transport_t *trans, rpc_transport_notify_t, void *mydata); @@ -269,20 +282,33 @@ rpc_transport_get_peername (rpc_transport_t *this, char *hostname, int hostlen); int32_t rpc_transport_get_peeraddr (rpc_transport_t *this, char *peeraddr, int addrlen, - struct sockaddr *sa, size_t salen); + struct sockaddr_storage *sa, size_t salen); int32_t rpc_transport_get_myname (rpc_transport_t *this, char *hostname, int hostlen); int32_t rpc_transport_get_myaddr (rpc_transport_t *this, char *peeraddr, int addrlen, - struct sockaddr *sa, size_t salen); + struct sockaddr_storage *sa, size_t salen); + +int +rpc_transport_throttle (rpc_transport_t *this, gf_boolean_t onoff); rpc_transport_pollin_t * -rpc_transport_pollin_alloc (rpc_transport_t *this, struct iobuf *iobuf, - size_t iobuf_size, struct iobuf *vectoriob, - size_t vectoriob_size, void *private); +rpc_transport_pollin_alloc (rpc_transport_t *this, struct iovec *vector, + int count, struct iobuf *hdr_iobuf, + struct iobref *iobref, void *private); void rpc_transport_pollin_destroy (rpc_transport_pollin_t *pollin); +int +rpc_transport_keepalive_options_set (dict_t *options, int32_t interval, + int32_t time); + +int +rpc_transport_unix_options_build (dict_t **options, char *filepath, + int frame_timeout); + +int +rpc_transport_inet_options_build (dict_t **options, const char *hostname, int port); #endif /* __RPC_TRANSPORT_H__ */ diff --git a/rpc/rpc-lib/src/rpcsvc-auth.c b/rpc/rpc-lib/src/rpcsvc-auth.c index 381cf2823..4cb86a758 100644 --- a/rpc/rpc-lib/src/rpcsvc-auth.c +++ b/rpc/rpc-lib/src/rpcsvc-auth.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include "rpcsvc.h" @@ -29,6 +20,8 @@ rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options); extern rpcsvc_auth_t * rpcsvc_auth_glusterfs_init (rpcsvc_t *svc, dict_t *options); +extern rpcsvc_auth_t * +rpcsvc_auth_glusterfs_v2_init (rpcsvc_t *svc, dict_t *options); int rpcsvc_auth_add_initer (struct list_head *list, char *idfier, @@ -41,7 +34,6 @@ rpcsvc_auth_add_initer (struct list_head *list, char *idfier, new = GF_CALLOC (1, sizeof (*new), gf_common_mt_rpcsvc_auth_list); if (!new) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Memory allocation failed"); return -1; } @@ -67,6 +59,16 @@ rpcsvc_auth_add_initers (rpcsvc_t *svc) goto err; } + + ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-glusterfs-v2", + (rpcsvc_auth_initer_t) + rpcsvc_auth_glusterfs_v2_init); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "Failed to add AUTH_GLUSTERFS-v2"); + goto err; + } + ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-unix", (rpcsvc_auth_initer_t) rpcsvc_auth_unix_init); @@ -176,6 +178,75 @@ err: } int +rpcsvc_set_addr_namelookup (rpcsvc_t *svc, dict_t *options) +{ + int ret; + static char *addrlookup_key = "rpc-auth.addr.namelookup"; + + if (!svc || !options) + return (-1); + + /* By default it's disabled */ + ret = dict_get_str_boolean (options, addrlookup_key, _gf_false); + if (ret < 0) { + svc->addr_namelookup = _gf_false; + } else { + svc->addr_namelookup = ret; + } + + if (svc->addr_namelookup) + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Addr-Name lookup enabled"); + + return (0); +} + +int +rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + char *allow_insecure_str = NULL; + gf_boolean_t is_allow_insecure = _gf_false; + + GF_ASSERT (svc); + GF_ASSERT (options); + + ret = dict_get_str (options, "rpc-auth-allow-insecure", + &allow_insecure_str); + if (0 == ret) { + ret = gf_string2boolean (allow_insecure_str, + &is_allow_insecure); + if (0 == ret) { + if (_gf_true == is_allow_insecure) + svc->allow_insecure = 1; + else + svc->allow_insecure = 0; + } + } + + return 0; +} + +int +rpcsvc_set_root_squash (rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + + GF_ASSERT (svc); + GF_ASSERT (options); + + ret = dict_get_str_boolean (options, "root-squash", 0); + if (ret != -1) + svc->root_squash = ret; + else + svc->root_squash = _gf_false; + + if (svc->root_squash) + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "root squashing enabled "); + + return 0; +} + +int rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options) { int ret = -1; @@ -183,6 +254,9 @@ rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options) if ((!svc) || (!options)) return -1; + (void) rpcsvc_set_allow_insecure (svc, options); + (void) rpcsvc_set_root_squash (svc, options); + (void) rpcsvc_set_addr_namelookup (svc, options); ret = rpcsvc_auth_add_initers (svc); if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers"); @@ -199,6 +273,25 @@ out: return ret; } +int +rpcsvc_auth_reconf (rpcsvc_t *svc, dict_t *options) +{ + int ret = 0; + + if ((!svc) || (!options)) + return (-1); + + ret = rpcsvc_set_allow_insecure (svc, options); + if (ret) + return (-1); + + ret = rpcsvc_set_root_squash (svc, options); + if (ret) + return (-1); + + return rpcsvc_set_addr_namelookup (svc, options); +} + rpcsvc_auth_t * __rpcsvc_auth_get_handler (rpcsvc_request_t *req) @@ -210,7 +303,7 @@ __rpcsvc_auth_get_handler (rpcsvc_request_t *req) if (!req) return NULL; - svc = rpcsvc_request_service (req); + svc = req->svc; if (!svc) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "!svc"); goto err; @@ -277,6 +370,9 @@ rpcsvc_auth_request_init (rpcsvc_request_t *req) if (!auth->authops->request_init) ret = auth->authops->request_init (req, auth->authprivate); + req->auxgids = req->auxgidsmall; /* reset to auxgidlarge during + unsersialize if necessary */ + req->auxgidlarge = NULL; err: return ret; } @@ -292,17 +388,17 @@ rpcsvc_authenticate (rpcsvc_request_t *req) if (!req) return ret; - //minauth = rpcsvc_request_prog_minauth (req); - minauth = 1; + /* FIXME use rpcsvc_request_prog_minauth() */ + minauth = 0; if (minauth > rpcsvc_request_cred_flavour (req)) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Auth too weak"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, "Auth too weak"); rpcsvc_request_set_autherr (req, AUTH_TOOWEAK); goto err; } auth = rpcsvc_auth_get_handler (req); if (!auth) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "No auth handler found"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, "No auth handler found"); goto err; } @@ -313,18 +409,13 @@ err: return ret; } - int rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen) { - int count = 0; - int gen = RPCSVC_AUTH_REJECT; - int spec = RPCSVC_AUTH_REJECT; - int final = RPCSVC_AUTH_REJECT; - char *srchstr = NULL; - char *valstr = NULL; - gf_boolean_t boolval = _gf_false; - int ret = 0; + int count = 0; + int result = RPCSVC_AUTH_REJECT; + char *srchstr = NULL; + int ret = 0; struct rpcsvc_auth_list *auth = NULL; struct rpcsvc_auth_list *tmp = NULL; @@ -342,59 +433,27 @@ rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen) if (count >= arrlen) break; - gen = gf_asprintf (&srchstr, "rpc-auth.%s", auth->name); - if (gen == -1) { + result = gf_asprintf (&srchstr, "rpc-auth.%s.%s", + auth->name, volname); + if (result == -1) { count = -1; goto err; } - gen = RPCSVC_AUTH_REJECT; - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (valstr, &boolval); - if (ret == 0) { - if (boolval == _gf_true) - gen = RPCSVC_AUTH_ACCEPT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } - + ret = dict_get_str_boolean (svc->options, srchstr, 0xC00FFEE); GF_FREE (srchstr); - spec = gf_asprintf (&srchstr, "rpc-auth.%s.%s", auth->name, - volname); - if (spec == -1) { - count = -1; - goto err; - } - spec = RPCSVC_AUTH_DONTCARE; - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (valstr, &boolval); - if (ret == 0) { - if (boolval == _gf_true) - spec = RPCSVC_AUTH_ACCEPT; - else - spec = RPCSVC_AUTH_REJECT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile" - "d to read auth val"); - } - - GF_FREE (srchstr); - final = rpcsvc_combine_gen_spec_volume_checks (gen, spec); - if (final == RPCSVC_AUTH_ACCEPT) { + switch (ret) { + case _gf_true: + result = RPCSVC_AUTH_ACCEPT; autharr[count] = auth->auth->authnum; ++count; + break; + case _gf_false: + result = RPCSVC_AUTH_REJECT; + break; + default: + result = RPCSVC_AUTH_DONTCARE; } } @@ -402,16 +461,22 @@ err: return count; } - gid_t * rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen) { if ((!req) || (!arrlen)) return NULL; - if ((req->cred.flavour != AUTH_UNIX) || - (req->cred.flavour != AUTH_GLUSTERFS)) + /* In case of AUTH_NULL auxgids are not used */ + switch (req->cred.flavour) { + case AUTH_UNIX: + case AUTH_GLUSTERFS: + case AUTH_GLUSTERFS_v2: + break; + default: + gf_log ("rpc", GF_LOG_DEBUG, "auth type not unix or glusterfs"); return NULL; + } *arrlen = req->auxgidcount; if (*arrlen == 0) diff --git a/rpc/rpc-lib/src/rpcsvc-common.h b/rpc/rpc-lib/src/rpcsvc-common.h index 0b9d84cfd..aed55e039 100644 --- a/rpc/rpc-lib/src/rpcsvc-common.h +++ b/rpc/rpc-lib/src/rpcsvc-common.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _RPCSVC_COMMON_H @@ -29,6 +20,7 @@ typedef enum { RPCSVC_EVENT_ACCEPT, RPCSVC_EVENT_DISCONNECT, + RPCSVC_EVENT_TRANSPORT_DESTROY, RPCSVC_EVENT_LISTENER_DEAD, } rpcsvc_event_t; @@ -38,6 +30,8 @@ struct rpcsvc_state; typedef int (*rpcsvc_notify_t) (struct rpcsvc_state *, void *mydata, rpcsvc_event_t, void *data); +struct drc_globals; +typedef struct drc_globals rpcsvc_drc_globals_t; /* Contains global state required for all the RPC services. */ @@ -58,26 +52,75 @@ typedef struct rpcsvc_state { dict_t *options; /* Allow insecure ports. */ - int allow_insecure; - + gf_boolean_t allow_insecure; + gf_boolean_t register_portmap; + gf_boolean_t root_squash; glusterfs_ctx_t *ctx; - void *listener; - /* list of connections which will listen for incoming connections */ - struct list_head listeners; + struct list_head listeners; /* list of programs registered with rpcsvc */ - struct list_head programs; + struct list_head programs; /* list of notification callbacks */ - struct list_head notify; - int notify_count; + struct list_head notify; + int notify_count; void *mydata; /* This is xlator */ - rpcsvc_notify_t notifyfn; + rpcsvc_notify_t notifyfn; + struct mem_pool *rxpool; + rpcsvc_drc_globals_t *drc; + /* per-client limit of outstanding rpc requests */ + int outstanding_rpc_limit; + gf_boolean_t addr_namelookup; } rpcsvc_t; +/* DRC START */ +enum drc_op_type { + DRC_NA = 0, + DRC_IDEMPOTENT = 1, + DRC_NON_IDEMPOTENT = 2 +}; +typedef enum drc_op_type drc_op_type_t; + +enum drc_type { + DRC_TYPE_NONE = 0, + DRC_TYPE_IN_MEMORY = 1 +}; +typedef enum drc_type drc_type_t; + +enum drc_lru_factor { + DRC_LRU_5_PC = 20, + DRC_LRU_10_PC = 10, + DRC_LRU_25_PC = 4, + DRC_LRU_50_PC = 2 +}; +typedef enum drc_lru_factor drc_lru_factor_t; + +enum drc_xid_state { + DRC_XID_MONOTONOUS = 0, + DRC_XID_WRAPPED = 1 +}; +typedef enum drc_xid_state drc_xid_state_t; + +enum drc_op_state { + DRC_OP_IN_TRANSIT = 0, + DRC_OP_CACHED = 1 +}; +typedef enum drc_op_state drc_op_state_t; + +enum drc_policy { + DRC_LRU = 0 +}; +typedef enum drc_policy drc_policy_t; + +/* Default policies for DRC */ +#define DRC_DEFAULT_TYPE DRC_TYPE_IN_MEMORY +#define DRC_DEFAULT_CACHE_SIZE 0x20000 +#define DRC_DEFAULT_LRU_FACTOR DRC_LRU_25_PC + +/* DRC END */ #endif /* #ifndef _RPCSVC_COMMON_H */ diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c index 9bb7e0e4c..037c157f2 100644 --- a/rpc/rpc-lib/src/rpcsvc.c +++ b/rpc/rpc-lib/src/rpcsvc.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -34,6 +25,10 @@ #include "iobuf.h" #include "globals.h" #include "xdr-common.h" +#include "xdr-generic.h" +#include "rpc-common-xdr.h" +#include "syncop.h" +#include "rpc-drc.h" #include <errno.h> #include <pthread.h> @@ -46,512 +41,24 @@ #include <stdarg.h> #include <stdio.h> -struct rpcsvc_program gluster_dump_prog; +#include "xdr-rpcclnt.h" +#include "glusterfs-acl.h" +struct rpcsvc_program gluster_dump_prog; -#define rpcsvc_alloc_request(con, request) \ +#define rpcsvc_alloc_request(svc, request) \ do { \ - request = (rpcsvc_request_t *) mem_get ((con)->rxpool); \ + request = (rpcsvc_request_t *) mem_get ((svc)->rxpool); \ memset (request, 0, sizeof (rpcsvc_request_t)); \ } while (0) - -int -rpcsvc_conn_peer_check_search (dict_t *options, char *pattern, char *clstr) -{ - int ret = -1; - char *addrtok = NULL; - char *addrstr = NULL; - char *svptr = NULL; - - if ((!options) || (!clstr)) - return -1; - - if (!dict_get (options, pattern)) - return -1; - - ret = dict_get_str (options, pattern, &addrstr); - if (ret < 0) { - ret = -1; - goto err; - } - - if (!addrstr) { - ret = -1; - goto err; - } - - addrtok = strtok_r (addrstr, ",", &svptr); - while (addrtok) { - - ret = fnmatch (addrtok, clstr, FNM_CASEFOLD); - if (ret == 0) - goto err; - - addrtok = strtok_r (NULL, ",", &svptr); - } - - ret = -1; -err: - - return ret; -} - - -int -rpcsvc_conn_peer_check_allow (dict_t *options, char *volname, char *clstr) -{ - int ret = RPCSVC_AUTH_DONTCARE; - char *srchstr = NULL; - char globalrule[] = "rpc-auth.addr.allow"; - - if ((!options) || (!clstr)) - return ret; - - /* If volname is NULL, then we're searching for the general rule to - * determine the current address in clstr is allowed or not for all - * subvolumes. - */ - if (volname) { - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_DONTCARE; - goto out; - } - } else - srchstr = globalrule; - - ret = rpcsvc_conn_peer_check_search (options, srchstr, clstr); - if (volname) - GF_FREE (srchstr); - - if (ret == 0) - ret = RPCSVC_AUTH_ACCEPT; - else - ret = RPCSVC_AUTH_DONTCARE; -out: - return ret; -} - -int -rpcsvc_conn_peer_check_reject (dict_t *options, char *volname, char *clstr) -{ - int ret = RPCSVC_AUTH_DONTCARE; - char *srchstr = NULL; - char generalrule[] = "rpc-auth.addr.reject"; - - if ((!options) || (!clstr)) - return ret; - - if (volname) { - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.reject", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_REJECT; - goto out; - } - } else - srchstr = generalrule; - - ret = rpcsvc_conn_peer_check_search (options, srchstr, clstr); - if (volname) - GF_FREE (srchstr); - - if (ret == 0) - ret = RPCSVC_AUTH_REJECT; - else - ret = RPCSVC_AUTH_DONTCARE; -out: - return ret; -} - - -/* This function tests the results of the allow rule and the reject rule to - * combine them into a single result that can be used to determine if the - * connection should be allowed to proceed. - * Heres the test matrix we need to follow in this function. - * - * A - Allow, the result of the allow test. Never returns R. - * R - Reject, result of the reject test. Never returns A. - * Both can return D or dont care if no rule was given. - * - * | @allow | @reject | Result | - * | A | R | R | - * | D | D | D | - * | A | D | A | - * | D | R | R | - */ -int -rpcsvc_combine_allow_reject_volume_check (int allow, int reject) -{ - int final = RPCSVC_AUTH_REJECT; - - /* If allowed rule allows but reject rule rejects, we stay cautious - * and reject. */ - if ((allow == RPCSVC_AUTH_ACCEPT) && (reject == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - /* if both are dont care, that is user did not specify for either allow - * or reject, we leave it up to the general rule to apply, in the hope - * that there is one. - */ - else if ((allow == RPCSVC_AUTH_DONTCARE) && - (reject == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_DONTCARE; - /* If one is dont care, the other one applies. */ - else if ((allow == RPCSVC_AUTH_ACCEPT) && - (reject == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((allow == RPCSVC_AUTH_DONTCARE) && - (reject == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - -/* Combines the result of the general rule test against, the specific rule - * to determine final permission for the client's address. - * - * | @gen | @spec | Result | - * | A | A | A | - * | A | R | R | - * | A | D | A | - * | D | A | A | - * | D | R | R | - * | D | D | D | - * | R | A | A | - * | R | D | R | - * | R | R | R | - */ -int -rpcsvc_combine_gen_spec_addr_checks (int gen, int spec) -{ - int final = RPCSVC_AUTH_REJECT; - - if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec== RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_DONTCARE; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - - -/* Combines the result of the general rule test against, the specific rule - * to determine final test for the connection coming in for a given volume. - * - * | @gen | @spec | Result | - * | A | A | A | - * | A | R | R | - * | A | D | A | - * | D | A | A | - * | D | R | R | - * | D | D | R |, special case, we intentionally disallow this. - * | R | A | A | - * | R | D | R | - * | R | R | R | - */ -int -rpcsvc_combine_gen_spec_volume_checks (int gen, int spec) -{ - int final = RPCSVC_AUTH_REJECT; - - if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_ACCEPT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - /* On no rule, we reject. */ - else if ((gen == RPCSVC_AUTH_DONTCARE) && (spec== RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_ACCEPT)) - final = RPCSVC_AUTH_ACCEPT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_DONTCARE)) - final = RPCSVC_AUTH_REJECT; - else if ((gen == RPCSVC_AUTH_REJECT) && (spec == RPCSVC_AUTH_REJECT)) - final = RPCSVC_AUTH_REJECT; - - return final; -} - - -int -rpcsvc_conn_peer_check_name (dict_t *options, char *volname, - rpcsvc_conn_t *conn) -{ - int ret = RPCSVC_AUTH_REJECT; - int aret = RPCSVC_AUTH_REJECT; - int rjret = RPCSVC_AUTH_REJECT; - char clstr[RPCSVC_PEER_STRLEN]; - - if (!conn) - return ret; - - ret = rpcsvc_conn_peername (conn, clstr, RPCSVC_PEER_STRLEN); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " - "%s", gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - aret = rpcsvc_conn_peer_check_allow (options, volname, clstr); - rjret = rpcsvc_conn_peer_check_reject (options, volname, clstr); - - ret = rpcsvc_combine_allow_reject_volume_check (aret, rjret); - -err: - return ret; -} - - -int -rpcsvc_conn_peer_check_addr (dict_t *options, char *volname,rpcsvc_conn_t *conn) -{ - int ret = RPCSVC_AUTH_REJECT; - int aret = RPCSVC_AUTH_DONTCARE; - int rjret = RPCSVC_AUTH_REJECT; - char clstr[RPCSVC_PEER_STRLEN]; - - if (!conn) - return ret; - - ret = rpcsvc_conn_peeraddr (conn, clstr, RPCSVC_PEER_STRLEN, NULL, 0); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " - "%s", gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } - - aret = rpcsvc_conn_peer_check_allow (options, volname, clstr); - rjret = rpcsvc_conn_peer_check_reject (options, volname, clstr); - - ret = rpcsvc_combine_allow_reject_volume_check (aret, rjret); -err: - return ret; -} - - -int -rpcsvc_conn_check_volume_specific (dict_t *options, char *volname, - rpcsvc_conn_t *conn) -{ - int namechk = RPCSVC_AUTH_REJECT; - int addrchk = RPCSVC_AUTH_REJECT; - gf_boolean_t namelookup = _gf_true; - char *namestr = NULL; - int ret = 0; - - if ((!options) || (!volname) || (!conn)) - return RPCSVC_AUTH_REJECT; - - /* Enabled by default */ - if ((dict_get (options, "rpc-auth.addr.namelookup"))) { - ret = dict_get_str (options, "rpc-auth.addr.namelookup" - , &namestr); - if (ret == 0) { - ret = gf_string2boolean (namestr, &namelookup); - if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, - "wrong option %s given for " - "'namelookup'", namestr); - } - } - - /* We need two separate checks because the rules with addresses in them - * can be network addresses which can be general and names can be - * specific which will over-ride the network address rules. - */ - if (namelookup) - namechk = rpcsvc_conn_peer_check_name (options, volname, conn); - addrchk = rpcsvc_conn_peer_check_addr (options, volname, conn); - - if (namelookup) - ret = rpcsvc_combine_gen_spec_addr_checks (addrchk, namechk); - else - ret = addrchk; - - return ret; -} - - -int -rpcsvc_conn_check_volume_general (dict_t *options, rpcsvc_conn_t *conn) -{ - int addrchk = RPCSVC_AUTH_REJECT; - int namechk = RPCSVC_AUTH_REJECT; - gf_boolean_t namelookup = _gf_true; - char *namestr = NULL; - int ret = 0; - - if ((!options) || (!conn)) - return RPCSVC_AUTH_REJECT; - - /* Enabled by default */ - if ((dict_get (options, "rpc-auth.addr.namelookup"))) { - ret = dict_get_str (options, "rpc-auth.addr.namelookup" - , &namestr); - if (!ret) { - ret = gf_string2boolean (namestr, &namelookup); - if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, - "wrong option %s given for " - "'namelookup'", namestr); - } - } - - /* We need two separate checks because the rules with addresses in them - * can be network addresses which can be general and names can be - * specific which will over-ride the network address rules. - */ - if (namelookup) - namechk = rpcsvc_conn_peer_check_name (options, NULL, conn); - addrchk = rpcsvc_conn_peer_check_addr (options, NULL, conn); - - if (namelookup) - ret = rpcsvc_combine_gen_spec_addr_checks (addrchk, namechk); - else - ret = addrchk; - - return ret; -} - -int -rpcsvc_conn_peer_check (dict_t *options, char *volname, rpcsvc_conn_t *conn) -{ - int general_chk = RPCSVC_AUTH_REJECT; - int specific_chk = RPCSVC_AUTH_REJECT; - - if ((!options) || (!volname) || (!conn)) - return RPCSVC_AUTH_REJECT; - - general_chk = rpcsvc_conn_check_volume_general (options, conn); - specific_chk = rpcsvc_conn_check_volume_specific (options, volname, - conn); - - return rpcsvc_combine_gen_spec_volume_checks (general_chk,specific_chk); -} - - -char * -rpcsvc_volume_allowed (dict_t *options, char *volname) -{ - char globalrule[] = "rpc-auth.addr.allow"; - char *srchstr = NULL; - char *addrstr = NULL; - int ret = -1; - - if ((!options) || (!volname)) - return NULL; - - ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - goto out; - } - - if (!dict_get (options, srchstr)) { - GF_FREE (srchstr); - srchstr = globalrule; - ret = dict_get_str (options, srchstr, &addrstr); - if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, - "failed to get the string %s", srchstr); - } else { - ret = dict_get_str (options, srchstr, &addrstr); - if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, - "failed to get the string %s", srchstr); - } -out: - return addrstr; -} - - - -/* Initialize the core of a connection */ -rpcsvc_conn_t * -rpcsvc_conn_alloc (rpcsvc_t *svc, rpc_transport_t *trans) -{ - rpcsvc_conn_t *conn = NULL; - int ret = -1; - unsigned int poolcount = 0; - - conn = GF_CALLOC (1, sizeof(*conn), gf_common_mt_rpcsvc_conn_t); - if (!conn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "memory allocation failed"); - return NULL; - } - - conn->trans = trans; - conn->svc = svc; - poolcount = RPCSVC_POOLCOUNT_MULT * svc->memfactor; - - gf_log (GF_RPCSVC, GF_LOG_TRACE, "rx pool: %d", poolcount); - conn->rxpool = mem_pool_new (rpcsvc_request_t, poolcount); - /* TODO: leak */ - if (!conn->rxpool) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "mem pool allocation failed"); - goto free_conn; - } - - /* Cannot consider a connection connected unless the user of this - * connection decides it is ready to use. It is possible that we have - * to free this connection soon after. That free will not happpen - * unless the state is disconnected. - */ - conn->connstate = RPCSVC_CONNSTATE_DISCONNECTED; - pthread_mutex_init (&conn->connlock, NULL); - conn->connref = 0; - - ret = 0; - -free_conn: - if (ret == -1) { - GF_FREE (conn); - conn = NULL; - } - - return conn; -} +rpcsvc_listener_t * +rpcsvc_get_listener (rpcsvc_t *svc, uint16_t port, rpc_transport_t *trans); int rpcsvc_notify (rpc_transport_t *trans, void *mydata, rpc_transport_event_t event, void *data, ...); -void -rpcsvc_conn_state_init (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - ++conn->connref; - conn->connstate = RPCSVC_CONNSTATE_CONNECTED; -} - - rpcsvc_notify_wrapper_t * rpcsvc_notify_wrapper_alloc (void) { @@ -559,7 +66,6 @@ rpcsvc_notify_wrapper_alloc (void) wrapper = GF_CALLOC (1, sizeof (*wrapper), gf_common_mt_rpcsvc_wrapper_t); if (!wrapper) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "memory allocation failed"); goto out; } @@ -578,11 +84,7 @@ rpcsvc_listener_destroy (rpcsvc_listener_t *listener) goto out; } - if (!listener->conn) { - goto listener_free; - } - - svc = listener->conn->svc; + svc = listener->svc; if (!svc) { goto listener_free; } @@ -599,285 +101,61 @@ out: return; } - -void -rpcsvc_conn_destroy (rpcsvc_conn_t *conn) +rpcsvc_vector_sizer +rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum, + uint32_t progver, uint32_t procnum) { - rpcsvc_notify_wrapper_t *wrapper = NULL; - rpcsvc_event_t event = 0; - rpcsvc_listener_t *listener = NULL; - rpcsvc_t *svc = NULL; - rpcsvc_notify_wrapper_t *wrappers = NULL; - int i = 0, wrapper_count = 0; - - if (!conn) - goto out; - - mem_pool_destroy (conn->rxpool); - - listener = conn->listener; - if (!listener) - goto out; - - event = (listener->conn == conn) ? RPCSVC_EVENT_LISTENER_DEAD - : RPCSVC_EVENT_DISCONNECT; + rpcsvc_program_t *program = NULL; + char found = 0; - svc = conn->svc; if (!svc) - goto out; + return NULL; pthread_mutex_lock (&svc->rpclock); { - wrappers = GF_CALLOC (svc->notify_count, sizeof (*wrapper), - gf_common_mt_rpcsvc_wrapper_t); - if (!wrappers) { - goto unlock; - } - - list_for_each_entry (wrapper, &conn->listener->list, - list) { - if (wrapper->notify) { - wrappers[i++] = *wrapper; + list_for_each_entry (program, &svc->programs, program) { + if ((program->prognum == prognum) + && (program->progver == progver)) { + found = 1; + break; } } - wrapper_count = i; } -unlock: pthread_mutex_unlock (&svc->rpclock); - if (wrappers) { - for (i = 0; i < wrapper_count; i++) { - wrappers[i].notify (conn->svc, wrappers[i].data, - event, conn); - } - - GF_FREE (wrappers); - } - - if (listener->conn == conn) { - rpcsvc_listener_destroy (listener); - } - - /* Need to destory record state, txlists etc. */ - GF_FREE (conn); -out: - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Connection destroyed"); -} - - -rpcsvc_conn_t * -rpcsvc_conn_init (rpcsvc_t *svc, rpc_transport_t *trans) -{ - int ret = -1; - rpcsvc_conn_t *conn = NULL; - - conn = rpcsvc_conn_alloc (svc, trans); - if (!conn) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "cannot init a connection"); - goto out; - } - - ret = rpc_transport_register_notify (trans, rpcsvc_notify, conn); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "registering notify failed"); - rpcsvc_conn_destroy (conn); - conn = NULL; - goto out; - } - - rpcsvc_conn_state_init (conn); - -out: - return conn; -} - - -int -__rpcsvc_conn_unref (rpcsvc_conn_t *conn) -{ - --conn->connref; - return conn->connref; -} - - -void -__rpcsvc_conn_deinit (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - if (rpcsvc_conn_check_active (conn)) { - conn->connstate = RPCSVC_CONNSTATE_DISCONNECTED; - } - - if (conn->trans) { - rpc_transport_disconnect (conn->trans); - conn->trans = NULL; - } -} - - -void -rpcsvc_conn_deinit (rpcsvc_conn_t *conn) -{ - int ref = 0; - - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - __rpcsvc_conn_deinit (conn); - ref = __rpcsvc_conn_unref (conn); - } - pthread_mutex_unlock (&conn->connlock); - - if (ref == 0) - rpcsvc_conn_destroy (conn); - - return; -} - - -void -rpcsvc_conn_unref (rpcsvc_conn_t *conn) -{ - int ref = 0; - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - ref = __rpcsvc_conn_unref (conn); - } - pthread_mutex_unlock (&conn->connlock); - - if (ref == 0) { - rpcsvc_conn_destroy (conn); - } + if (found) + return program->actors[procnum].vector_sizer; + else + return NULL; } - int -rpcsvc_conn_active (rpcsvc_conn_t *conn) +rpcsvc_request_outstanding (rpcsvc_t *svc, rpc_transport_t *trans, int delta) { - int status = 0; - - if (!conn) - return 0; + int ret = 0; + int old_count = 0; + int new_count = 0; + int limit = 0; - pthread_mutex_lock (&conn->connlock); + pthread_mutex_lock (&trans->lock); { - status = rpcsvc_conn_check_active (conn); - } - pthread_mutex_unlock (&conn->connlock); - - return status; -} - - -void -rpcsvc_conn_ref (rpcsvc_conn_t *conn) -{ - if (!conn) - return; - - pthread_mutex_lock (&conn->connlock); - { - ++conn->connref; - } - pthread_mutex_unlock (&conn->connlock); - - return; -} - - -int -rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, rpcsvc_conn_t *conn) -{ - struct sockaddr_in sa; - int ret = RPCSVC_AUTH_REJECT; - socklen_t sasize = sizeof (sa); - char *srchstr = NULL; - char *valstr = NULL; - int globalinsecure = RPCSVC_AUTH_REJECT; - int exportinsecure = RPCSVC_AUTH_DONTCARE; - uint16_t port = 0; - gf_boolean_t insecure = _gf_false; - - if ((!svc) || (!volname) || (!conn)) - return ret; - - ret = rpcsvc_conn_peeraddr (conn, NULL, 0, (struct sockaddr *)&sa, - sasize); - if (ret != 0) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get peer addr: %s", - gai_strerror (ret)); - ret = RPCSVC_AUTH_REJECT; - goto err; - } + limit = svc->outstanding_rpc_limit; + if (!limit) + goto unlock; - port = ntohs (sa.sin_port); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "Client port: %d", (int)port); - /* If the port is already a privileged one, dont bother with checking - * options. - */ - if (port <= 1024) { - ret = RPCSVC_AUTH_ACCEPT; - goto err; - } + old_count = trans->outstanding_rpc_count; + trans->outstanding_rpc_count += delta; + new_count = trans->outstanding_rpc_count; - /* Disabled by default */ - if ((dict_get (svc->options, "rpc-auth.ports.insecure"))) { - ret = dict_get_str (svc->options, "rpc-auth.ports.insecure" - , &srchstr); - if (ret == 0) { - ret = gf_string2boolean (srchstr, &insecure); - if (ret == 0) { - if (insecure == _gf_true) - globalinsecure = RPCSVC_AUTH_ACCEPT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } + if (old_count <= limit && new_count > limit) + ret = rpc_transport_throttle (trans, _gf_true); - /* Disabled by default */ - ret = gf_asprintf (&srchstr, "rpc-auth.ports.%s.insecure", volname); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); - ret = RPCSVC_AUTH_REJECT; - goto err; + if (old_count > limit && new_count <= limit) + ret = rpc_transport_throttle (trans, _gf_false); } +unlock: + pthread_mutex_unlock (&trans->lock); - if (dict_get (svc->options, srchstr)) { - ret = dict_get_str (svc->options, srchstr, &valstr); - if (ret == 0) { - ret = gf_string2boolean (srchstr, &insecure); - if (ret == 0) { - if (insecure == _gf_true) - exportinsecure = RPCSVC_AUTH_ACCEPT; - else - exportinsecure = RPCSVC_AUTH_REJECT; - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } else - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" - " read rpc-auth.ports.insecure value"); - } - - ret = rpcsvc_combine_gen_spec_volume_checks (globalinsecure, - exportinsecure); - if (ret == RPCSVC_AUTH_ACCEPT) - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port allowed"); - else - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port not" - " allowed"); - -err: return ret; } @@ -887,7 +165,7 @@ err: * of the pointers below are NULL. */ rpcsvc_actor_t * -rpcsvc_program_actor (rpcsvc_conn_t *conn, rpcsvc_request_t *req) +rpcsvc_program_actor (rpcsvc_request_t *req) { rpcsvc_program_t *program = NULL; int err = SYSTEM_ERR; @@ -895,10 +173,10 @@ rpcsvc_program_actor (rpcsvc_conn_t *conn, rpcsvc_request_t *req) rpcsvc_t *svc = NULL; char found = 0; - if ((!conn) || (!req)) + if (!req) goto err; - svc = conn->svc; + svc = req->svc; pthread_mutex_lock (&svc->rpclock); { list_for_each_entry (program, &svc->programs, program) { @@ -917,26 +195,35 @@ rpcsvc_program_actor (rpcsvc_conn_t *conn, rpcsvc_request_t *req) if (!found) { if (err != PROG_MISMATCH) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, - "RPC program not available"); + /* log in DEBUG when nfs clients try to see if + * ACL requests are accepted by nfs server + */ + gf_log (GF_RPCSVC, (req->prognum == ACL_PROGRAM) ? + GF_LOG_DEBUG : GF_LOG_WARNING, + "RPC program not available (req %u %u)", + req->prognum, req->progver); err = PROG_UNAVAIL; goto err; } - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC program version not" - " available"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, + "RPC program version not available (req %u %u)", + req->prognum, req->progver); goto err; } req->prog = program; if (!program->actors) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC System error"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, + "RPC Actor not found for program %s %d", + program->progname, program->prognum); err = SYSTEM_ERR; goto err; } if ((req->procnum < 0) || (req->procnum >= program->numactors)) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC Program procedure not" - " available"); + " available for procedure %d in %s", req->procnum, + program->progname); err = PROC_UNAVAIL; goto err; } @@ -944,12 +231,15 @@ rpcsvc_program_actor (rpcsvc_conn_t *conn, rpcsvc_request_t *req) actor = &program->actors[req->procnum]; if (!actor->actor) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC Program procedure not" - " available"); + " available for procedure %d in %s", req->procnum, + program->progname); err = PROC_UNAVAIL; actor = NULL; goto err; } + req->synctask = program->synctask; + err = SUCCESS; gf_log (GF_RPCSVC, GF_LOG_TRACE, "Actor found: %s - %s", program->progname, actor->procname); @@ -962,9 +252,9 @@ err: /* this procedure can only pass 4 arguments to registered notifyfn. To send more - * arguements call wrapper->notify directly. + * arguments call wrapper->notify directly. */ -inline void +static inline void rpcsvc_program_notify (rpcsvc_listener_t *listener, rpcsvc_event_t event, void *data) { @@ -974,9 +264,9 @@ rpcsvc_program_notify (rpcsvc_listener_t *listener, rpcsvc_event_t event, goto out; } - list_for_each_entry (wrapper, &listener->list, list) { + list_for_each_entry (wrapper, &listener->svc->notify, list) { if (wrapper->notify) { - wrapper->notify (listener->conn->svc, + wrapper->notify (listener->svc, wrapper->data, event, data); } @@ -987,60 +277,66 @@ out: } -int -rpcsvc_accept (rpcsvc_conn_t *listen_conn, rpc_transport_t *new_trans) +static inline int +rpcsvc_accept (rpcsvc_t *svc, rpc_transport_t *listen_trans, + rpc_transport_t *new_trans) { rpcsvc_listener_t *listener = NULL; - rpcsvc_conn_t *conn = NULL; - char clstr[RPCSVC_PEER_STRLEN]; - - listener = listen_conn->listener; - conn = rpcsvc_conn_init (listen_conn->svc, new_trans); - if (!conn) { - rpc_transport_disconnect (new_trans); - memset (clstr, 0, RPCSVC_PEER_STRLEN); - rpc_transport_get_peername (new_trans, clstr, - RPCSVC_PEER_STRLEN); - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "allocating connection for " - "new transport (%s) failed", clstr); + int32_t ret = -1; + + listener = rpcsvc_get_listener (svc, -1, listen_trans); + if (listener == NULL) { goto out; } - conn->listener = listener; - - //rpcsvc_program_notify (listener, RPCSVC_EVENT_ACCEPT, conn); + rpcsvc_program_notify (listener, RPCSVC_EVENT_ACCEPT, new_trans); + ret = 0; out: - return 0; + return ret; } void -rpcsvc_request_destroy (rpcsvc_conn_t *conn, rpcsvc_request_t *req) +rpcsvc_request_destroy (rpcsvc_request_t *req) { - if (!conn || !req) { + if (!req) { goto out; } - if (req->recordiob) { - iobuf_unref (req->recordiob); + if (req->iobref) { + iobref_unref (req->iobref); } - if (req->vectorediob) { - iobuf_unref (req->vectorediob); - } + if (req->hdr_iobuf) + iobuf_unref (req->hdr_iobuf); + + /* This marks the "end" of an RPC request. Reply is + completely written to the socket and is on the way + to the client. It is time to decrement the + outstanding request counter by 1. + */ + rpcsvc_request_outstanding (req->svc, req->trans, -1); + + rpc_transport_unref (req->trans); + + GF_FREE (req->auxgidlarge); + + mem_put (req); - mem_put (conn->rxpool, req); out: return; } rpcsvc_request_t * -rpcsvc_request_init (rpcsvc_conn_t *conn, struct rpc_msg *callmsg, +rpcsvc_request_init (rpcsvc_t *svc, rpc_transport_t *trans, + struct rpc_msg *callmsg, struct iovec progmsg, rpc_transport_pollin_t *msg, rpcsvc_request_t *req) { - if ((!conn) || (!callmsg)|| (!req) || (!msg)) + int i = 0; + + if ((!trans) || (!callmsg)|| (!req) || (!msg)) return NULL; /* We start a RPC request as always denied. */ @@ -1049,18 +345,19 @@ rpcsvc_request_init (rpcsvc_conn_t *conn, struct rpc_msg *callmsg, req->prognum = rpc_call_program (callmsg); req->progver = rpc_call_progver (callmsg); req->procnum = rpc_call_progproc (callmsg); - req->conn = conn; + req->trans = rpc_transport_ref (trans); + req->count = msg->count; req->msg[0] = progmsg; + req->iobref = iobref_ref (msg->iobref); if (msg->vectored) { - req->msg[1].iov_base = iobuf_ptr (msg->data.vector.iobuf2); - req->msg[1].iov_len = msg->data.vector.size2; - - req->recordiob = iobuf_ref (msg->data.vector.iobuf1); - req->vectorediob = iobuf_ref (msg->data.vector.iobuf2); - } else { - req->recordiob = iobuf_ref (msg->data.simple.iobuf); + /* msg->vector[2] is defined in structure. prevent a + out of bound access */ + for (i = 1; i < min (msg->count, 2); i++) { + req->msg[i] = msg->vector[i]; + } } + req->svc = svc; req->trans_private = msg->private; INIT_LIST_HEAD (&req->txlist); @@ -1082,7 +379,8 @@ rpcsvc_request_init (rpcsvc_conn_t *conn, struct rpc_msg *callmsg, rpcsvc_request_t * -rpcsvc_request_create (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) +rpcsvc_request_create (rpcsvc_t *svc, rpc_transport_t *trans, + rpc_transport_pollin_t *msg) { char *msgbuf = NULL; struct rpc_msg rpcmsg; @@ -1091,7 +389,7 @@ rpcsvc_request_create (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) size_t msglen = 0; int ret = -1; - if (!conn) + if (!svc || !trans) return NULL; /* We need to allocate the request before actually calling @@ -1100,39 +398,50 @@ rpcsvc_request_create (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) * This avoids a need to keep a temp buffer into which the auth data * would've been copied otherwise. */ - rpcsvc_alloc_request (conn, req); + rpcsvc_alloc_request (svc, req); if (!req) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to alloc request"); goto err; } - if (msg->vectored) { - msgbuf = iobuf_ptr (msg->data.vector.iobuf1); - msglen = msg->data.vector.size1; - } else { - msgbuf = iobuf_ptr (msg->data.simple.iobuf); - msglen = msg->data.simple.size; - } + /* We just received a new request from the wire. Account for + it in the outsanding request counter to make sure we don't + ingest too many concurrent requests from the same client. + */ + ret = rpcsvc_request_outstanding (svc, trans, +1); + + msgbuf = msg->vector[0].iov_base; + msglen = msg->vector[0].iov_len; ret = xdr_to_rpc_call (msgbuf, msglen, &rpcmsg, &progmsg, req->cred.authdata,req->verf.authdata); if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC call decoding failed"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, "RPC call decoding failed"); rpcsvc_request_seterr (req, GARBAGE_ARGS); + req->trans = rpc_transport_ref (trans); + req->svc = svc; goto err; } ret = -1; - rpcsvc_request_init (conn, &rpcmsg, progmsg, msg, req); + rpcsvc_request_init (svc, trans, &rpcmsg, progmsg, msg, req); - gf_log (GF_RPCSVC, GF_LOG_TRACE, "RPC XID: %lx, Ver: %ld, Program: %ld," - " ProgVers: %ld, Proc: %ld", rpc_call_xid (&rpcmsg), + gf_log (GF_RPCSVC, GF_LOG_TRACE, "received rpc-message (XID: 0x%lx, " + "Ver: %ld, Program: %ld, ProgVers: %ld, Proc: %ld) from" + " rpc-transport (%s)", rpc_call_xid (&rpcmsg), rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), - rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg)); + rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), + trans->name); if (rpc_call_rpcvers (&rpcmsg) != 2) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC version not supported"); + /* LOG- TODO: print rpc version, also print the peerinfo + from transport */ + gf_log (GF_RPCSVC, GF_LOG_ERROR, "RPC version not supported " + "(XID: 0x%lx, Ver: %ld, Prog: %ld, ProgVers: %ld, " + "Proc: %ld) from trans (%s)", rpc_call_xid (&rpcmsg), + rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), + rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), + trans->name); rpcsvc_request_seterr (req, RPC_MISMATCH); goto err; } @@ -1144,7 +453,12 @@ rpcsvc_request_create (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) * error happened. */ rpcsvc_request_seterr (req, AUTH_ERROR); - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed authentication"); + gf_log (GF_RPCSVC, GF_LOG_ERROR, "auth failed on request. " + "(XID: 0x%lx, Ver: %ld, Prog: %ld, ProgVers: %ld, " + "Proc: %ld) from trans (%s)", rpc_call_xid (&rpcmsg), + rpc_call_rpcvers (&rpcmsg), rpc_call_program (&rpcmsg), + rpc_call_progver (&rpcmsg), rpc_call_progproc (&rpcmsg), + trans->name); ret = -1; goto err; } @@ -1154,12 +468,13 @@ rpcsvc_request_create (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) * since we are not handling authentication failures for now. */ req->rpc_status = MSG_ACCEPTED; + req->reply = NULL; ret = 0; err: if (ret == -1) { ret = rpcsvc_error_reply (req); if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, + gf_log ("rpcsvc", GF_LOG_WARNING, "failed to queue error reply"); req = NULL; } @@ -1169,57 +484,213 @@ err: int -rpcsvc_handle_rpc_call (rpcsvc_conn_t *conn, rpc_transport_pollin_t *msg) +rpcsvc_check_and_reply_error (int ret, call_frame_t *frame, void *opaque) { - rpcsvc_actor_t *actor = NULL; - rpcsvc_request_t *req = NULL; - int ret = -1; + rpcsvc_request_t *req = NULL; + + req = opaque; + + if (ret) + gf_log ("rpcsvc", GF_LOG_ERROR, + "rpc actor failed to complete successfully"); + + if (ret == RPCSVC_ACTOR_ERROR) { + ret = rpcsvc_error_reply (req); + if (ret) + gf_log ("rpcsvc", GF_LOG_WARNING, + "failed to queue error reply"); + } + + return 0; +} + +int +rpcsvc_handle_rpc_call (rpcsvc_t *svc, rpc_transport_t *trans, + rpc_transport_pollin_t *msg) +{ + rpcsvc_actor_t *actor = NULL; + rpcsvc_actor actor_fn = NULL; + rpcsvc_request_t *req = NULL; + int ret = -1; + uint16_t port = 0; + gf_boolean_t is_unix = _gf_false; + gf_boolean_t unprivileged = _gf_false; + drc_cached_op_t *reply = NULL; + rpcsvc_drc_globals_t *drc = NULL; + + if (!trans || !svc) + return -1; + + switch (trans->peerinfo.sockaddr.ss_family) { + case AF_INET: + port = ((struct sockaddr_in *)&trans->peerinfo.sockaddr)->sin_port; + break; - if (!conn) + case AF_INET6: + port = ((struct sockaddr_in6 *)&trans->peerinfo.sockaddr)->sin6_port; + break; + case AF_UNIX: + is_unix = _gf_true; + break; + default: + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "invalid address family (%d)", + trans->peerinfo.sockaddr.ss_family); return -1; + } + + + + if (is_unix == _gf_false) { + port = ntohs (port); + + gf_log ("rpcsvc", GF_LOG_TRACE, "Client port: %d", (int)port); - req = rpcsvc_request_create (conn, msg); + if (port > 1024) + unprivileged = _gf_true; + } + + req = rpcsvc_request_create (svc, trans, msg); if (!req) - goto err; + goto out; if (!rpcsvc_request_accepted (req)) goto err_reply; - actor = rpcsvc_program_actor (conn, req); + actor = rpcsvc_program_actor (req); if (!actor) goto err_reply; - if (actor && (req->rpc_err == SUCCESS)) { - if (req->vectorediob) { - if (actor->vector_actor) { - rpcsvc_conn_ref (conn); - ret = actor->vector_actor (req, - req->vectorediob); - } else { - rpcsvc_request_seterr (req, PROC_UNAVAIL); - gf_log (GF_RPCSVC, GF_LOG_ERROR, - "No vectored handler present"); - ret = RPCSVC_ACTOR_ERROR; - } - } else if (actor->actor) { - rpcsvc_conn_ref (req->conn); - /* Before going to xlator code, set the THIS properly */ - THIS = conn->svc->mydata; - ret = actor->actor (req); + if (0 == svc->allow_insecure && unprivileged && !actor->unprivileged) { + /* Non-privileged user, fail request */ + gf_log ("glusterd", GF_LOG_ERROR, + "Request received from non-" + "privileged port. Failing request"); + rpcsvc_request_destroy (req); + return -1; + } + + /* DRC */ + if (rpcsvc_need_drc (req)) { + drc = req->svc->drc; + + LOCK (&drc->lock); + reply = rpcsvc_drc_lookup (req); + + /* retransmission of completed request, send cached reply */ + if (reply && reply->state == DRC_OP_CACHED) { + gf_log (GF_RPCSVC, GF_LOG_INFO, "duplicate request:" + " XID: 0x%x", req->xid); + ret = rpcsvc_send_cached_reply (req, reply); + drc->cache_hits++; + UNLOCK (&drc->lock); + goto out; + + } /* retransmitted request, original op in transit, drop it */ + else if (reply && reply->state == DRC_OP_IN_TRANSIT) { + gf_log (GF_RPCSVC, GF_LOG_INFO, "op in transit," + " discarding. XID: 0x%x", req->xid); + ret = 0; + drc->intransit_hits++; + rpcsvc_request_destroy (req); + UNLOCK (&drc->lock); + goto out; + + } /* fresh request, cache it as in-transit and proceed */ + else { + ret = rpcsvc_cache_request (req); } + UNLOCK (&drc->lock); } -err_reply: - if ((ret == RPCSVC_ACTOR_ERROR) || (req->rpc_err != SUCCESS)) - ret = rpcsvc_error_reply (req); + if (req->rpc_err == SUCCESS) { + /* Before going to xlator code, set the THIS properly */ + THIS = svc->mydata; - if (ret) - gf_log ("rpcsvc", GF_LOG_DEBUG, "failed to queue error reply"); + actor_fn = actor->actor; + if (!actor_fn) { + rpcsvc_request_seterr (req, PROC_UNAVAIL); + /* LOG TODO: print more info about procnum, + prognum etc, also print transport info */ + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "No vectored handler present"); + ret = RPCSVC_ACTOR_ERROR; + goto err_reply; + } + + if (req->synctask) { + if (msg->hdr_iobuf) + req->hdr_iobuf = iobuf_ref (msg->hdr_iobuf); + + ret = synctask_new (THIS->ctx->env, + (synctask_fn_t) actor_fn, + rpcsvc_check_and_reply_error, NULL, + req); + } else { + ret = actor_fn (req); + } + } + +err_reply: + + ret = rpcsvc_check_and_reply_error (ret, NULL, req); /* No need to propagate error beyond this function since the reply * has now been queued. */ ret = 0; -err: + +out: + return ret; +} + + +int +rpcsvc_handle_disconnect (rpcsvc_t *svc, rpc_transport_t *trans) +{ + rpcsvc_event_t event; + rpcsvc_notify_wrapper_t *wrappers = NULL, *wrapper; + int32_t ret = -1, i = 0, wrapper_count = 0; + rpcsvc_listener_t *listener = NULL; + + event = (trans->listener == NULL) ? RPCSVC_EVENT_LISTENER_DEAD + : RPCSVC_EVENT_DISCONNECT; + + pthread_mutex_lock (&svc->rpclock); + { + if (!svc->notify_count) + goto unlock; + + wrappers = GF_CALLOC (svc->notify_count, sizeof (*wrapper), + gf_common_mt_rpcsvc_wrapper_t); + if (!wrappers) { + goto unlock; + } + + list_for_each_entry (wrapper, &svc->notify, list) { + if (wrapper->notify) { + wrappers[i++] = *wrapper; + } + } + + wrapper_count = i; + } +unlock: + pthread_mutex_unlock (&svc->rpclock); + + if (wrappers) { + for (i = 0; i < wrapper_count; i++) { + wrappers[i].notify (svc, wrappers[i].data, + event, trans); + } + + GF_FREE (wrappers); + } + + if (event == RPCSVC_EVENT_LISTENER_DEAD) { + listener = rpcsvc_get_listener (svc, -1, trans->listener); + rpcsvc_listener_destroy (listener); + } + return ret; } @@ -1228,30 +699,30 @@ int rpcsvc_notify (rpc_transport_t *trans, void *mydata, rpc_transport_event_t event, void *data, ...) { - rpcsvc_conn_t *conn = NULL; int ret = -1; rpc_transport_pollin_t *msg = NULL; rpc_transport_t *new_trans = NULL; + rpcsvc_t *svc = NULL; + rpcsvc_listener_t *listener = NULL; - conn = mydata; - if (conn == NULL) { + svc = mydata; + if (svc == NULL) { goto out; } switch (event) { case RPC_TRANSPORT_ACCEPT: new_trans = data; - ret = rpcsvc_accept (conn, new_trans); + ret = rpcsvc_accept (svc, trans, new_trans); break; case RPC_TRANSPORT_DISCONNECT: - //rpcsvc_conn_deinit (conn); - ret = 0; + ret = rpcsvc_handle_disconnect (svc, trans); break; case RPC_TRANSPORT_MSG_RECEIVED: msg = data; - ret = rpcsvc_handle_rpc_call (conn, msg); + ret = rpcsvc_handle_rpc_call (svc, trans, msg); break; case RPC_TRANSPORT_MSG_SENT: @@ -1262,13 +733,20 @@ rpcsvc_notify (rpc_transport_t *trans, void *mydata, /* do nothing, no need for rpcsvc to handle this, client should * handle this event */ + /* print info about transport too : LOG TODO */ gf_log ("rpcsvc", GF_LOG_CRITICAL, "got CONNECT event, which should have not come"); ret = 0; break; case RPC_TRANSPORT_CLEANUP: - /* FIXME: think about this later */ + listener = rpcsvc_get_listener (svc, -1, trans->listener); + if (listener == NULL) { + goto out; + } + + rpcsvc_program_notify (listener, RPCSVC_EVENT_TRANSPORT_DESTROY, + trans); ret = 0; break; @@ -1285,26 +763,6 @@ out: } -void -rpcsvc_set_lastfrag (uint32_t *fragsize) { - (*fragsize) |= 0x80000000U; -} - -void -rpcsvc_set_frag_header_size (uint32_t size, char *haddr) -{ - size = htonl (size); - memcpy (haddr, &size, sizeof (size)); -} - -void -rpcsvc_set_last_frag_header_size (uint32_t size, char *haddr) -{ - rpcsvc_set_lastfrag (&size); - rpcsvc_set_frag_header_size (size, haddr); -} - - /* Given the RPC reply structure and the payload handed by the RPC program, * encode the RPC record header into the buffer pointed by recordstart. */ @@ -1320,10 +778,9 @@ rpcsvc_record_build_header (char *recordstart, size_t rlen, /* After leaving aside the 4 bytes for the fragment header, lets * encode the RPC reply structure into the buffer given to us. */ - ret = rpc_reply_to_xdr (&reply,(recordstart + RPCSVC_FRAGHDR_SIZE), - rlen, &replyhdr); + ret = rpc_reply_to_xdr (&reply, recordstart, rlen, &replyhdr); if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to create RPC reply"); + gf_log (GF_RPCSVC, GF_LOG_WARNING, "Failed to create RPC reply"); goto err; } @@ -1331,16 +788,78 @@ rpcsvc_record_build_header (char *recordstart, size_t rlen, gf_log (GF_RPCSVC, GF_LOG_TRACE, "Reply fraglen %zu, payload: %zu, " "rpc hdr: %zu", fraglen, payload, replyhdr.iov_len); - /* Since we're not spreading RPC records over mutiple fragments - * we just set this fragment as the first and last fragment for this - * record. - */ - rpcsvc_set_last_frag_header_size (fraglen, recordstart); + txrecord.iov_base = recordstart; - /* Even though the RPC record starts at recordstart+RPCSVC_FRAGHDR_SIZE - * we need to transmit the record with the fragment header, which starts - * at recordstart. + /* Remember, this is only the vec for the RPC header and does not + * include the payload above. We needed the payload only to calculate + * the size of the full fragment. This size is sent in the fragment + * header. */ + txrecord.iov_len = replyhdr.iov_len; +err: + return txrecord; +} + +static inline int +rpcsvc_get_callid (rpcsvc_t *rpc) +{ + return GF_UNIVERSAL_ANSWER; +} + +int +rpcsvc_fill_callback (int prognum, int progver, int procnum, int payload, + uint64_t xid, struct rpc_msg *request) +{ + int ret = -1; + + if (!request) { + goto out; + } + + memset (request, 0, sizeof (*request)); + + request->rm_xid = xid; + request->rm_direction = CALL; + + request->rm_call.cb_rpcvers = 2; + request->rm_call.cb_prog = prognum; + request->rm_call.cb_vers = progver; + request->rm_call.cb_proc = procnum; + + request->rm_call.cb_cred.oa_flavor = AUTH_NONE; + request->rm_call.cb_cred.oa_base = NULL; + request->rm_call.cb_cred.oa_length = 0; + + request->rm_call.cb_verf.oa_flavor = AUTH_NONE; + request->rm_call.cb_verf.oa_base = NULL; + request->rm_call.cb_verf.oa_length = 0; + + ret = 0; +out: + return ret; +} + + +struct iovec +rpcsvc_callback_build_header (char *recordstart, size_t rlen, + struct rpc_msg *request, size_t payload) +{ + struct iovec requesthdr = {0, }; + struct iovec txrecord = {0, 0}; + int ret = -1; + size_t fraglen = 0; + + ret = rpc_request_to_xdr (request, recordstart, rlen, &requesthdr); + if (ret == -1) { + gf_log ("rpcsvc", GF_LOG_WARNING, + "Failed to create RPC request"); + goto out; + } + + fraglen = payload + requesthdr.iov_len; + gf_log ("rpcsvc", GF_LOG_TRACE, "Request fraglen %zu, payload: %zu, " + "rpc hdr: %zu", fraglen, payload, requesthdr.iov_len); + txrecord.iov_base = recordstart; /* Remember, this is only the vec for the RPC header and does not @@ -1348,27 +867,141 @@ rpcsvc_record_build_header (char *recordstart, size_t rlen, * the size of the full fragment. This size is sent in the fragment * header. */ - txrecord.iov_len = RPCSVC_FRAGHDR_SIZE + replyhdr.iov_len; -err: + txrecord.iov_len = requesthdr.iov_len; + +out: return txrecord; } +struct iobuf * +rpcsvc_callback_build_record (rpcsvc_t *rpc, int prognum, int progver, + int procnum, size_t payload, uint64_t xid, + struct iovec *recbuf) +{ + struct rpc_msg request = {0, }; + struct iobuf *request_iob = NULL; + char *record = NULL; + struct iovec recordhdr = {0, }; + size_t pagesize = 0; + size_t xdr_size = 0; + int ret = -1; + + if ((!rpc) || (!recbuf)) { + goto out; + } + + /* Fill the rpc structure and XDR it into the buffer got above. */ + ret = rpcsvc_fill_callback (prognum, progver, procnum, payload, xid, + &request); + if (ret == -1) { + gf_log ("rpcsvc", GF_LOG_WARNING, "cannot build a rpc-request " + "xid (%"PRIu64")", xid); + goto out; + } + + /* First, try to get a pointer into the buffer which the RPC + * layer can use. + */ + xdr_size = xdr_sizeof ((xdrproc_t)xdr_callmsg, &request); + + request_iob = iobuf_get2 (rpc->ctx->iobuf_pool, (xdr_size + payload)); + if (!request_iob) { + goto out; + } + + pagesize = iobuf_pagesize (request_iob); + + record = iobuf_ptr (request_iob); /* Now we have it. */ + + recordhdr = rpcsvc_callback_build_header (record, pagesize, &request, + payload); + + if (!recordhdr.iov_base) { + gf_log ("rpc-clnt", GF_LOG_ERROR, "Failed to build record " + " header"); + iobuf_unref (request_iob); + request_iob = NULL; + recbuf->iov_base = NULL; + goto out; + } + + recbuf->iov_base = recordhdr.iov_base; + recbuf->iov_len = recordhdr.iov_len; + +out: + return request_iob; +} + +int +rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans, + rpcsvc_cbk_program_t *prog, int procnum, + struct iovec *proghdr, int proghdrcount) +{ + struct iobuf *request_iob = NULL; + struct iovec rpchdr = {0,}; + rpc_transport_req_t req; + int ret = -1; + int proglen = 0; + uint64_t callid = 0; + + if (!rpc) { + goto out; + } + + memset (&req, 0, sizeof (req)); + + callid = rpcsvc_get_callid (rpc); + + if (proghdr) { + proglen += iov_length (proghdr, proghdrcount); + } + + request_iob = rpcsvc_callback_build_record (rpc, prog->prognum, + prog->progver, procnum, + proglen, callid, + &rpchdr); + if (!request_iob) { + gf_log ("rpcsvc", GF_LOG_WARNING, + "cannot build rpc-record"); + goto out; + } + + req.msg.rpchdr = &rpchdr; + req.msg.rpchdrcount = 1; + req.msg.proghdr = proghdr; + req.msg.proghdrcount = proghdrcount; + + ret = rpc_transport_submit_request (trans, &req); + if (ret == -1) { + gf_log ("rpcsvc", GF_LOG_WARNING, + "transmission of rpc-request failed"); + goto out; + } + + ret = 0; + +out: + iobuf_unref (request_iob); + + return ret; +} int -rpcsvc_conn_submit (rpcsvc_conn_t *conn, struct iovec *hdrvec, - int hdrcount, struct iovec *proghdr, int proghdrcount, - struct iovec *progpayload, int progpayloadcount, - struct iobref *iobref, void *priv) +rpcsvc_transport_submit (rpc_transport_t *trans, struct iovec *rpchdr, + int rpchdrcount, struct iovec *proghdr, + int proghdrcount, struct iovec *progpayload, + int progpayloadcount, struct iobref *iobref, + void *priv) { int ret = -1; rpc_transport_reply_t reply = {{0, }}; - if ((!conn) || (!hdrvec) || (!hdrvec->iov_base) || (!conn->trans)) { + if ((!trans) || (!rpchdr) || (!rpchdr->iov_base)) { goto out; } - reply.msg.rpchdr = hdrvec; - reply.msg.rpchdrcount = hdrcount; + reply.msg.rpchdr = rpchdr; + reply.msg.rpchdrcount = rpchdrcount; reply.msg.proghdr = proghdr; reply.msg.proghdrcount = proghdrcount; reply.msg.progpayload = progpayload; @@ -1376,15 +1009,7 @@ rpcsvc_conn_submit (rpcsvc_conn_t *conn, struct iovec *hdrvec, reply.msg.iobref = iobref; reply.private = priv; - /* Now that we have both the RPC and Program buffers in xdr format - * lets hand it to the transmission layer. - */ - if (!rpcsvc_conn_check_active (conn)) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Connection inactive"); - goto out; - } - - ret = rpc_transport_submit_reply (conn->trans, &reply); + ret = rpc_transport_submit_reply (trans, &reply); out: return ret; @@ -1394,24 +1019,31 @@ out: int rpcsvc_fill_reply (rpcsvc_request_t *req, struct rpc_msg *reply) { + int ret = -1; rpcsvc_program_t *prog = NULL; if ((!req) || (!reply)) - return -1; + goto out; - prog = rpcsvc_request_program (req); + ret = 0; rpc_fill_empty_reply (reply, req->xid); - - if (req->rpc_status == MSG_DENIED) + if (req->rpc_status == MSG_DENIED) { rpc_fill_denied_reply (reply, req->rpc_err, req->auth_err); - else if (req->rpc_status == MSG_ACCEPTED) - rpc_fill_accepted_reply (reply, req->rpc_err, prog->proglowvers, - prog->proghighvers, req->verf.flavour, - req->verf.datalen, + goto out; + } + + prog = rpcsvc_request_program (req); + + if (req->rpc_status == MSG_ACCEPTED) + rpc_fill_accepted_reply (reply, req->rpc_err, + (prog) ? prog->proglowvers : 0, + (prog) ? prog->proghighvers: 0, + req->verf.flavour, req->verf.datalen, req->verf.authdata); else gf_log (GF_RPCSVC, GF_LOG_ERROR, "Invalid rpc_status value"); - return 0; +out: + return ret; } @@ -1425,35 +1057,40 @@ rpcsvc_fill_reply (rpcsvc_request_t *req, struct rpc_msg *reply) */ struct iobuf * rpcsvc_record_build_record (rpcsvc_request_t *req, size_t payload, - struct iovec *recbuf) + size_t hdrlen, struct iovec *recbuf) { struct rpc_msg reply; struct iobuf *replyiob = NULL; char *record = NULL; struct iovec recordhdr = {0, }; size_t pagesize = 0; - rpcsvc_conn_t *conn = NULL; + size_t xdr_size = 0; rpcsvc_t *svc = NULL; + int ret = -1; - if ((!req) || (!req->conn) || (!recbuf)) + if ((!req) || (!req->trans) || (!req->svc) || (!recbuf)) return NULL; - /* First, try to get a pointer into the buffer which the RPC - * layer can use. - */ - conn = req->conn; - svc = rpcsvc_conn_rpcsvc (conn); - replyiob = iobuf_get (svc->ctx->iobuf_pool); - pagesize = iobpool_pagesize ((struct iobuf_pool *)svc->ctx->iobuf_pool); + svc = req->svc; + + /* Fill the rpc structure and XDR it into the buffer got above. */ + ret = rpcsvc_fill_reply (req, &reply); + if (ret) + goto err_exit; + + xdr_size = xdr_sizeof ((xdrproc_t)xdr_replymsg, &reply); + + /* Payload would include 'readv' size etc too, where as + that comes as another payload iobuf */ + replyiob = iobuf_get2 (svc->ctx->iobuf_pool, (xdr_size + hdrlen)); if (!replyiob) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get iobuf"); goto err_exit; } + pagesize = iobuf_pagesize (replyiob); + record = iobuf_ptr (replyiob); /* Now we have it. */ - /* Fill the rpc structure and XDR it into the buffer got above. */ - rpcsvc_fill_reply (req, &reply); recordhdr = rpcsvc_record_build_header (record, pagesize, reply, payload); if (!recordhdr.iov_base) { @@ -1503,17 +1140,19 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr, int hdrcount, struct iovec *payload, int payloadcount, struct iobref *iobref) { - int ret = -1, i = 0; - struct iobuf *replyiob = NULL; - struct iovec recordhdr = {0, }; - rpcsvc_conn_t *conn = NULL; - size_t msglen = 0; - char new_iobref = 0; - - if ((!req) || (!req->conn)) + int ret = -1, i = 0; + struct iobuf *replyiob = NULL; + struct iovec recordhdr = {0, }; + rpc_transport_t *trans = NULL; + size_t msglen = 0; + size_t hdrlen = 0; + char new_iobref = 0; + rpcsvc_drc_globals_t *drc = NULL; + + if ((!req) || (!req->trans)) return -1; - conn = req->conn; + trans = req->trans; for (i = 0; i < hdrcount; i++) { msglen += proghdr[i].iov_len; @@ -1526,7 +1165,7 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr, gf_log (GF_RPCSVC, GF_LOG_TRACE, "Tx message: %zu", msglen); /* Build the buffer containing the encoded RPC reply. */ - replyiob = rpcsvc_record_build_record (req, msglen, &recordhdr); + replyiob = rpcsvc_record_build_record (req, msglen, hdrlen, &recordhdr); if (!replyiob) { gf_log (GF_RPCSVC, GF_LOG_ERROR,"Reply record creation failed"); goto disconnect_exit; @@ -1535,8 +1174,6 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr, if (!iobref) { iobref = iobref_new (); if (!iobref) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "memory allocation " - "failed"); goto disconnect_exit; } @@ -1545,14 +1182,35 @@ rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec *proghdr, iobref_add (iobref, replyiob); - ret = rpcsvc_conn_submit (conn, &recordhdr, 1, proghdr, hdrcount, - payload, payloadcount, iobref, - req->trans_private); + /* cache the request in the duplicate request cache for appropriate ops */ + if (req->reply) { + drc = req->svc->drc; + + LOCK (&drc->lock); + ret = rpcsvc_cache_reply (req, iobref, &recordhdr, 1, + proghdr, hdrcount, + payload, payloadcount); + UNLOCK (&drc->lock); + } - rpcsvc_request_destroy (conn, req); + ret = rpcsvc_transport_submit (trans, &recordhdr, 1, proghdr, hdrcount, + payload, payloadcount, iobref, + req->trans_private); if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to submit message"); + gf_log (GF_RPCSVC, GF_LOG_ERROR, "failed to submit message " + "(XID: 0x%x, Program: %s, ProgVers: %d, Proc: %d) to " + "rpc-transport (%s)", req->xid, + req->prog ? req->prog->progname : "(not matched)", + req->prog ? req->prog->progver : 0, + req->procnum, trans->name); + } else { + gf_log (GF_RPCSVC, GF_LOG_TRACE, + "submitted reply for rpc-message (XID: 0x%x, " + "Program: %s, ProgVers: %d, Proc: %d) to rpc-transport " + "(%s)", req->xid, req->prog ? req->prog->progname: "-", + req->prog ? req->prog->progver : 0, + req->procnum, trans->name); } disconnect_exit: @@ -1564,20 +1222,7 @@ disconnect_exit: iobref_unref (iobref); } - /* Note that a unref is called everytime a reply is sent. This is in - * response to the ref that is performed on the conn when a request is - * handed to the RPC program. - * - * The catch, however, is that if the reply is an rpc error, we must - * not unref. This is because the ref only contains - * references for the actors to which the request was handed plus one - * reference maintained by the RPC layer. By unrefing for a case where - * no actor was called, we will be losing the ref held for the RPC - * layer. - */ - if ((rpcsvc_request_accepted (req)) && - (rpcsvc_request_accepted_success (req))) - rpcsvc_conn_unref (conn); + rpcsvc_request_destroy (req); return ret; } @@ -1591,6 +1236,8 @@ rpcsvc_error_reply (rpcsvc_request_t *req) if (!req) return -1; + gf_log_callingfn ("", GF_LOG_DEBUG, "sending a RPC error reply"); + /* At this point the req should already have been filled with the * appropriate RPC error numbers. */ @@ -1599,50 +1246,92 @@ rpcsvc_error_reply (rpcsvc_request_t *req) /* Register the program with the local portmapper service. */ -int -rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, rpcsvc_conn_t *conn) +inline int +rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port) { - int ret = 0; - struct sockaddr_in sa = {0, }; + int ret = -1; /* FAIL */ - if (!newprog || !conn->trans) { + if (!newprog) { goto out; } + /* pmap_set() returns 0 for FAIL and 1 for SUCCESS */ if (!(pmap_set (newprog->prognum, newprog->progver, IPPROTO_TCP, - sa.sin_port))) { + port))) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not register with" " portmap"); goto out; } - ret = 0; + ret = 0; /* SUCCESS */ out: return ret; } -int +inline int rpcsvc_program_unregister_portmap (rpcsvc_program_t *prog) { + int ret = -1; + if (!prog) - return -1; + goto out; if (!(pmap_unset(prog->prognum, prog->progver))) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Could not unregister with" " portmap"); - return -1; + goto out; } - return 0; + ret = 0; +out: + return ret; +} + +int +rpcsvc_register_portmap_enabled (rpcsvc_t *svc) +{ + return svc->register_portmap; +} + +int32_t +rpcsvc_get_listener_port (rpcsvc_listener_t *listener) +{ + int32_t listener_port = -1; + + if ((listener == NULL) || (listener->trans == NULL)) { + goto out; + } + + switch (listener->trans->myinfo.sockaddr.ss_family) { + case AF_INET: + listener_port = ((struct sockaddr_in *)&listener->trans->myinfo.sockaddr)->sin_port; + break; + + case AF_INET6: + listener_port = ((struct sockaddr_in6 *)&listener->trans->myinfo.sockaddr)->sin6_port; + break; + + default: + gf_log (GF_RPCSVC, GF_LOG_DEBUG, + "invalid address family (%d)", + listener->trans->myinfo.sockaddr.ss_family); + goto out; + } + + listener_port = ntohs (listener_port); + +out: + return listener_port; } rpcsvc_listener_t * -rpcsvc_get_listener (rpcsvc_t *svc, uint16_t port) +rpcsvc_get_listener (rpcsvc_t *svc, uint16_t port, rpc_transport_t *trans) { - rpcsvc_listener_t *listener = NULL; - char found = 0; + rpcsvc_listener_t *listener = NULL; + char found = 0; + uint32_t listener_port = 0; if (!svc) { goto out; @@ -1651,8 +1340,24 @@ rpcsvc_get_listener (rpcsvc_t *svc, uint16_t port) pthread_mutex_lock (&svc->rpclock); { list_for_each_entry (listener, &svc->listeners, list) { - if (((struct sockaddr_in *)&listener->sa)->sin_port - == port) { + if (trans != NULL) { + if (listener->trans == trans) { + found = 1; + break; + } + + continue; + } + + listener_port = rpcsvc_get_listener_port (listener); + if (listener_port == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "invalid port for listener %s", + listener->trans->name); + continue; + } + + if (listener_port == port) { found = 1; break; } @@ -1680,7 +1385,7 @@ rpcsvc_submit_message (rpcsvc_request_t *req, struct iovec *proghdr, int hdrcount, struct iovec *payload, int payloadcount, struct iobref *iobref) { - if ((!req) || (!req->conn) || (!proghdr) || (!proghdr->iov_base)) + if ((!req) || (!req->trans) || (!proghdr) || (!proghdr->iov_base)) return -1; return rpcsvc_submit_generic (req, proghdr, hdrcount, payload, @@ -1689,84 +1394,106 @@ rpcsvc_submit_message (rpcsvc_request_t *req, struct iovec *proghdr, int -rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t prog) +rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t *program) { int ret = -1; + rpcsvc_program_t *prog = NULL; + if (!svc || !program) { + goto out; + } - if (!svc) - return -1; - - /* TODO: De-init the listening connection for this program. */ - ret = rpcsvc_program_unregister_portmap (&prog); + ret = rpcsvc_program_unregister_portmap (program); if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "portmap unregistration of" " program failed"); - goto err; + goto out; + } + + pthread_mutex_lock (&svc->rpclock); + { + list_for_each_entry (prog, &svc->programs, program) { + if ((prog->prognum == program->prognum) + && (prog->progver == program->progver)) { + break; + } + } + } + pthread_mutex_unlock (&svc->rpclock); + + if (prog == NULL) { + ret = -1; + goto out; } - ret = 0; gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Program unregistered: %s, Num: %d," - " Ver: %d, Port: %d", prog.progname, prog.prognum, - prog.progver, prog.progport); + " Ver: %d, Port: %d", prog->progname, prog->prognum, + prog->progver, prog->progport); -err: - if (ret == -1) + pthread_mutex_lock (&svc->rpclock); + { + list_del_init (&prog->program); + } + pthread_mutex_unlock (&svc->rpclock); + + ret = 0; +out: + if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Program unregistration failed" - ": %s, Num: %d, Ver: %d, Port: %d", prog.progname, - prog.prognum, prog.progver, prog.progport); + ": %s, Num: %d, Ver: %d, Port: %d", program->progname, + program->prognum, program->progver, program->progport); + } return ret; } -int -rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen) +inline int +rpcsvc_transport_peername (rpc_transport_t *trans, char *hostname, int hostlen) { - if (!conn || !conn->trans) + if (!trans) { return -1; + } - return rpc_transport_get_peername (conn->trans, hostname, hostlen); + return rpc_transport_get_peername (trans, hostname, hostlen); } -int -rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen, - struct sockaddr *sa, socklen_t sasize) +inline int +rpcsvc_transport_peeraddr (rpc_transport_t *trans, char *addrstr, int addrlen, + struct sockaddr_storage *sa, socklen_t sasize) { - if (!conn || !conn->trans) + if (!trans) { return -1; + } - return rpc_transport_get_peeraddr(conn->trans, addrstr, addrlen, sa, + return rpc_transport_get_peeraddr(trans, addrstr, addrlen, sa, sasize); } -rpcsvc_conn_t * -rpcsvc_conn_create (rpcsvc_t *svc, dict_t *options, char *name) +rpc_transport_t * +rpcsvc_transport_create (rpcsvc_t *svc, dict_t *options, char *name) { - int ret = -1; + int ret = -1; rpc_transport_t *trans = NULL; - rpcsvc_conn_t *conn = NULL; trans = rpc_transport_load (svc->ctx, options, name); if (!trans) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, "cannot create listener, " + gf_log (GF_RPCSVC, GF_LOG_WARNING, "cannot create listener, " "initing the transport failed"); goto out; } ret = rpc_transport_listen (trans); if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_DEBUG, + gf_log (GF_RPCSVC, GF_LOG_WARNING, "listening on transport failed"); goto out; } - conn = rpcsvc_conn_init (svc, trans); - if (!conn) { - ret = -1; - gf_log (GF_RPCSVC, GF_LOG_DEBUG, - "initializing connection for transport failed"); + ret = rpc_transport_register_notify (trans, rpcsvc_notify, svc); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_WARNING, "registering notify failed"); goto out; } @@ -1774,24 +1501,25 @@ rpcsvc_conn_create (rpcsvc_t *svc, dict_t *options, char *name) out: if ((ret == -1) && (trans)) { rpc_transport_disconnect (trans); + trans = NULL; } - return conn; + return trans; } rpcsvc_listener_t * -rpcsvc_listener_alloc (rpcsvc_t *svc, rpcsvc_conn_t *conn) +rpcsvc_listener_alloc (rpcsvc_t *svc, rpc_transport_t *trans) { rpcsvc_listener_t *listener = NULL; listener = GF_CALLOC (1, sizeof (*listener), gf_common_mt_rpcsvc_listener_t); if (!listener) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "memory allocation failed"); goto out; } - listener->conn = conn; + listener->trans = trans; + listener->svc = svc; INIT_LIST_HEAD (&listener->list); @@ -1805,33 +1533,123 @@ out: } -rpcsvc_listener_t * +int32_t rpcsvc_create_listener (rpcsvc_t *svc, dict_t *options, char *name) { - rpcsvc_conn_t *conn = NULL; + rpc_transport_t *trans = NULL; rpcsvc_listener_t *listener = NULL; + int32_t ret = -1; if (!svc || !options) { goto out; } - conn = rpcsvc_conn_create (svc, options, name); - if (!conn) { + trans = rpcsvc_transport_create (svc, options, name); + if (!trans) { + /* LOG TODO */ goto out; } - listener = rpcsvc_listener_alloc (svc, conn); + listener = rpcsvc_listener_alloc (svc, trans); if (listener == NULL) { goto out; } - conn->listener = listener; + ret = 0; out: - if (!listener && conn) { - rpcsvc_conn_deinit (conn); + if (!listener && trans) { + rpc_transport_disconnect (trans); } - return listener; + return ret; +} + + +int32_t +rpcsvc_create_listeners (rpcsvc_t *svc, dict_t *options, char *name) +{ + int32_t ret = -1, count = 0; + data_t *data = NULL; + char *str = NULL, *ptr = NULL, *transport_name = NULL; + char *transport_type = NULL, *saveptr = NULL, *tmp = NULL; + + if ((svc == NULL) || (options == NULL) || (name == NULL)) { + goto out; + } + + data = dict_get (options, "transport-type"); + if (data == NULL) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "option transport-type not set"); + goto out; + } + + transport_type = data_to_str (data); + if (transport_type == NULL) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "option transport-type not set"); + goto out; + } + + /* duplicate transport_type, since following dict_set will free it */ + transport_type = gf_strdup (transport_type); + if (transport_type == NULL) { + goto out; + } + + str = gf_strdup (transport_type); + if (str == NULL) { + goto out; + } + + ptr = strtok_r (str, ",", &saveptr); + + while (ptr != NULL) { + tmp = gf_strdup (ptr); + if (tmp == NULL) { + goto out; + } + + ret = gf_asprintf (&transport_name, "%s.%s", tmp, name); + if (ret == -1) { + goto out; + } + + ret = dict_set_dynstr (options, "transport-type", tmp); + if (ret == -1) { + goto out; + } + + tmp = NULL; + ptr = strtok_r (NULL, ",", &saveptr); + + ret = rpcsvc_create_listener (svc, options, transport_name); + if (ret != 0) { + goto out; + } + + GF_FREE (transport_name); + transport_name = NULL; + count++; + } + + ret = dict_set_dynstr (options, "transport-type", transport_type); + if (ret == -1) { + goto out; + } + + transport_type = NULL; + +out: + GF_FREE (str); + + GF_FREE (transport_type); + + GF_FREE (tmp); + + GF_FREE (transport_name); + + return count; } @@ -1889,35 +1707,47 @@ out: } - -int -rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program) +inline int +rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t *program) { - rpcsvc_program_t *newprog = NULL; - int ret = -1; - rpcsvc_listener_t *listener = NULL; + int ret = -1; + rpcsvc_program_t *newprog = NULL; + char already_registered = 0; - if (!svc) - return -1; - - newprog = GF_CALLOC (1, sizeof(*newprog), gf_common_mt_rpcsvc_program_t); - if (!newprog) - return -1; + if (!svc) { + goto out; + } - if (!program.actors) - goto free_prog; + if (program->actors == NULL) { + goto out; + } - memcpy (newprog, &program, sizeof (program)); + pthread_mutex_lock (&svc->rpclock); + { + list_for_each_entry (newprog, &svc->programs, program) { + if ((newprog->prognum == program->prognum) + && (newprog->progver == program->progver)) { + already_registered = 1; + break; + } + } + } + pthread_mutex_unlock (&svc->rpclock); - listener = svc->listener; + if (already_registered) { + ret = 0; + goto out; + } - ret = rpcsvc_program_register_portmap (newprog, listener->conn); - if (ret == -1) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "portmap registration of" - " program failed"); - goto free_prog; + newprog = GF_CALLOC (1, sizeof(*newprog),gf_common_mt_rpcsvc_program_t); + if (newprog == NULL) { + goto out; } + memcpy (newprog, program, sizeof (*program)); + + INIT_LIST_HEAD (&newprog->program); + pthread_mutex_lock (&svc->rpclock); { list_add_tail (&newprog->program, &svc->programs); @@ -1929,12 +1759,11 @@ rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program) " Ver: %d, Port: %d", newprog->progname, newprog->prognum, newprog->progver, newprog->progport); -free_prog: +out: if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Program registration failed:" - " %s, Num: %d, Ver: %d, Port: %d", newprog->progname, - newprog->prognum, newprog->progver, newprog->progport); - GF_FREE (newprog); + " %s, Num: %d, Ver: %d, Port: %d", program->progname, + program->prognum, program->progver, program->progport); } return ret; @@ -1962,10 +1791,10 @@ build_prog_details (rpcsvc_request_t *req, gf_dump_rsp *rsp) gf_prog_detail *prog = NULL; gf_prog_detail *prev = NULL; - if (!req || !req->conn || !req->conn->svc) + if (!req || !req->trans || !req->svc) goto out; - list_for_each_entry (program, &req->conn->svc->programs, program) { + list_for_each_entry (program, &req->svc->programs, program) { prog = GF_CALLOC (1, sizeof (*prog), 0); if (!prog) goto out; @@ -1988,38 +1817,41 @@ static int rpcsvc_dump (rpcsvc_request_t *req) { char rsp_buf[8 * 1024] = {0,}; - gf_dump_rsp rsp = {0,}; - struct iovec iov = {0,}; - int op_errno = EINVAL; - int ret = -1; + gf_dump_rsp rsp = {0,}; + struct iovec iov = {0,}; + int op_errno = EINVAL; + int ret = -1; + uint32_t dump_rsp_len = 0; if (!req) - goto fail; + goto sendrsp; ret = build_prog_details (req, &rsp); if (ret < 0) { op_errno = -ret; - goto fail; + goto sendrsp; } -fail: + op_errno = 0; + +sendrsp: rsp.op_errno = gf_errno_to_error (op_errno); rsp.op_ret = ret; + dump_rsp_len = xdr_sizeof ((xdrproc_t) xdr_gf_dump_rsp, + &rsp); + iov.iov_base = rsp_buf; - iov.iov_len = (8 * 1024); + iov.iov_len = dump_rsp_len; - ret = xdr_serialize_dump_rsp (iov, &rsp); + ret = xdr_serialize_generic (iov, &rsp, (xdrproc_t)xdr_gf_dump_rsp); if (ret < 0) { - if (req) - req->rpc_err = GARBAGE_ARGS; - op_errno = EINVAL; - goto fail; + ret = RPCSVC_ACTOR_ERROR; + } else { + rpcsvc_submit_generic (req, &iov, 1, NULL, 0, NULL); + ret = 0; } - ret = rpcsvc_submit_generic (req, &iov, 1, NULL, 0, - NULL); - free_prog_details (&rsp); return ret; @@ -2028,19 +1860,217 @@ fail: int rpcsvc_init_options (rpcsvc_t *svc, dict_t *options) { + char *optstr = NULL; + int ret = -1; + + if ((!svc) || (!options)) + return -1; + svc->memfactor = RPCSVC_DEFAULT_MEMFACTOR; - return 0; + + svc->register_portmap = _gf_true; + if (dict_get (options, "rpc.register-with-portmap")) { + ret = dict_get_str (options, "rpc.register-with-portmap", + &optstr); + if (ret < 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to parse " + "dict"); + goto out; + } + + ret = gf_string2boolean (optstr, &svc->register_portmap); + if (ret < 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to parse bool " + "string"); + goto out; + } + } + + if (!svc->register_portmap) + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Portmap registration " + "disabled"); + + ret = rpcsvc_set_outstanding_rpc_limit (svc, options); +out: + return ret; +} + +int +rpcsvc_reconfigure_options (rpcsvc_t *svc, dict_t *options) +{ + xlator_t *xlator = NULL; + xlator_list_t *volentry = NULL; + char *srchkey = NULL; + char *keyval = NULL; + int ret = -1; + + if ((!svc) || (!svc->options) || (!options)) + return (-1); + + /* Fetch the xlator from svc */ + xlator = (xlator_t *) svc->mydata; + if (!xlator) + return (-1); + + /* Reconfigure the volume specific rpc-auth.addr allow part */ + volentry = xlator->children; + while (volentry) { + ret = gf_asprintf (&srchkey, "rpc-auth.addr.%s.allow", + volentry->xlator->name); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + return (-1); + } + + /* If found the srchkey, delete old key/val pair + * and set the key with new value. + */ + if (!dict_get_str (options, srchkey, &keyval)) { + dict_del (svc->options, srchkey); + ret = dict_set_str (svc->options, srchkey, keyval); + if (ret < 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "dict_set_str error"); + GF_FREE (srchkey); + return (-1); + } + } + + GF_FREE (srchkey); + volentry = volentry->next; + } + + /* Reconfigure the volume specific rpc-auth.addr reject part */ + volentry = xlator->children; + while (volentry) { + ret = gf_asprintf (&srchkey, "rpc-auth.addr.%s.reject", + volentry->xlator->name); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + return (-1); + } + + /* If found the srchkey, delete old key/val pair + * and set the key with new value. + */ + if (!dict_get_str (options, srchkey, &keyval)) { + dict_del (svc->options, srchkey); + ret = dict_set_str (svc->options, srchkey, keyval); + if (ret < 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, + "dict_set_str error"); + GF_FREE (srchkey); + return (-1); + } + } + + GF_FREE (srchkey); + volentry = volentry->next; + } + + ret = rpcsvc_init_options (svc, options); + if (ret) + return (-1); + + return rpcsvc_auth_reconf (svc, options); } +int +rpcsvc_transport_unix_options_build (dict_t **options, char *filepath) +{ + dict_t *dict = NULL; + char *fpath = NULL; + int ret = -1; + + GF_ASSERT (filepath); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + fpath = gf_strdup (filepath); + if (!fpath) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (dict, "transport.socket.listen-path", fpath); + if (ret) + goto out; + + ret = dict_set_str (dict, "transport.address-family", "unix"); + if (ret) + goto out; + + ret = dict_set_str (dict, "transport.socket.nodelay", "off"); + if (ret) + goto out; + + ret = dict_set_str (dict, "transport-type", "socket"); + if (ret) + goto out; + + *options = dict; +out: + if (ret) { + GF_FREE (fpath); + if (dict) + dict_unref (dict); + } + return ret; +} + +/* + * Reconfigure() the rpc.outstanding-rpc-limit param. + */ +int +rpcsvc_set_outstanding_rpc_limit (rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; /* FAILURE */ + int rpclim = 0; + static char *rpclimkey = "rpc.outstanding-rpc-limit"; + + if ((!svc) || (!options)) + return (-1); + + /* Reconfigure() the rpc.outstanding-rpc-limit param */ + ret = dict_get_int32 (options, rpclimkey, &rpclim); + if (ret < 0) { + /* Fall back to default for FAILURE */ + rpclim = RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT; + } else { + /* SUCCESS: round off to multiple of 8. + * If the input value fails Boundary check, fall back to + * default i.e. RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT. + * NB: value 0 is special, means its unset i.e. unlimited. + */ + rpclim = ((rpclim + 8 - 1) >> 3) * 8; + if (rpclim < RPCSVC_MIN_OUTSTANDING_RPC_LIMIT) { + rpclim = RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT; + } else if (rpclim > RPCSVC_MAX_OUTSTANDING_RPC_LIMIT) { + rpclim = RPCSVC_MAX_OUTSTANDING_RPC_LIMIT; + } + } + + if (svc->outstanding_rpc_limit != rpclim) { + svc->outstanding_rpc_limit = rpclim; + gf_log (GF_RPCSVC, GF_LOG_INFO, + "Configured %s with value %d", + rpclimkey, rpclim); + } + + return (0); +} /* The global RPC service initializer. */ rpcsvc_t * -rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options) +rpcsvc_init (xlator_t *xl, glusterfs_ctx_t *ctx, dict_t *options, + uint32_t poolcount) { - rpcsvc_t *svc = NULL; - int ret = -1; - rpcsvc_listener_t *listener = NULL; + rpcsvc_t *svc = NULL; + int ret = -1; if ((!ctx) || (!options)) return NULL; @@ -2061,6 +2091,17 @@ rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options) goto free_svc; } + if (!poolcount) + poolcount = RPCSVC_POOLCOUNT_MULT * svc->memfactor; + + gf_log (GF_RPCSVC, GF_LOG_TRACE, "rx pool: %d", poolcount); + svc->rxpool = mem_pool_new (rpcsvc_request_t, poolcount); + /* TODO: leak */ + if (!svc->rxpool) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "mem pool allocation failed"); + goto free_svc; + } + ret = rpcsvc_auth_init (svc, options); if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init " @@ -2071,38 +2112,18 @@ rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options) ret = -1; svc->options = options; svc->ctx = ctx; + svc->mydata = xl; gf_log (GF_RPCSVC, GF_LOG_DEBUG, "RPC service inited."); - /* One listen port per RPC */ - listener = rpcsvc_get_listener (svc, 0); - if (!listener) { - /* FIXME: listener is given the name of first program that - * creates it. This is not always correct. For eg., multiple - * programs can be listening on the same listener - * (glusterfs 3.1.0, 3.1.2, 3.1.3 etc). - */ - listener = rpcsvc_create_listener (svc, options, "RPC"); - if (!listener) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "creation of listener" - " for program failed"); - goto free_svc; - } - } - - if (!listener->conn) { - gf_log (GF_RPCSVC, GF_LOG_ERROR, "listener with no connection " - "found"); - goto free_svc; - } - - svc->listener = listener; + gluster_dump_prog.options = options; - ret = rpcsvc_program_register (svc, gluster_dump_prog); + ret = rpcsvc_program_register (svc, &gluster_dump_prog); if (ret) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "failed to register DUMP program"); goto free_svc; } + ret = 0; free_svc: if (ret == -1) { @@ -2114,10 +2135,339 @@ free_svc: } +int +rpcsvc_transport_peer_check_search (dict_t *options, char *pattern, + char *ip, char *hostname) +{ + int ret = -1; + char *addrtok = NULL; + char *addrstr = NULL; + char *dup_addrstr = NULL; + char *svptr = NULL; + + if ((!options) || (!ip)) + return -1; + + ret = dict_get_str (options, pattern, &addrstr); + if (ret < 0) { + ret = -1; + goto err; + } + + if (!addrstr) { + ret = -1; + goto err; + } + + dup_addrstr = gf_strdup (addrstr); + addrtok = strtok_r (dup_addrstr, ",", &svptr); + while (addrtok) { + + /* CASEFOLD not present on Solaris */ +#ifdef FNM_CASEFOLD + ret = fnmatch (addrtok, ip, FNM_CASEFOLD); +#else + ret = fnmatch (addrtok, ip, 0); +#endif + if (ret == 0) + goto err; + + /* compare hostnames if applicable */ + if (hostname) { +#ifdef FNM_CASEFOLD + ret = fnmatch (addrtok, hostname, FNM_CASEFOLD); +#else + ret = fnmatch (addrtok, hostname, 0); +#endif + if (ret == 0) + goto err; + } + + addrtok = strtok_r (NULL, ",", &svptr); + } + + ret = -1; +err: + GF_FREE (dup_addrstr); + + return ret; +} + + +static int +rpcsvc_transport_peer_check_allow (dict_t *options, char *volname, + char *ip, char *hostname) +{ + int ret = RPCSVC_AUTH_DONTCARE; + char *srchstr = NULL; + + if ((!options) || (!ip) || (!volname)) + return ret; + + ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + ret = RPCSVC_AUTH_DONTCARE; + goto out; + } + + ret = rpcsvc_transport_peer_check_search (options, srchstr, + ip, hostname); + GF_FREE (srchstr); + + if (ret == 0) + ret = RPCSVC_AUTH_ACCEPT; + else + ret = RPCSVC_AUTH_REJECT; +out: + return ret; +} + +static int +rpcsvc_transport_peer_check_reject (dict_t *options, char *volname, + char *ip, char *hostname) +{ + int ret = RPCSVC_AUTH_DONTCARE; + char *srchstr = NULL; + + if ((!options) || (!ip) || (!volname)) + return ret; + + ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.reject", + volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + ret = RPCSVC_AUTH_REJECT; + goto out; + } + + ret = rpcsvc_transport_peer_check_search (options, srchstr, + ip, hostname); + GF_FREE (srchstr); + + if (ret == 0) + ret = RPCSVC_AUTH_REJECT; + else + ret = RPCSVC_AUTH_DONTCARE; +out: + return ret; +} + + +/* Combines rpc auth's allow and reject options. + * Order of checks is important. + * First, REJECT if either rejects. + * If neither rejects, ACCEPT if either accepts. + * If neither accepts, DONTCARE + */ +int +rpcsvc_combine_allow_reject_volume_check (int allow, int reject) +{ + if (allow == RPCSVC_AUTH_REJECT || + reject == RPCSVC_AUTH_REJECT) + return RPCSVC_AUTH_REJECT; + + if (allow == RPCSVC_AUTH_ACCEPT || + reject == RPCSVC_AUTH_ACCEPT) + return RPCSVC_AUTH_ACCEPT; + + return RPCSVC_AUTH_DONTCARE; +} + +int +rpcsvc_auth_check (rpcsvc_t *svc, char *volname, + rpc_transport_t *trans) +{ + int ret = RPCSVC_AUTH_REJECT; + int accept = RPCSVC_AUTH_REJECT; + int reject = RPCSVC_AUTH_REJECT; + char *hostname = NULL; + char *ip = NULL; + char client_ip[RPCSVC_PEER_STRLEN] = {0}; + char *allow_str = NULL; + char *reject_str = NULL; + char *srchstr = NULL; + dict_t *options = NULL; + + if (!svc || !volname || !trans) + return ret; + + /* Fetch the options from svc struct and validate */ + options = svc->options; + if (!options) + return ret; + + ret = rpcsvc_transport_peername (trans, client_ip, RPCSVC_PEER_STRLEN); + if (ret != 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " + "%s", gai_strerror (ret)); + return RPCSVC_AUTH_REJECT; + } + + /* Accept if its the default case: Allow all, Reject none + * The default volfile always contains a 'allow *' rule + * for each volume. If allow rule is missing (which implies + * there is some bad volfile generating code doing this), we + * assume no one is allowed mounts, and thus, we reject mounts. + */ + ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + return RPCSVC_AUTH_REJECT; + } + + ret = dict_get_str (options, srchstr, &allow_str); + GF_FREE (srchstr); + if (ret < 0) + return RPCSVC_AUTH_REJECT; + + ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.reject", volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + return RPCSVC_AUTH_REJECT; + } + + ret = dict_get_str (options, srchstr, &reject_str); + GF_FREE (srchstr); + if (reject_str == NULL && !strcmp ("*", allow_str)) + return RPCSVC_AUTH_ACCEPT; + + /* Non-default rule, authenticate */ + if (!get_host_name (client_ip, &ip)) + ip = client_ip; + + /* addr-namelookup check */ + if (svc->addr_namelookup == _gf_true) { + ret = gf_get_hostname_from_ip (ip, &hostname); + if (ret) { + if (hostname) + GF_FREE (hostname); + /* failed to get hostname, but hostname auth + * is enabled, so authentication will not be + * 100% correct. reject mounts + */ + return RPCSVC_AUTH_REJECT; + } + } + + accept = rpcsvc_transport_peer_check_allow (options, volname, + ip, hostname); + + reject = rpcsvc_transport_peer_check_reject (options, volname, + ip, hostname); + + if (hostname) + GF_FREE (hostname); + return rpcsvc_combine_allow_reject_volume_check (accept, reject); +} + +int +rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, + rpc_transport_t *trans) +{ + union gf_sock_union sock_union; + int ret = RPCSVC_AUTH_REJECT; + socklen_t sinsize = sizeof (&sock_union.sin); + char *srchstr = NULL; + char *valstr = NULL; + uint16_t port = 0; + gf_boolean_t insecure = _gf_false; + + memset (&sock_union, 0, sizeof (sock_union)); + + if ((!svc) || (!volname) || (!trans)) + return ret; + + ret = rpcsvc_transport_peeraddr (trans, NULL, 0, &sock_union.storage, + sinsize); + if (ret != 0) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get peer addr: %s", + gai_strerror (ret)); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + port = ntohs (sock_union.sin.sin_port); + gf_log (GF_RPCSVC, GF_LOG_TRACE, "Client port: %d", (int)port); + /* If the port is already a privileged one, dont bother with checking + * options. + */ + if (port <= 1024) { + ret = RPCSVC_AUTH_ACCEPT; + goto err; + } + + /* Disabled by default */ + ret = gf_asprintf (&srchstr, "rpc-auth.ports.%s.insecure", volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + ret = RPCSVC_AUTH_REJECT; + goto err; + } + + ret = dict_get_str (svc->options, srchstr, &valstr); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" + " read rpc-auth.ports.insecure value"); + goto err; + } + + ret = gf_string2boolean (valstr, &insecure); + if (ret) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to" + " convert rpc-auth.ports.insecure value"); + goto err; + } + + ret = insecure ? RPCSVC_AUTH_ACCEPT : RPCSVC_AUTH_REJECT; + + if (ret == RPCSVC_AUTH_ACCEPT) + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port allowed"); + else + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Unprivileged port not" + " allowed"); + +err: + if (srchstr) + GF_FREE (srchstr); + + return ret; +} + + +char * +rpcsvc_volume_allowed (dict_t *options, char *volname) +{ + char globalrule[] = "rpc-auth.addr.allow"; + char *srchstr = NULL; + char *addrstr = NULL; + int ret = -1; + + if ((!options) || (!volname)) + return NULL; + + ret = gf_asprintf (&srchstr, "rpc-auth.addr.%s.allow", volname); + if (ret == -1) { + gf_log (GF_RPCSVC, GF_LOG_ERROR, "asprintf failed"); + goto out; + } + + if (!dict_get (options, srchstr)) + ret = dict_get_str (options, globalrule, &addrstr); + else + ret = dict_get_str (options, srchstr, &addrstr); + +out: + GF_FREE (srchstr); + + return addrstr; +} + + rpcsvc_actor_t gluster_dump_actors[] = { - [GF_DUMP_NULL] = {"NULL", GF_DUMP_NULL, NULL, NULL, NULL }, - [GF_DUMP_DUMP] = {"DUMP", GF_DUMP_DUMP, rpcsvc_dump, NULL, NULL }, - [GF_DUMP_MAXVALUE] = {"MAXVALUE", GF_DUMP_MAXVALUE, NULL, NULL, NULL }, + [GF_DUMP_NULL] = {"NULL", GF_DUMP_NULL, NULL, NULL, 0, DRC_NA}, + [GF_DUMP_DUMP] = {"DUMP", GF_DUMP_DUMP, rpcsvc_dump, NULL, 0, DRC_NA}, + [GF_DUMP_MAXVALUE] = {"MAXVALUE", GF_DUMP_MAXVALUE, NULL, NULL, 0, DRC_NA}, }; diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h index 10dc32698..cbc1f4226 100644 --- a/rpc/rpc-lib/src/rpcsvc.h +++ b/rpc/rpc-lib/src/rpcsvc.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _RPCSVC_H @@ -34,27 +25,37 @@ #include "iobuf.h" #include "xdr-rpc.h" #include "glusterfs.h" +#include "xlator.h" #include "rpcsvc-common.h" #include <pthread.h> #include <sys/uio.h> #include <inttypes.h> +#include <rpc/rpc_msg.h> #include "compat.h" -#ifndef NGRPS -#define NGRPS 16 -#endif /* !NGRPS */ +#ifndef MAX_IOVEC +#define MAX_IOVEC 16 +#endif + +#define RPCSVC_DEFAULT_OUTSTANDING_RPC_LIMIT 64 +#define RPCSVC_MAX_OUTSTANDING_RPC_LIMIT 65536 +#define RPCSVC_MIN_OUTSTANDING_RPC_LIMIT 0 /* No limit i.e. Unlimited */ #define GF_RPCSVC "rpc-service" #define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB)) #define RPCSVC_FRAGHDR_SIZE 4 /* 4-byte RPC fragment header size */ - -#define RPCSVC_DEFAULT_MEMFACTOR 15 +#define RPCSVC_DEFAULT_LISTEN_PORT GF_DEFAULT_BASE_PORT +#define RPCSVC_DEFAULT_MEMFACTOR 8 #define RPCSVC_EVENTPOOL_SIZE_MULT 1024 -#define RPCSVC_POOLCOUNT_MULT 35 +#define RPCSVC_POOLCOUNT_MULT 64 #define RPCSVC_CONN_READ (128 * GF_UNIT_KB) #define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB) +#define RPC_ROOT_UID 0 +#define RPC_ROOT_GID 0 +#define RPC_NOBODY_UID 65534 +#define RPC_NOBODY_GID 65534 /* RPC Record States */ #define RPCSVC_READ_FRAGHDR 1 @@ -109,8 +110,6 @@ #define AUTH_KERB 4 /* kerberos style */ #endif /* */ -#define AUTH_GLUSTERFS 5 - typedef struct rpcsvc_program rpcsvc_program_t; struct rpcsvc_notify_wrapper { @@ -120,85 +119,43 @@ struct rpcsvc_notify_wrapper { }; typedef struct rpcsvc_notify_wrapper rpcsvc_notify_wrapper_t; -#define RPCSVC_CONNSTATE_CONNECTED 1 -#define RPCSVC_CONNSTATE_DISCONNECTED 2 - -#define rpcsvc_conn_check_active(conn) ((conn)->connstate==RPCSVC_CONNSTATE_CONNECTED) typedef struct rpcsvc_request rpcsvc_request_t; -typedef struct rpc_conn_state rpcsvc_conn_t; typedef struct { - rpcsvc_conn_t *conn; - struct sockaddr sa; - struct list_head list; + rpc_transport_t *trans; + rpcsvc_t *svc; + /* FIXME: remove address from this structure. Instead use get_myaddr + * interface implemented by individual transports. + */ + struct sockaddr_storage sa; + struct list_head list; } rpcsvc_listener_t; struct rpcsvc_config { int max_block_size; }; -/* Contains the state for each connection that is used for transmitting and - * receiving RPC messages. - * - * Anything that can be accessed by a RPC program must be synced through - * connlock. - */ -struct rpc_conn_state { - - /* Transport or connection state */ - rpc_transport_t *trans; - - rpcsvc_t *svc; - /* RPC Records and Fragments assembly state. - * All incoming data is staged here before being - * called a full RPC message. - */ - /* rpcsvc_record_state_t rstate; */ - - /* It is possible that a client disconnects while - * the higher layer RPC service is busy in a call. - * In this case, we cannot just free the conn - * structure, since the higher layer service could - * still have a reference to it. - * The refcount avoids freeing until all references - * have been given up, although the connection is clos()ed at the first - * call to unref. - */ - int connref; - pthread_mutex_t connlock; - int connstate; - - /* Memory pool for rpcsvc_request_t */ - struct mem_pool *rxpool; - - /* The request which hasnt yet been handed to the RPC program because - * this request is being treated as a vector request and so needs some - * more data to be got from the network. - */ - /* rpcsvc_request_t *vectoredreq; */ - rpcsvc_listener_t *listener; -}; - -#define RPCSVC_CONNSTATE_CONNECTED 1 -#define RPCSVC_CONNSTATE_DISCONNECTED 2 - -#define RPCSVC_MAX_AUTH_BYTES 400 typedef struct rpcsvc_auth_data { int flavour; int datalen; - char authdata[RPCSVC_MAX_AUTH_BYTES]; + char authdata[GF_MAX_AUTH_BYTES]; } rpcsvc_auth_data_t; #define rpcsvc_auth_flavour(au) ((au).flavour) +typedef struct drc_client drc_client_t; +typedef struct drc_cached_op drc_cached_op_t; + /* The container for the RPC call handed up to an actor. * Dynamically allocated. Lives till the call reply is completely * transmitted. * */ struct rpcsvc_request { /* connection over which this request came. */ - rpcsvc_conn_t *conn; + rpc_transport_t *trans; + + rpcsvc_t *svc; rpcsvc_program_t *prog; @@ -222,13 +179,15 @@ struct rpcsvc_request { gid_t gid; pid_t pid; - uint64_t lk_owner; + gf_lkowner_t lk_owner; uint64_t gfs_id; - /* Might want to move this to AUTH_UNIX specifix state since this array - * is not available for every authenticatino scheme. + /* Might want to move this to AUTH_UNIX specific state since this array + * is not available for every authentication scheme. */ - gid_t auxgids[NGRPS]; + gid_t *auxgids; + gid_t auxgidsmall[SMALL_GROUP_COUNT]; + gid_t *auxgidlarge; int auxgidcount; @@ -236,22 +195,10 @@ struct rpcsvc_request { * by the program actors. This is the buffer that will need to * be de-xdred by the actor. */ - struct iovec msg[2]; - - /* The full message buffer allocated to store the RPC headers. - * This buffer is ref'd when allocated why RPC svc and unref'd after - * the buffer is handed to the actor. That means if the actor or any - * higher layer wants to keep this buffer around, they too must ref it - * right after entering the program actor. - */ - struct iobuf *recordiob; - - /* iobuf to hold payload of calls like write. By storing large payloads - * starting from page-aligned addresses, performance increases while - * accessing the payload - */ - struct iobuf *vectorediob; + struct iovec msg[MAX_IOVEC]; + int count; + struct iobref *iobref; /* Status of the RPC call, whether it was accepted or denied. */ int rpc_status; @@ -267,8 +214,8 @@ struct rpcsvc_request { int auth_err; /* There can be cases of RPC requests where the reply needs to - * be built from multiple sources. For eg. where even the NFS reply can - * contain a payload, as in the NFSv3 read reply. Here the RPC header + * be built from multiple sources. E.g. where even the NFS reply + * can contain a payload, as in the NFSv3 read reply. Here the RPC header * ,NFS header and the read data are brought together separately from * different buffers, so we need to stage the buffers temporarily here * before all of them get added to the connection's transmission list. @@ -290,6 +237,9 @@ struct rpcsvc_request { */ rpcsvc_auth_data_t verf; + /* Execute this request's actor function as a synctask? */ + gf_boolean_t synctask; + /* Container for a RPC program wanting to store a temp * request-specific item. */ @@ -297,33 +247,56 @@ struct rpcsvc_request { /* Container for transport to store request-specific item */ void *trans_private; + + /* we need to ref the 'iobuf' in case of 'synctasking' it */ + struct iobuf *hdr_iobuf; + + /* pointer to cached reply for use in DRC */ + drc_cached_op_t *reply; }; #define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->prog)) -#define rpcsvc_request_program_private(req) (((rpcsvc_program_t *)((req)->program))->private) -#define rpcsvc_request_conn(req) (req)->conn +#define rpcsvc_request_procnum(req) (((req)->procnum)) +#define rpcsvc_request_program_private(req) (((rpcsvc_program_t *)((req)->prog))->private) #define rpcsvc_request_accepted(req) ((req)->rpc_status == MSG_ACCEPTED) #define rpcsvc_request_accepted_success(req) ((req)->rpc_err == SUCCESS) -#define rpcsvc_request_uid(req) ((req)->uid) -#define rpcsvc_request_gid(req) ((req)->gid) -#define rpcsvc_conn_rpcsvc(conn) ((conn)->svc) -#define rpcsvc_request_service(req) (rpcsvc_conn_rpcsvc(rpcsvc_request_conn(req))) #define rpcsvc_request_prog_minauth(req) (rpcsvc_request_program(req)->min_auth) #define rpcsvc_request_cred_flavour(req) (rpcsvc_auth_flavour(req->cred)) #define rpcsvc_request_verf_flavour(req) (rpcsvc_auth_flavour(req->verf)) - +#define rpcsvc_request_service(req) ((req)->svc) #define rpcsvc_request_uid(req) ((req)->uid) #define rpcsvc_request_gid(req) ((req)->gid) #define rpcsvc_request_private(req) ((req)->private) #define rpcsvc_request_xid(req) ((req)->xid) #define rpcsvc_request_set_private(req,prv) (req)->private = (void *)(prv) -#define rpcsvc_request_record_iob(rq) ((rq)->recordiob) +#define rpcsvc_request_iobref_ref(req) (iobref_ref ((req)->iobref)) #define rpcsvc_request_record_ref(req) (iobuf_ref ((req)->recordiob)) #define rpcsvc_request_record_unref(req) (iobuf_unref ((req)->recordiob)) - +#define rpcsvc_request_record_iob(req) ((req)->recordiob) +#define rpcsvc_request_set_vecstate(req, state) ((req)->vecstate = state) +#define rpcsvc_request_vecstate(req) ((req)->vecstate) +#define rpcsvc_request_transport(req) ((req)->trans) +#define rpcsvc_request_transport_ref(req) (rpc_transport_ref((req)->trans)) +#define RPC_AUTH_ROOT_SQUASH(req) \ + do { \ + int gidcount = 0; \ + if (req->svc->root_squash) { \ + if (req->uid == RPC_ROOT_UID) \ + req->uid = RPC_NOBODY_UID; \ + if (req->gid == RPC_ROOT_GID) \ + req->gid = RPC_NOBODY_GID; \ + for (gidcount = 0; gidcount < req->auxgidcount; \ + ++gidcount) { \ + if (!req->auxgids[gidcount]) \ + req->auxgids[gidcount] = \ + RPC_NOBODY_GID; \ + } \ + } \ + } while (0); #define RPCSVC_ACTOR_SUCCESS 0 #define RPCSVC_ACTOR_ERROR (-1) +#define RPCSVC_ACTOR_IGNORE (-2) /* Functor for every type of protocol actor * must be defined like this. @@ -338,9 +311,8 @@ struct rpcsvc_request { * */ typedef int (*rpcsvc_actor) (rpcsvc_request_t *req); -typedef int (*rpcsvc_vector_actor) (rpcsvc_request_t *req, struct iobuf *iob); -typedef int (*rpcsvc_vector_sizer) (rpcsvc_request_t *req, ssize_t *readsize, - int *newiob); +typedef int (*rpcsvc_vector_sizer) (int state, ssize_t *readsize, + char *base_addr, char *curr_addr); /* Every protocol actor will also need to specify the function the RPC layer * will use to serialize or encode the message into XDR format just before @@ -354,7 +326,6 @@ typedef void *(*rpcsvc_encode_reply) (void *msg); */ typedef void (*rpcsvc_deallocate_reply) (void *msg); - #define RPCSVC_NAME_MAX 32 /* The descriptor for each procedure/actor that runs * over the RPC service. @@ -370,11 +341,13 @@ typedef struct rpcsvc_actor_desc { * the XDR scheme, RPC cannot guarantee memory aligned addresses for * the resulting message-specific structures. Allowing a specialized * handler for letting the RPC program read the data from the network - * directly into its alligned buffers. + * directly into its aligned buffers. */ - rpcsvc_vector_actor vector_actor; rpcsvc_vector_sizer vector_sizer; + /* Can actor be ran on behalf an unprivileged requestor? */ + gf_boolean_t unprivileged; + drc_op_type_t op_type; } rpcsvc_actor_t; /* Describes a program and its version along with the function pointers @@ -429,19 +402,26 @@ struct rpcsvc_program { */ int min_auth; + /* Execute actor function as a synctask? */ + gf_boolean_t synctask; + /* list member to link to list of registered services with rpcsvc */ struct list_head program; }; - +typedef struct rpcsvc_cbk_program { + char *progname; + int prognum; + int progver; +} rpcsvc_cbk_program_t; /* All users of RPC services should use this API to register their * procedure handlers. */ extern int -rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program); +rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t *program); extern int -rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t program); +rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t *program); /* This will create and add a listener to listener pool. Programs can * use any of the listener in this pool. A single listener can be used by @@ -451,18 +431,30 @@ rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t program); * rpcsvc_program_register_portmap. */ /* FIXME: can multiple programs registered on same port? */ -extern rpcsvc_listener_t * -rpcsvc_create_listener (rpcsvc_t *svc, dict_t *options, char *name); +extern int32_t +rpcsvc_create_listeners (rpcsvc_t *svc, dict_t *options, char *name); + +void +rpcsvc_listener_destroy (rpcsvc_listener_t *listener); extern int -rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, - rpcsvc_conn_t *conn); +rpcsvc_program_register_portmap (rpcsvc_program_t *newprog, uint32_t port); + +extern int +rpcsvc_program_unregister_portmap (rpcsvc_program_t *newprog); + +extern int +rpcsvc_register_portmap_enabled (rpcsvc_t *svc); /* Inits the global RPC service data structures. * Called in main. */ extern rpcsvc_t * -rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options); +rpcsvc_init (xlator_t *xl, glusterfs_ctx_t *ctx, dict_t *options, + uint32_t poolcount); + +extern int +rpcsvc_reconfigure_options (rpcsvc_t *svc, dict_t *options); int rpcsvc_register_notify (rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata); @@ -474,6 +466,13 @@ int rpcsvc_unregister_notify (rpcsvc_t *svc, rpcsvc_notify_t notify, void *mydata); int +rpcsvc_transport_submit (rpc_transport_t *trans, struct iovec *rpchdr, + int rpchdrcount, struct iovec *proghdr, + int proghdrcount, struct iovec *progpayload, + int progpayloadcount, struct iobref *iobref, + void *priv); + +int rpcsvc_submit_message (rpcsvc_request_t *req, struct iovec *proghdr, int hdrcount, struct iovec *payload, int payloadcount, struct iobref *iobref); @@ -492,17 +491,19 @@ rpcsvc_error_reply (rpcsvc_request_t *req); #define RPCSVC_AUTH_DONTCARE 3 extern int -rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen); +rpcsvc_transport_peername (rpc_transport_t *trans, char *hostname, int hostlen); extern int -rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen, - struct sockaddr *returnsa, socklen_t sasize); +rpcsvc_transport_peeraddr (rpc_transport_t *trans, char *addrstr, int addrlen, + struct sockaddr_storage *returnsa, socklen_t sasize); extern int -rpcsvc_conn_peer_check (dict_t *options, char *volname, rpcsvc_conn_t *conn); +rpcsvc_auth_check (rpcsvc_t *svc, char *volname, rpc_transport_t *trans); extern int -rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, rpcsvc_conn_t *conn); +rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, + rpc_transport_t *trans); + #define rpcsvc_request_seterr(req, err) (req)->rpc_err = err #define rpcsvc_request_set_autherr(req, err) (req)->auth_err = err @@ -513,7 +514,7 @@ extern int rpcsvc_request_attach_vector (rpcsvc_request_t *req, struct iobref *ioref, int finalvector); -typedef int (*auth_init_conn) (rpcsvc_conn_t *conn, void *priv); +typedef int (*auth_init_trans) (rpc_transport_t *trans, void *priv); typedef int (*auth_init_request) (rpcsvc_request_t *req, void *priv); typedef int (*auth_request_authenticate) (rpcsvc_request_t *req, void *priv); @@ -522,7 +523,7 @@ typedef int (*auth_request_authenticate) (rpcsvc_request_t *req, void *priv); * each connection will end up using a different authentication scheme. */ typedef struct rpcsvc_auth_ops { - auth_init_conn conn_init; + auth_init_trans transport_init; auth_init_request request_init; auth_request_authenticate authenticate; } rpcsvc_auth_ops_t; @@ -558,7 +559,10 @@ extern int rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options); extern int -rpcsvc_auth_conn_init (rpcsvc_conn_t *xprt); +rpcsvc_auth_reconf (rpcsvc_t *svc, dict_t *options); + +extern int +rpcsvc_auth_transport_init (rpc_transport_t *xprt); extern int rpcsvc_authenticate (rpcsvc_request_t *req); @@ -574,9 +578,29 @@ rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen); extern gid_t * rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen); -extern int -rpcsvc_combine_gen_spec_volume_checks (int gen, int spec); - extern char * rpcsvc_volume_allowed (dict_t *options, char *volname); + +int rpcsvc_callback_submit (rpcsvc_t *rpc, rpc_transport_t *trans, + rpcsvc_cbk_program_t *prog, int procnum, + struct iovec *proghdr, int proghdrcount); + +rpcsvc_actor_t * +rpcsvc_program_actor (rpcsvc_request_t *req); + +int +rpcsvc_transport_unix_options_build (dict_t **options, char *filepath); +int +rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options); +int +rpcsvc_set_addr_namelookup (rpcsvc_t *svc, dict_t *options); +int +rpcsvc_set_root_squash (rpcsvc_t *svc, dict_t *options); +int +rpcsvc_set_outstanding_rpc_limit (rpcsvc_t *svc, dict_t *options); +int +rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen); +rpcsvc_vector_sizer +rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum, + uint32_t progver, uint32_t procnum); #endif diff --git a/rpc/rpc-lib/src/xdr-common.h b/rpc/rpc-lib/src/xdr-common.h index 7ba137252..34dc9c6a2 100644 --- a/rpc/rpc-lib/src/xdr-common.h +++ b/rpc/rpc-lib/src/xdr-common.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _XDR_COMMON_H_ @@ -25,75 +16,52 @@ #include "config.h" #endif -#include <rpc/rpc.h> +#include <rpc/types.h> +#include <sys/types.h> +#include <rpc/xdr.h> +#include <sys/uio.h> + +#ifdef __NetBSD__ +#include <dirent.h> +#endif /* __NetBSD__ */ -enum { +enum gf_dump_procnum { GF_DUMP_NULL, GF_DUMP_DUMP, GF_DUMP_MAXVALUE, -} gf_dump_procnum_t; +}; #define GLUSTER_DUMP_PROGRAM 123451501 /* Completely random */ #define GLUSTER_DUMP_VERSION 1 +#define GF_MAX_AUTH_BYTES 2048 #if GF_DARWIN_HOST_OS #define xdr_u_quad_t xdr_u_int64_t #define xdr_quad_t xdr_int64_t #define xdr_uint32_t xdr_u_int32_t +#define uint64_t u_int64_t #endif -struct auth_glusterfs_parms { - u_quad_t lk_owner; - u_int pid; - u_int uid; - u_int gid; - u_int ngrps; - u_int groups[16]; -}; -typedef struct auth_glusterfs_parms auth_glusterfs_parms; - -struct gf_dump_req { - u_quad_t gfs_id; -}; -typedef struct gf_dump_req gf_dump_req; - -struct gf_prog_detail { - char *progname; - u_quad_t prognum; - u_quad_t progver; - struct gf_prog_detail *next; -}; -typedef struct gf_prog_detail gf_prog_detail; - -struct gf_dump_rsp { - u_quad_t gfs_id; - int op_ret; - int op_errno; - struct gf_prog_detail *prog; -}; -typedef struct gf_dump_rsp gf_dump_rsp; - -extern bool_t -xdr_auth_glusterfs_parms (XDR *xdrs, auth_glusterfs_parms *objp); -extern bool_t xdr_gf_dump_req (XDR *, gf_dump_req*); -extern bool_t xdr_gf_prog_detail (XDR *, gf_prog_detail*); -extern bool_t xdr_gf_dump_rsp (XDR *, gf_dump_rsp*); +#if defined(__NetBSD__) +#define xdr_u_quad_t xdr_u_int64_t +#define xdr_quad_t xdr_int64_t +#define xdr_uint32_t xdr_u_int32_t +#define xdr_uint64_t xdr_u_int64_t +#endif -ssize_t -xdr_serialize_dump_rsp (struct iovec outmsg, void *rsp); -ssize_t -xdr_to_dump_req (struct iovec inmsg, void *args); -ssize_t -xdr_from_dump_req (struct iovec outmsg, void *rsp); -ssize_t -xdr_to_dump_rsp (struct iovec inmsg, void *args); -#define XDR_BYTES_PER_UNIT 4 +#if GF_SOLARIS_HOST_OS +#define u_quad_t uint64_t +#define quad_t int64_t +#define xdr_u_quad_t xdr_uint64_t +#define xdr_quad_t xdr_int64_t +#define xdr_uint32_t xdr_uint32_t +#endif /* Returns the address of the byte that follows the * last byte used for decoding the previous xdr component. - * For eg, once the RPC call for NFS has been decoded, thie macro will return + * E.g. once the RPC call for NFS has been decoded, the macro will return * the address from which the NFS header starts. */ #define xdr_decoded_remaining_addr(xdr) ((&xdr)->x_private) diff --git a/rpc/rpc-lib/src/xdr-rpc.c b/rpc/rpc-lib/src/xdr-rpc.c index 088bddbf5..adb48a531 100644 --- a/rpc/rpc-lib/src/xdr-rpc.c +++ b/rpc/rpc-lib/src/xdr-rpc.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -33,6 +24,7 @@ #include "xdr-rpc.h" #include "xdr-common.h" #include "logging.h" +#include "common-utils.h" /* Decodes the XDR format in msgbuf into rpc_msg. * The remaining payload is returned into payload. @@ -42,11 +34,12 @@ xdr_to_rpc_call (char *msgbuf, size_t len, struct rpc_msg *call, struct iovec *payload, char *credbytes, char *verfbytes) { XDR xdr; - char opaquebytes[MAX_AUTH_BYTES]; + char opaquebytes[GF_MAX_AUTH_BYTES]; struct opaque_auth *oa = NULL; + int ret = -1; - if ((!msgbuf) || (!call)) - return -1; + GF_VALIDATE_OR_GOTO ("rpc", msgbuf, out); + GF_VALIDATE_OR_GOTO ("rpc", call, out); memset (call, 0, sizeof (*call)); @@ -63,15 +56,19 @@ xdr_to_rpc_call (char *msgbuf, size_t len, struct rpc_msg *call, oa->oa_base = verfbytes; xdrmem_create (&xdr, msgbuf, len, XDR_DECODE); - if (!xdr_callmsg (&xdr, call)) - return -1; + if (!xdr_callmsg (&xdr, call)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to decode call msg"); + goto out; + } if (payload) { payload->iov_base = xdr_decoded_remaining_addr (xdr); payload->iov_len = xdr_decoded_remaining_len (xdr); } - return 0; + ret = 0; +out: + return ret; } @@ -85,8 +82,9 @@ true_func (XDR *s, caddr_t *a) int rpc_fill_empty_reply (struct rpc_msg *reply, uint32_t xid) { - if (!reply) - return -1; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("rpc", reply, out); /* Setting to 0 also results in reply verifier flavor to be * set to AUTH_NULL which is what we want right now. @@ -95,19 +93,22 @@ rpc_fill_empty_reply (struct rpc_msg *reply, uint32_t xid) reply->rm_xid = xid; reply->rm_direction = REPLY; - return 0; + ret = 0; +out: + return ret; } int rpc_fill_denied_reply (struct rpc_msg *reply, int rjstat, int auth_err) { - if (!reply) - return -1; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("rpc", reply, out); reply->rm_reply.rp_stat = MSG_DENIED; reply->rjcted_rply.rj_stat = rjstat; if (rjstat == RPC_MISMATCH) { - /* No problem with hardocoding + /* No problem with hardcoding * RPC version numbers. We only support * v2 anyway. */ @@ -116,7 +117,9 @@ rpc_fill_denied_reply (struct rpc_msg *reply, int rjstat, int auth_err) } else if (rjstat == AUTH_ERROR) reply->rjcted_rply.rj_why = auth_err; - return 0; + ret = 0; +out: + return ret; } @@ -124,8 +127,9 @@ int rpc_fill_accepted_reply (struct rpc_msg *reply, int arstat, int proglow, int proghigh, int verf, int len, char *vdata) { - if (!reply) - return -1; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("rpc", reply, out); reply->rm_reply.rp_stat = MSG_ACCEPTED; reply->acpted_rply.ar_stat = arstat; @@ -145,26 +149,34 @@ rpc_fill_accepted_reply (struct rpc_msg *reply, int arstat, int proglow, reply->acpted_rply.ar_results.where = NULL; } - return 0; + ret = 0; +out: + return ret; } int rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len, struct iovec *dst) { - XDR xdr; + XDR xdr; + int ret = -1; - if ((!dest) || (!reply) || (!dst)) - return -1; + GF_VALIDATE_OR_GOTO ("rpc", reply, out); + GF_VALIDATE_OR_GOTO ("rpc", dest, out); + GF_VALIDATE_OR_GOTO ("rpc", dst, out); xdrmem_create (&xdr, dest, len, XDR_ENCODE); - if (!xdr_replymsg(&xdr, reply)) - return -1; + if (!xdr_replymsg(&xdr, reply)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to encode reply msg"); + goto out; + } dst->iov_base = dest; dst->iov_len = xdr_encoded_length (xdr); - return 0; + ret = 0; +out: + return ret; } @@ -173,9 +185,12 @@ xdr_to_auth_unix_cred (char *msgbuf, int msglen, struct authunix_parms *au, char *machname, gid_t *gids) { XDR xdr; + int ret = -1; - if ((!msgbuf) || (!machname) || (!gids) || (!au)) - return -1; + GF_VALIDATE_OR_GOTO ("rpc", msgbuf, out); + GF_VALIDATE_OR_GOTO ("rpc", machname, out); + GF_VALIDATE_OR_GOTO ("rpc", gids, out); + GF_VALIDATE_OR_GOTO ("rpc", au, out); au->aup_machname = machname; #ifdef GF_DARWIN_HOST_OS @@ -186,8 +201,12 @@ xdr_to_auth_unix_cred (char *msgbuf, int msglen, struct authunix_parms *au, xdrmem_create (&xdr, msgbuf, msglen, XDR_DECODE); - if (!xdr_authunix_parms (&xdr, au)) - return -1; + if (!xdr_authunix_parms (&xdr, au)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to decode auth unix parms"); + goto out; + } - return 0; + ret = 0; +out: + return ret; } diff --git a/rpc/rpc-lib/src/xdr-rpc.h b/rpc/rpc-lib/src/xdr-rpc.h index 4c0ee69b1..f5f4a941e 100644 --- a/rpc/rpc-lib/src/xdr-rpc.h +++ b/rpc/rpc-lib/src/xdr-rpc.h @@ -1,23 +1,14 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ -#ifndef _XDR_RPC_H +#ifndef _XDR_RPC_H_ #define _XDR_RPC_H_ #ifndef _CONFIG_H @@ -25,12 +16,28 @@ #include "config.h" #endif +#ifndef GF_SOLARIS_HOST_OS #include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> +#endif + +#ifdef GF_SOLARIS_HOST_OS +#include <rpc/auth.h> +#include <rpc/auth_sys.h> +#endif + +//#include <rpc/pmap_clnt.h> #include <arpa/inet.h> #include <rpc/xdr.h> #include <sys/uio.h> +#include "xdr-common.h" + +typedef enum { + AUTH_GLUSTERFS = 5, + AUTH_GLUSTERFS_v2 = 390039, /* using a number from 'unused' range, + from the list available in RFC5531 */ +} gf_rpc_authtype_t; + /* Converts a given network buffer from its XDR format to a structure * that contains everything an RPC call needs to work. */ @@ -54,7 +61,7 @@ rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len, extern int xdr_to_auth_unix_cred (char *msgbuf, int msglen, struct authunix_parms *au, char *machname, gid_t *gids); -/* Macros that simplify accesing the members of an RPC call structure. */ +/* Macros that simplify accessing the members of an RPC call structure. */ #define rpc_call_xid(call) ((call)->rm_xid) #define rpc_call_direction(call) ((call)->rm_direction) #define rpc_call_rpcvers(call) ((call)->ru.RM_cmb.cb_rpcvers) diff --git a/rpc/rpc-lib/src/xdr-rpcclnt.c b/rpc/rpc-lib/src/xdr-rpcclnt.c index 98676ae61..810d1961b 100644 --- a/rpc/rpc-lib/src/xdr-rpcclnt.c +++ b/rpc/rpc-lib/src/xdr-rpcclnt.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _CONFIG_H @@ -34,6 +25,7 @@ #include "xdr-rpc.h" #include "xdr-common.h" #include "logging.h" +#include "common-utils.h" /* Decodes the XDR format in msgbuf into rpc_msg. * The remaining payload is returned into payload. @@ -43,12 +35,10 @@ xdr_to_rpc_reply (char *msgbuf, size_t len, struct rpc_msg *reply, struct iovec *payload, char *verfbytes) { XDR xdr; - int ret = -1; + int ret = -EINVAL; - if ((!msgbuf) || (!reply)) { - ret = -EINVAL; - goto out; - } + GF_VALIDATE_OR_GOTO ("rpc", msgbuf, out); + GF_VALIDATE_OR_GOTO ("rpc", reply, out); memset (reply, 0, sizeof (struct rpc_msg)); @@ -58,6 +48,7 @@ xdr_to_rpc_reply (char *msgbuf, size_t len, struct rpc_msg *reply, xdrmem_create (&xdr, msgbuf, len, XDR_DECODE); if (!xdr_replymsg (&xdr, reply)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to decode reply msg"); ret = -errno; goto out; } @@ -71,13 +62,6 @@ out: return ret; } -#if 0 -bool_t -true_func (XDR *s, caddr_t *a) -{ - return TRUE; -} -#endif int rpc_request_to_xdr (struct rpc_msg *request, char *dest, size_t len, @@ -86,12 +70,13 @@ rpc_request_to_xdr (struct rpc_msg *request, char *dest, size_t len, XDR xdr; int ret = -1; - if ((!dest) || (!request) || (!dst)) { - goto out; - } + GF_VALIDATE_OR_GOTO ("rpc", dest, out); + GF_VALIDATE_OR_GOTO ("rpc", request, out); + GF_VALIDATE_OR_GOTO ("rpc", dst, out); xdrmem_create (&xdr, dest, len, XDR_ENCODE); if (!xdr_callmsg (&xdr, request)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to encode call msg"); goto out; } @@ -112,13 +97,14 @@ auth_unix_cred_to_xdr (struct authunix_parms *au, char *dest, size_t len, XDR xdr; int ret = -1; - if (!au || !dest || !iov) { - goto out; - } + GF_VALIDATE_OR_GOTO ("rpc", au, out); + GF_VALIDATE_OR_GOTO ("rpc", dest, out); + GF_VALIDATE_OR_GOTO ("rpc", iov, out); xdrmem_create (&xdr, dest, len, XDR_DECODE); if (!xdr_authunix_parms (&xdr, au)) { + gf_log ("rpc", GF_LOG_WARNING, "failed to decode authunix parms"); goto out; } diff --git a/rpc/rpc-lib/src/xdr-rpcclnt.h b/rpc/rpc-lib/src/xdr-rpcclnt.h index 37c3046d3..c08d872f8 100644 --- a/rpc/rpc-lib/src/xdr-rpcclnt.h +++ b/rpc/rpc-lib/src/xdr-rpcclnt.h @@ -1,20 +1,11 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #ifndef _XDR_RPCCLNT_H @@ -25,15 +16,15 @@ #include "config.h" #endif -#include <rpc/rpc.h> -#include <rpc/pmap_clnt.h> +//#include <rpc/rpc.h> +//#include <rpc/pmap_clnt.h> #include <arpa/inet.h> #include <rpc/xdr.h> #include <sys/uio.h> #include <rpc/rpc_msg.h> #include <rpc/auth_unix.h> -/* Macros that simplify accesing the members of an RPC call structure. */ +/* Macros that simplify accessing the members of an RPC call structure. */ #define rpc_reply_xid(reply) ((reply)->rm_xid) #define rpc_reply_status(reply) ((reply)->ru.RM_rmb.rp_stat) #define rpc_accepted_reply_status(reply) ((reply)->acpted_rply.ar_stat) |
