nfs: Add RPCv2 service
Signed-off-by: Shehjar Tikoo <shehjart@gluster.com> Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 399 (NFS translator with Mount v3 and NFS v3 support) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
This commit is contained in:
parent
eff83c8dae
commit
8b2949db0d
@ -1,10 +1,10 @@
|
||||
lib_LTLIBRARIES = librpcsvc.la
|
||||
librpcsvc_la_LDFLAGS = -module -avoidversion
|
||||
|
||||
librpcsvc_la_SOURCES = msg-nfs3.c xdr-nfs3.c xdr-rpc.c
|
||||
librpcsvc_la_SOURCES = msg-nfs3.c xdr-nfs3.c xdr-rpc.c auth-unix.c rpcsvc-auth.c rpcsvc.c auth-null.c rpc-socket.c
|
||||
librpcsvc_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
noinst_HEADERS = xdr-rpc.h msg-nfs3.h xdr-common.h xdr-nfs3.h
|
||||
noinst_HEADERS = xdr-rpc.h msg-nfs3.h xdr-common.h xdr-nfs3.h rpc-socket.h rpcsvc.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)
|
||||
|
||||
|
71
xlators/nfs/lib/src/auth-null.c
Normal file
71
xlators/nfs/lib/src/auth-null.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rpcsvc.h"
|
||||
#include "list.h"
|
||||
#include "dict.h"
|
||||
|
||||
|
||||
int
|
||||
auth_null_request_init (rpcsvc_request_t *req, void *priv)
|
||||
{
|
||||
if (!req)
|
||||
return -1;
|
||||
|
||||
memset (req->cred.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
|
||||
req->cred.datalen = 0;
|
||||
|
||||
memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
|
||||
req->verf.datalen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int auth_null_authenticate (rpcsvc_request_t *req, void *priv)
|
||||
{
|
||||
/* Always succeed. */
|
||||
return RPCSVC_AUTH_ACCEPT;
|
||||
}
|
||||
|
||||
rpcsvc_auth_ops_t auth_null_ops = {
|
||||
.conn_init = NULL,
|
||||
.request_init = auth_null_request_init,
|
||||
.authenticate = auth_null_authenticate
|
||||
};
|
||||
|
||||
rpcsvc_auth_t rpcsvc_auth_null = {
|
||||
.authname = "AUTH_NULL",
|
||||
.authnum = AUTH_NULL,
|
||||
.authops = &auth_null_ops,
|
||||
.authprivate = NULL
|
||||
};
|
||||
|
||||
|
||||
rpcsvc_auth_t *
|
||||
rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options)
|
||||
{
|
||||
return &rpcsvc_auth_null;
|
||||
}
|
||||
|
91
xlators/nfs/lib/src/auth-unix.c
Normal file
91
xlators/nfs/lib/src/auth-unix.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rpcsvc.h"
|
||||
#include "list.h"
|
||||
#include "dict.h"
|
||||
#include "xdr-rpc.h"
|
||||
|
||||
|
||||
int
|
||||
auth_unix_request_init (rpcsvc_request_t *req, void *priv)
|
||||
{
|
||||
if (!req)
|
||||
return -1;
|
||||
memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
|
||||
req->verf.datalen = 0;
|
||||
req->verf.flavour = AUTH_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int auth_unix_authenticate (rpcsvc_request_t *req, void *priv)
|
||||
{
|
||||
int ret = RPCSVC_AUTH_REJECT;
|
||||
struct authunix_parms aup;
|
||||
char machname[MAX_MACHINE_NAME];
|
||||
|
||||
if (!req)
|
||||
return ret;
|
||||
|
||||
ret = xdr_to_auth_unix_cred (req->cred.authdata, req->cred.datalen,
|
||||
&aup, machname, req->auxgids);
|
||||
if (ret == -1) {
|
||||
ret = RPCSVC_AUTH_REJECT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
req->uid = aup.aup_uid;
|
||||
req->gid = aup.aup_gid;
|
||||
req->auxgidcount = aup.aup_len;
|
||||
|
||||
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: machine name: %s, uid: %d"
|
||||
", gid: %d", machname, req->uid, req->gid);
|
||||
ret = RPCSVC_AUTH_ACCEPT;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
rpcsvc_auth_ops_t auth_unix_ops = {
|
||||
.conn_init = NULL,
|
||||
.request_init = auth_unix_request_init,
|
||||
.authenticate = auth_unix_authenticate
|
||||
};
|
||||
|
||||
rpcsvc_auth_t rpcsvc_auth_unix = {
|
||||
.authname = "AUTH_UNIX",
|
||||
.authnum = AUTH_UNIX,
|
||||
.authops = &auth_unix_ops,
|
||||
.authprivate = NULL
|
||||
};
|
||||
|
||||
|
||||
rpcsvc_auth_t *
|
||||
rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options)
|
||||
{
|
||||
return &rpcsvc_auth_unix;
|
||||
}
|
||||
|
358
xlators/nfs/lib/src/rpc-socket.c
Normal file
358
xlators/nfs/lib/src/rpc-socket.c
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rpc-socket.h"
|
||||
#include "rpcsvc.h"
|
||||
#include "dict.h"
|
||||
#include "logging.h"
|
||||
#include "byte-order.h"
|
||||
#include "common-utils.h"
|
||||
#include "compat-errno.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
static int
|
||||
rpcsvc_socket_server_get_local_socket (int addrfam, char *listenhost,
|
||||
uint16_t listenport,
|
||||
struct sockaddr *addr,
|
||||
socklen_t *addr_len)
|
||||
{
|
||||
struct addrinfo hints, *res = 0;
|
||||
char service[NI_MAXSERV];
|
||||
int ret = -1;
|
||||
|
||||
memset (service, 0, sizeof (service));
|
||||
sprintf (service, "%d", listenport);
|
||||
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
addr->sa_family = hints.ai_family = addrfam;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
|
||||
|
||||
ret = getaddrinfo(listenhost, service, &hints, &res);
|
||||
if (ret != 0) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR,
|
||||
"getaddrinfo failed for host %s, service %s (%s)",
|
||||
listenhost, service, gai_strerror (ret));
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy (addr, res->ai_addr, res->ai_addrlen);
|
||||
*addr_len = res->ai_addrlen;
|
||||
|
||||
freeaddrinfo (res);
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport)
|
||||
{
|
||||
int sock = -1;
|
||||
struct sockaddr_storage sockaddr;
|
||||
socklen_t sockaddr_len;
|
||||
int flags = 0;
|
||||
int ret = -1;
|
||||
int opt = 1;
|
||||
|
||||
ret = rpcsvc_socket_server_get_local_socket (addrfam, listenhost,
|
||||
listenport,SA (&sockaddr),
|
||||
&sockaddr_len);
|
||||
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
|
||||
sock = socket (SA (&sockaddr)->sa_family, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "socket creation failed"
|
||||
" (%s)", strerror (errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
flags = fcntl (sock, F_GETFL);
|
||||
if (flags == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags"
|
||||
" (%s)", strerror(errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
ret = fcntl (sock, F_SETFL, flags | O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket "
|
||||
"non-blocking (%s)", strerror (errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "setsockopt() for "
|
||||
"SO_REUSEADDR failed (%s)", strerror (errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
ret = bind (sock, (struct sockaddr *)&sockaddr, sockaddr_len);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "binding socket failed:"
|
||||
" %s", strerror (errno));
|
||||
if (errno == EADDRINUSE)
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Port is already"
|
||||
" in use");
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
ret = listen (sock, 10);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "could not listen on"
|
||||
" socket (%s)", strerror (errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
close_err:
|
||||
close (sock);
|
||||
sock = -1;
|
||||
|
||||
err:
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_accept (int listenfd)
|
||||
{
|
||||
int new_sock = -1;
|
||||
struct sockaddr_storage new_sockaddr = {0, };
|
||||
socklen_t addrlen = sizeof (new_sockaddr);
|
||||
int flags = 0;
|
||||
int ret = -1;
|
||||
int on = 1;
|
||||
|
||||
new_sock = accept (listenfd, SA (&new_sockaddr), &addrlen);
|
||||
if (new_sock == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR,"accept on socket failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
flags = fcntl (new_sock, F_GETFL);
|
||||
if (flags == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags"
|
||||
" (%s)", strerror(errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
ret = fcntl (new_sock, F_SETFL, flags | O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket "
|
||||
"non-blocking (%s)", strerror (errno));
|
||||
goto close_err;
|
||||
}
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
ret = setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set no-delay "
|
||||
" socket option");
|
||||
}
|
||||
#endif
|
||||
|
||||
return new_sock;
|
||||
|
||||
close_err:
|
||||
close (new_sock);
|
||||
new_sock = -1;
|
||||
|
||||
err:
|
||||
return new_sock;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize)
|
||||
{
|
||||
ssize_t dataread = 0;
|
||||
ssize_t readlen = -1;
|
||||
|
||||
if (!readaddr)
|
||||
return -1;
|
||||
|
||||
while (readsize > 0) {
|
||||
readlen = read (sockfd, readaddr, readsize);
|
||||
if (readlen == -1) {
|
||||
if (errno != EAGAIN) {
|
||||
dataread = -1;
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
} else if (readlen == 0)
|
||||
break;
|
||||
|
||||
dataread += readlen;
|
||||
readaddr += readlen;
|
||||
readsize -= readlen;
|
||||
}
|
||||
|
||||
return dataread;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
rpcsvc_socket_write (int sockfd, char *buffer, size_t size)
|
||||
{
|
||||
size_t writelen = -1;
|
||||
ssize_t written = 0;
|
||||
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
while (size > 0) {
|
||||
writelen = write (sockfd, buffer, size);
|
||||
if (writelen == -1) {
|
||||
if (errno != EAGAIN) {
|
||||
written = -1;
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
} else if (writelen == 0)
|
||||
break;
|
||||
|
||||
written += writelen;
|
||||
size -= writelen;
|
||||
buffer += writelen;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
socklen_t sl = sizeof (sa);
|
||||
int ret = EAI_FAIL;
|
||||
|
||||
if (!hostname)
|
||||
return ret;
|
||||
|
||||
ret = getpeername (sockfd, &sa, &sl);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer name:"
|
||||
" %s", strerror (errno));
|
||||
ret = EAI_FAIL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = getnameinfo (&sa, sl, hostname, hostlen, NULL, 0, 0);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen,
|
||||
struct sockaddr *returnsa, socklen_t sasize)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
int ret = EAI_FAIL;
|
||||
|
||||
if (returnsa)
|
||||
ret = getpeername (sockfd, returnsa, &sasize);
|
||||
else {
|
||||
sasize = sizeof (sa);
|
||||
ret = getpeername (sockfd, &sa, &sasize);
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer addr:"
|
||||
" %s", strerror (errno));
|
||||
ret = EAI_FAIL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If caller did not specify a string into which the address can be
|
||||
* stored, dont bother getting it.
|
||||
*/
|
||||
if (!addrstr) {
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (returnsa)
|
||||
ret = getnameinfo (returnsa, sasize, addrstr, addrlen, NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
else
|
||||
ret = getnameinfo (&sa, sasize, addrstr, addrlen, NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_block_tx (int sockfd)
|
||||
{
|
||||
int ret = -1;
|
||||
int on = 1;
|
||||
|
||||
#ifdef TCP_CORK
|
||||
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
#ifdef TCP_NOPUSH
|
||||
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_socket_unblock_tx (int sockfd)
|
||||
{
|
||||
int ret = -1;
|
||||
int off = 0;
|
||||
|
||||
#ifdef TCP_CORK
|
||||
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
|
||||
#endif
|
||||
|
||||
#ifdef TCP_NOPUSH
|
||||
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &off, sizeof(off));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
65
xlators/nfs/lib/src/rpc-socket.h
Normal file
65
xlators/nfs/lib/src/rpc-socket.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _RPCSVC_SOCKET_H_
|
||||
#define _RPCSVC_SOCKET_H_
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rpcsvc.h"
|
||||
#include "dict.h"
|
||||
#include "logging.h"
|
||||
#include "byte-order.h"
|
||||
#include "common-utils.h"
|
||||
#include "compat-errno.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#define SA(ptr) ((struct sockaddr *)ptr)
|
||||
#define GF_RPCSVC_SOCK "rpc-socket"
|
||||
extern int
|
||||
rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport);
|
||||
|
||||
extern int
|
||||
rpcsvc_socket_accept (int listenfd);
|
||||
|
||||
extern ssize_t
|
||||
rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize);
|
||||
|
||||
extern ssize_t
|
||||
rpcsvc_socket_write (int sockfd, char *buffer, size_t size);
|
||||
|
||||
extern int
|
||||
rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen);
|
||||
|
||||
extern int
|
||||
rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen,
|
||||
struct sockaddr *returnsa, socklen_t sasize);
|
||||
extern int
|
||||
rpcsvc_socket_block_tx (int sockfd);
|
||||
|
||||
extern int
|
||||
rpcsvc_socket_unblock_tx (int sockfd);
|
||||
#endif
|
391
xlators/nfs/lib/src/rpcsvc-auth.c
Normal file
391
xlators/nfs/lib/src/rpcsvc-auth.c
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rpcsvc.h"
|
||||
#include "logging.h"
|
||||
#include "dict.h"
|
||||
|
||||
extern rpcsvc_auth_t *
|
||||
rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options);
|
||||
|
||||
extern rpcsvc_auth_t *
|
||||
rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options);
|
||||
|
||||
int
|
||||
rpcsvc_auth_add_initer (struct list_head *list, char *idfier,
|
||||
rpcsvc_auth_initer_t init)
|
||||
{
|
||||
struct rpcsvc_auth_list *new = NULL;
|
||||
|
||||
if ((!list) || (!init) || (!idfier))
|
||||
return -1;
|
||||
|
||||
new = CALLOC (1, sizeof (*new));
|
||||
if (!new) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Memory allocation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
new->init = init;
|
||||
strcpy (new->name, idfier);
|
||||
INIT_LIST_HEAD (&new->authlist);
|
||||
list_add_tail (&new->authlist, list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_auth_add_initers (rpcsvc_t *svc)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-unix",
|
||||
(rpcsvc_auth_initer_t)
|
||||
rpcsvc_auth_unix_init);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_UNIX");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-null",
|
||||
(rpcsvc_auth_initer_t)
|
||||
rpcsvc_auth_null_init);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_NULL");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_auth_init_auth (rpcsvc_t *svc, dict_t *options,
|
||||
struct rpcsvc_auth_list *authitem)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if ((!svc) || (!options) || (!authitem))
|
||||
return -1;
|
||||
|
||||
if (!authitem->init) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "No init function defined");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
authitem->auth = authitem->init (svc, options);
|
||||
if (!authitem->auth) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Registration of auth failed:"
|
||||
" %s", authitem->name);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
authitem->enable = 1;
|
||||
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Authentication enabled: %s",
|
||||
authitem->auth->authname);
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_auth_init_auths (rpcsvc_t *svc, dict_t *options)
|
||||
{
|
||||
int ret = -1;
|
||||
struct rpcsvc_auth_list *auth = NULL;
|
||||
struct rpcsvc_auth_list *tmp = NULL;
|
||||
|
||||
if (!svc)
|
||||
return -1;
|
||||
|
||||
if (list_empty (&svc->authschemes)) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!");
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If auth null and sys are not disabled by the user, we must enable
|
||||
* it by default. This is a globally default rule, the user is still
|
||||
* allowed to disable the two for particular subvolumes.
|
||||
*/
|
||||
if (!dict_get (options, "rpc-auth.auth-null"))
|
||||
ret = dict_set_dynstr (options, "rpc-auth.auth-null", "on");
|
||||
|
||||
if (!dict_get (options, "rpc-auth.auth-unix"))
|
||||
ret = dict_set_dynstr (options, "rpc-auth.auth-unix", "on");
|
||||
|
||||
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
|
||||
ret = rpcsvc_auth_init_auth (svc, options, auth);
|
||||
if (ret == -1)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if ((!svc) || (!options))
|
||||
return -1;
|
||||
|
||||
ret = rpcsvc_auth_add_initers (svc);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rpcsvc_auth_init_auths (svc, options);
|
||||
if (ret == -1) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init auth schemes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
rpcsvc_auth_t *
|
||||
__rpcsvc_auth_get_handler (rpcsvc_request_t *req)
|
||||
{
|
||||
int ret = -1;
|
||||
struct rpcsvc_auth_list *auth = NULL;
|
||||
struct rpcsvc_auth_list *tmp = NULL;
|
||||
rpcsvc_t *svc = NULL;
|
||||
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
svc = rpcsvc_request_service (req);
|
||||
if (list_empty (&svc->authschemes)) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!");
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
|
||||
if (!auth->enable)
|
||||
continue;
|
||||
if (auth->auth->authnum == req->cred.flavour)
|
||||
goto err;
|
||||
|
||||
}
|
||||
|
||||
auth = NULL;
|
||||
err:
|
||||
if (auth)
|
||||
return auth->auth;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpcsvc_auth_t *
|
||||
rpcsvc_auth_get_handler (rpcsvc_request_t *req)
|
||||
{
|
||||
rpcsvc_auth_t *auth = NULL;
|
||||
|
||||
auth = __rpcsvc_auth_get_handler (req);
|
||||
if (auth)
|
||||
goto ret;
|
||||
|
||||
gf_log (GF_RPCSVC, GF_LOG_TRACE, "No auth handler: %d",
|
||||
req->cred.flavour);
|
||||
|
||||
/* The requested scheme was not available so fall back the to one
|
||||
* scheme that will always be present.
|
||||
*/
|
||||
req->cred.flavour = AUTH_NULL;
|
||||
req->verf.flavour = AUTH_NULL;
|
||||
auth = __rpcsvc_auth_get_handler (req);
|
||||
ret:
|
||||
return auth;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_auth_request_init (rpcsvc_request_t *req)
|
||||
{
|
||||
int ret = -1;
|
||||
rpcsvc_auth_t *auth = NULL;
|
||||
|
||||
if (!req)
|
||||
return -1;
|
||||
|
||||
auth = rpcsvc_auth_get_handler (req);
|
||||
if (!auth)
|
||||
goto err;
|
||||
ret = 0;
|
||||
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth handler: %s", auth->authname);
|
||||
if (!auth->authops->request_init)
|
||||
ret = auth->authops->request_init (req, auth->authprivate);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpcsvc_authenticate (rpcsvc_request_t *req)
|
||||
{
|
||||
int ret = RPCSVC_AUTH_REJECT;
|
||||
rpcsvc_auth_t *auth = NULL;
|
||||
int minauth = 0;
|
||||
|
||||
if (!req)
|
||||
return ret;
|
||||
|
||||
minauth = rpcsvc_request_prog_minauth (req);
|
||||
if (minauth > rpcsvc_request_cred_flavour (req)) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_DEBUG, "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");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (auth->authops->authenticate)
|
||||
ret = auth->authops->authenticate (req, auth->authprivate);
|
||||
|
||||
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;
|
||||
|
||||
struct rpcsvc_auth_list *auth = NULL;
|
||||
struct rpcsvc_auth_list *tmp = NULL;
|
||||
|
||||
if ((!svc) || (!autharr) || (!volname))
|
||||
return -1;
|
||||
|
||||
memset (autharr, 0, arrlen * sizeof(int));
|
||||
if (list_empty (&svc->authschemes)) {
|
||||
gf_log (GF_RPCSVC, GF_LOG_ERROR, "No authentication!");
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
|
||||
if (count >= arrlen)
|
||||
break;
|
||||
|
||||
gen = asprintf (&srchstr, "rpc-auth.%s", auth->name);
|
||||
if (gen == -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");
|
||||
}
|
||||
|
||||
FREE (srchstr);
|
||||
spec = 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");
|
||||
}
|
||||
|
||||
FREE (srchstr);
|
||||
final = rpcsvc_combine_gen_spec_volume_checks (gen, spec);
|
||||
if (final == RPCSVC_AUTH_ACCEPT) {
|
||||
autharr[count] = auth->auth->authnum;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
*arrlen = req->auxgidcount;
|
||||
if (*arrlen == 0)
|
||||
return NULL;
|
||||
|
||||
return &req->auxgids[0];
|
||||
}
|
||||
|
2743
xlators/nfs/lib/src/rpcsvc.c
Normal file
2743
xlators/nfs/lib/src/rpcsvc.c
Normal file
File diff suppressed because it is too large
Load Diff
715
xlators/nfs/lib/src/rpcsvc.h
Normal file
715
xlators/nfs/lib/src/rpcsvc.h
Normal file
@ -0,0 +1,715 @@
|
||||
/*
|
||||
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
|
||||
This file is part of GlusterFS.
|
||||
|
||||
GlusterFS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
GlusterFS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _RPCSVC_H
|
||||
#define _RPCSVC_H
|
||||
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "transport.h"
|
||||
#include "logging.h"
|
||||
#include "dict.h"
|
||||
#include "mem-pool.h"
|
||||
#include "list.h"
|
||||
#include "iobuf.h"
|
||||
#include "xdr-rpc.h"
|
||||
#include "glusterfs.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#define GF_RPCSVC "rpc-service"
|
||||
#define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB))
|
||||
|
||||
#define RPCSVC_DEFAULT_MEMFACTOR 15
|
||||
#define RPCSVC_EVENTPOOL_SIZE_MULT 1024
|
||||
#define RPCSVC_POOLCOUNT_MULT 35
|
||||
#define RPCSVC_CONN_READ (128 * GF_UNIT_KB)
|
||||
#define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB)
|
||||
|
||||
/* Defines for RPC record and fragment assembly */
|
||||
|
||||
#define RPCSVC_FRAGHDR_SIZE 4 /* 4-byte RPC fragment header size */
|
||||
|
||||
/* Given the 4-byte fragment header, returns non-zero if this fragment
|
||||
* is the last fragment for the RPC record being assemebled.
|
||||
* 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.
|
||||
*/
|
||||
#define RPCSVC_LASTFRAG(fraghdr) ((uint32_t)(fraghdr & 0x80000000U))
|
||||
|
||||
/* Given the 4-byte fragment header, extracts the bits that contain
|
||||
* the fragment size.
|
||||
*/
|
||||
#define RPCSVC_FRAGSIZE(fraghdr) ((uint32_t)(fraghdr & 0x7fffffffU))
|
||||
|
||||
/* RPC Record States */
|
||||
#define RPCSVC_READ_FRAGHDR 1
|
||||
#define RPCSVC_READ_FRAG 2
|
||||
/* The size in bytes, if crossed by a fragment will be handed over to the
|
||||
* vectored actor so that it can allocate its buffers the way it wants.
|
||||
* In our RPC layer, we assume that vectored RPC requests/records are never
|
||||
* spread over multiple RPC fragments since that prevents us from determining
|
||||
* whether the record should be handled in RPC layer completely or handed to
|
||||
* the vectored handler.
|
||||
*/
|
||||
#define RPCSVC_VECTORED_FRAGSZ 4096
|
||||
#define RPCSVC_VECTOR_READCRED 1003
|
||||
#define RPCSVC_VECTOR_READVERFSZ 1004
|
||||
#define RPCSVC_VECTOR_READVERF 1005
|
||||
#define RPCSVC_VECTOR_IGNORE 1006
|
||||
#define RPCSVC_VECTOR_READVEC 1007
|
||||
#define RPCSVC_VECTOR_READPROCHDR 1008
|
||||
|
||||
#define rpcsvc_record_vectored_baremsg(rs) (((rs)->state == RPCSVC_READ_FRAG) && (rs)->vecstate == 0)
|
||||
#define rpcsvc_record_vectored_cred(rs) ((rs)->vecstate == RPCSVC_VECTOR_READCRED)
|
||||
#define rpcsvc_record_vectored_verfsz(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERFSZ)
|
||||
#define rpcsvc_record_vectored_verfread(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERF)
|
||||
#define rpcsvc_record_vectored_ignore(rs) ((rs)->vecstate == RPCSVC_VECTOR_IGNORE)
|
||||
#define rpcsvc_record_vectored_readvec(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVEC)
|
||||
#define rpcsvc_record_vectored_readprochdr(rs) ((rs)->vecstate == RPCSVC_VECTOR_READPROCHDR)
|
||||
#define rpcsvc_record_vectored(rs) ((rs)->fragsize > RPCSVC_VECTORED_FRAGSZ)
|
||||
/* Includes bytes up to and including the credential length field. The credlen
|
||||
* will be followed by @credlen bytes of credential data which will have to be
|
||||
* read separately by the vectored reader. After the credentials comes the
|
||||
* verifier which will also have to be read separately including the 8 bytes of
|
||||
* verf flavour and verflen.
|
||||
*/
|
||||
#define RPCSVC_BARERPC_MSGSZ 32
|
||||
#define rpcsvc_record_readfraghdr(rs) ((rs)->state == RPCSVC_READ_FRAGHDR)
|
||||
#define rpcsvc_record_readfrag(rs) ((rs)->state == RPCSVC_READ_FRAG)
|
||||
|
||||
#define rpcsvc_conn_rpcsvc(conn) ((conn)->stage->svc)
|
||||
#define RPCSVC_LOWVERS 2
|
||||
#define RPCSVC_HIGHVERS 2
|
||||
|
||||
typedef struct rpc_svc_program rpcsvc_program_t;
|
||||
/* A Stage is the event handler thread together with
|
||||
* the connections being served by this thread.
|
||||
* It is called a stage because all the actors, i.e, protocol actors,
|
||||
* defined by higher level users of the RPC layer, are executed here.
|
||||
*/
|
||||
typedef struct rpc_svc_stage_context {
|
||||
pthread_t tid;
|
||||
struct event_pool *eventpool; /* Per-stage event-pool */
|
||||
void *svc; /* Ref to the rpcsvc_t */
|
||||
} rpcsvc_stage_t;
|
||||
|
||||
|
||||
/* RPC Records and Fragments assembly state.
|
||||
* This is per-connection state that is used to determine
|
||||
* how much data has come in, how much more needs to be read
|
||||
* and where it needs to be read.
|
||||
*
|
||||
* All this state is then used to re-assemble network buffers into
|
||||
* RPC fragments, which are then re-assembled into RPC records.
|
||||
*
|
||||
* See RFC 1831: "RPC: Remote Procedure Call Protocol Specification Version 2",
|
||||
* particularly the section on Record Marking Standard.
|
||||
*/
|
||||
typedef struct rpcsvc_record_state {
|
||||
|
||||
/* Pending messages storage
|
||||
* This memory area is currently being used to assemble
|
||||
* the latest RPC record.
|
||||
*
|
||||
* Note that this buffer contains the data other than the
|
||||
* fragment headers received from the network. This is so that we can
|
||||
* directly pass this buffer to higher layers without requiring to
|
||||
* perform memory copies and marshalling of data.
|
||||
*/
|
||||
struct iobuf *activeiob;
|
||||
|
||||
struct iobuf *vectoriob;
|
||||
/* The pointer into activeiob memory, into which will go the
|
||||
* contents from the next read from the network.
|
||||
*/
|
||||
char *fragcurrent;
|
||||
|
||||
/* Size of the currently incomplete RPC fragment.
|
||||
* This is filled in when the fragment header comes in.
|
||||
* Even though only the 31 least significant bits are used from the
|
||||
* fragment header, we use a 32 bit variable to store the size.
|
||||
*/
|
||||
uint32_t fragsize;
|
||||
|
||||
/* The fragment header is always read in here so that
|
||||
* the RPC messages contained in a RPC records can be processed
|
||||
* separately without copying them out of the activeiob above.
|
||||
*/
|
||||
char fragheader[RPCSVC_FRAGHDR_SIZE];
|
||||
char *hdrcurrent;
|
||||
|
||||
/* Bytes remaining to come in for the current fragment. */
|
||||
uint32_t remainingfrag;
|
||||
|
||||
/* It is possible for the frag header to be split over separate
|
||||
* read calls, so we need to keep track of how much is left.
|
||||
*/
|
||||
uint32_t remainingfraghdr;
|
||||
|
||||
/* Record size, the total size of the RPC record, i.e. the total
|
||||
* of all fragment sizes received till now. Does not include the size
|
||||
* of a partial fragment which is continuing to be assembled right now.
|
||||
*/
|
||||
int recordsize;
|
||||
|
||||
/* Current state of the record */
|
||||
int state;
|
||||
|
||||
/* Current state of the vectored reading process. */
|
||||
int vecstate;
|
||||
|
||||
/* Set to non-zero when the currently partial or complete fragment is
|
||||
* the last fragment being received for the current RPC record.
|
||||
*/
|
||||
uint32_t islastfrag;
|
||||
|
||||
} rpcsvc_record_state_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;
|
||||
/* Contains the state for each connection that is used for transmitting and
|
||||
* receiving RPC messages.
|
||||
*
|
||||
* There is also an eventidx because each connection's fd is added to the event
|
||||
* pool of the stage to which a connection belongs.
|
||||
* Anything that can be accessed by a RPC program must be synced through
|
||||
* connlock.
|
||||
*/
|
||||
typedef struct rpc_conn_state {
|
||||
|
||||
/* Transport or connection state */
|
||||
|
||||
/* Once we start working on RDMA support, this TCP specific state will
|
||||
* have to be abstracted away.
|
||||
*/
|
||||
int sockfd;
|
||||
int eventidx;
|
||||
int windowsize;
|
||||
|
||||
/* Reference to the stage which is handling this
|
||||
* connection.
|
||||
*/
|
||||
rpcsvc_stage_t *stage;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The program that is listening for requests on this connection. */
|
||||
rpcsvc_program_t *program;
|
||||
|
||||
/* List of buffers awaiting transmission */
|
||||
/* Accesses to txbufs between multiple threads calling
|
||||
* rpcsvc_submit is synced through connlock. Prefer spinlock over
|
||||
* mutex because this is a low overhead op that needs simple
|
||||
* appending to the tx list.
|
||||
*/
|
||||
struct list_head txbufs;
|
||||
|
||||
/* Mem pool for the txbufs above. */
|
||||
struct mem_pool *txpool;
|
||||
|
||||
/* 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_conn_t;
|
||||
|
||||
|
||||
#define RPCSVC_MAX_AUTH_BYTES 400
|
||||
typedef struct rpcsvc_auth_data {
|
||||
int flavour;
|
||||
int datalen;
|
||||
char authdata[RPCSVC_MAX_AUTH_BYTES];
|
||||
} rpcsvc_auth_data_t;
|
||||
|
||||
#define rpcsvc_auth_flavour(au) ((au).flavour)
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The identifier for the call from client.
|
||||
* Needed to pair the reply with the call.
|
||||
*/
|
||||
uint32_t xid;
|
||||
|
||||
int prognum;
|
||||
|
||||
int progver;
|
||||
|
||||
int procnum;
|
||||
/* Uid and gid filled by the rpc-auth module during the authentication
|
||||
* phase.
|
||||
*/
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
/* Might want to move this to AUTH_UNIX specifix state since this array
|
||||
* is not available for every authenticatino scheme.
|
||||
*/
|
||||
gid_t auxgids[NGRPS];
|
||||
int auxgidcount;
|
||||
|
||||
|
||||
/* The RPC message payload, contains the data required
|
||||
* by the program actors. This is the buffer that will need to
|
||||
* be de-xdred by the actor.
|
||||
*/
|
||||
struct iovec msg;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Status of the RPC call, whether it was accepted or denied. */
|
||||
int rpc_stat;
|
||||
|
||||
/* In case, the call was denied, the RPC error is stored here
|
||||
* till the reply is sent.
|
||||
*/
|
||||
int rpc_err;
|
||||
|
||||
/* In case the failure happened because of an authentication problem
|
||||
* , this value needs to be assigned the correct auth error number.
|
||||
*/
|
||||
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
|
||||
* ,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.
|
||||
*/
|
||||
struct list_head txlist;
|
||||
|
||||
/* While the reply record is being built, this variable keeps track
|
||||
* of how many bytes have been added to the record.
|
||||
*/
|
||||
size_t payloadsize;
|
||||
|
||||
/* The credentials extracted from the rpc request */
|
||||
rpcsvc_auth_data_t cred;
|
||||
|
||||
/* The verified extracted from the rpc request. In request side
|
||||
* processing this contains the verifier sent by the client, on reply
|
||||
* side processing, it is filled with the verified that will be
|
||||
* sent to the client.
|
||||
*/
|
||||
rpcsvc_auth_data_t verf;
|
||||
|
||||
/* Container for a RPC program wanting to store a temp
|
||||
* request-specific item.
|
||||
*/
|
||||
void *private;
|
||||
|
||||
};
|
||||
|
||||
#define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->conn->program))
|
||||
#define rpcsvc_request_program_private(req) (((rpcsvc_program_t *)((req)->conn->program))->private)
|
||||
#define rpcsvc_request_conn(req) (req)->conn
|
||||
#define rpcsvc_request_accepted(req) ((req)->rpc_stat == 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_stage_service(stg) ((rpcsvc_t *)((stg)->svc))
|
||||
#define rpcsvc_conn_stage(conn) ((conn)->stage)
|
||||
#define rpcsvc_request_service(req) (rpcsvc_stage_service(rpcsvc_conn_stage(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_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_record_ref(req) (iobuf_ref ((req)->recordiob))
|
||||
#define rpcsvc_request_record_unref(req) (iobuf_unref ((req)->recordiob))
|
||||
|
||||
|
||||
#define RPCSVC_ACTOR_SUCCESS 0
|
||||
#define RPCSVC_ACTOR_ERROR (-1)
|
||||
|
||||
/* Functor for every type of protocol actor
|
||||
* must be defined like this.
|
||||
*
|
||||
* See the request structure for info on how to handle the request
|
||||
* in the program actor.
|
||||
*
|
||||
* On successful santify checks inside the actor, it should return
|
||||
* RPCSVC_ACTOR_SUCCESS.
|
||||
* On an error, on which the RPC layer is expected to return a reply, the actor
|
||||
* should return RPCSVC_ACTOR_ERROR.
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* transmitting on the connection.
|
||||
*/
|
||||
typedef void *(*rpcsvc_encode_reply) (void *msg);
|
||||
|
||||
/* Once the reply has been transmitted, the message will have to be de-allocated
|
||||
* , so every actor will need to provide a function that deallocates the message
|
||||
* it had allocated as a response.
|
||||
*/
|
||||
typedef void (*rpcsvc_deallocate_reply) (void *msg);
|
||||
|
||||
|
||||
#define RPCSVC_NAME_MAX 32
|
||||
/* The descriptor for each procedure/actor that runs
|
||||
* over the RPC service.
|
||||
*/
|
||||
typedef struct rpc_svc_actor_desc {
|
||||
char procname[RPCSVC_NAME_MAX];
|
||||
int procnum;
|
||||
rpcsvc_actor actor;
|
||||
|
||||
/* Handler for cases where the RPC requests fragments are large enough
|
||||
* to benefit from being decoded into aligned memory addresses. While
|
||||
* decoding the request in a non-vectored manner, due to the nature of
|
||||
* 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.
|
||||
*/
|
||||
rpcsvc_vector_actor vector_actor;
|
||||
rpcsvc_vector_sizer vector_sizer;
|
||||
|
||||
} rpcsvc_actor_t;
|
||||
|
||||
typedef int (*rpcsvc_conn_notify_fn) (void *progpriv, rpcsvc_conn_t *conn);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
struct rpc_svc_program {
|
||||
char progname[RPCSVC_NAME_MAX];
|
||||
int prognum;
|
||||
int progver;
|
||||
uint16_t progport; /* Registered with portmap */
|
||||
int progaddrfamily; /* AF_INET or AF_INET6 */
|
||||
char *proghost; /* Bind host, can be NULL */
|
||||
rpcsvc_actor_t *actors; /* All procedure handlers */
|
||||
int numactors; /* Num actors in actor array */
|
||||
int proghighvers; /* Highest ver for program
|
||||
supported by the system. */
|
||||
int proglowvers; /* Lowest ver */
|
||||
|
||||
/* Program specific state handed to actors */
|
||||
void *private;
|
||||
|
||||
/* This upcall is made when a connection's refcount reaches 0 and the
|
||||
* connection is about to be destroyed. We want to let the RPC program
|
||||
* know that it should also now free any state it is maintaining
|
||||
* for this connection.
|
||||
*/
|
||||
rpcsvc_conn_notify_fn conn_destroy;
|
||||
|
||||
/* Used to tell RPC program to init the state it needs to associate
|
||||
* with the new connection.
|
||||
*/
|
||||
rpcsvc_conn_notify_fn conn_init;
|
||||
|
||||
/* An integer that identifies the min auth strength that is required
|
||||
* by this protocol, for eg. MOUNT3 needs AUTH_UNIX at least.
|
||||
* See RFC 1813, Section 5.2.1.
|
||||
*/
|
||||
int min_auth;
|
||||
};
|
||||
|
||||
|
||||
/* Contains global state required for all the RPC services.
|
||||
*/
|
||||
typedef struct rpc_svc_state {
|
||||
|
||||
/* Contains the list of rpcsvc_stage_t
|
||||
* list of (program, version) handlers.
|
||||
* other options.
|
||||
*/
|
||||
|
||||
/* At this point, lock is not used to protect anything. Later, it'll
|
||||
* be used for protecting stages.
|
||||
*/
|
||||
pthread_mutex_t rpclock;
|
||||
|
||||
/* This is the first stage that is inited, so that any RPC based
|
||||
* services that do not need multi-threaded support can just use the
|
||||
* service right away. This is not added to the stages list
|
||||
* declared later.
|
||||
* This is also the stage over which all service listeners are run.
|
||||
*/
|
||||
rpcsvc_stage_t *defaultstage;
|
||||
|
||||
/* When we have multi-threaded RPC support, we'll use this to link
|
||||
* to the multiple Stages.
|
||||
*/
|
||||
struct list_head stages; /* All stages */
|
||||
|
||||
unsigned int memfactor;
|
||||
|
||||
/* List of the authentication schemes available. */
|
||||
struct list_head authschemes;
|
||||
|
||||
/* Reference to the options */
|
||||
dict_t *options;
|
||||
|
||||
/* Allow insecure ports. */
|
||||
int allow_insecure;
|
||||
|
||||
glusterfs_ctx_t *ctx;
|
||||
} rpcsvc_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);
|
||||
|
||||
extern int
|
||||
rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t program);
|
||||
|
||||
/* Inits the global RPC service data structures.
|
||||
* Called in main.
|
||||
*/
|
||||
extern rpcsvc_t *
|
||||
rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options);
|
||||
|
||||
|
||||
extern int
|
||||
rpcsvc_submit_message (rpcsvc_request_t * req, struct iovec msg,
|
||||
struct iobuf *iob);
|
||||
|
||||
int
|
||||
rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec msgvec,
|
||||
struct iobuf *msg);
|
||||
#define rpcsvc_record_currentfrag_addr(rs) ((rs)->fragcurrent)
|
||||
#define rpcsvc_record_currenthdr_addr(rs) ((rs)->hdrcurrent)
|
||||
|
||||
#define rpcsvc_record_update_currentfrag(rs, size) \
|
||||
do { \
|
||||
(rs)->fragcurrent += size; \
|
||||
} while (0) \
|
||||
|
||||
#define rpcsvc_record_update_currenthdr(rs, size) \
|
||||
do { \
|
||||
(rs)->hdrcurrent += size; \
|
||||
} while (0) \
|
||||
|
||||
|
||||
/* These are used to differentiate between multiple txbufs which form
|
||||
* a single RPC record. For eg, one purpose we use these for is to
|
||||
* prevent dividing a RPC record over multiple TCP segments. Multiple
|
||||
* TCP segments are possible for a single RPC record because we generally do not
|
||||
* have control over how the kernel's TCP segments the buffers when putting
|
||||
* them on the wire. So, on Linux, we use these to set TCP_CORK to create
|
||||
* a single TCP segment from multiple txbufs that are part of the same RPC
|
||||
* record. This improves network performance by reducing tiny message
|
||||
* transmissions.
|
||||
*/
|
||||
#define RPCSVC_TXB_FIRST 0x1
|
||||
#define RPCSVC_TXB_LAST 0x2
|
||||
|
||||
/* The list of buffers appended to a connection's pending
|
||||
* transmission list.
|
||||
*/
|
||||
typedef struct rpcsvc_txbuf {
|
||||
struct list_head txlist;
|
||||
/* The iobuf which contains the full message to be transmitted */
|
||||
struct iobuf *iob;
|
||||
|
||||
/* For vectored messages from an RPC program, we need to be able
|
||||
* maintain a ref to an iobuf which we do not have access to directly
|
||||
* except through the iobref which in turn could've been passed to
|
||||
* the RPC program by a higher layer.
|
||||
*
|
||||
* So either the iob is defined or iobref is defined for a reply,
|
||||
* never both.
|
||||
*/
|
||||
struct iobref *iobref;
|
||||
/* In order to handle non-blocking writes, we'll need to keep track of
|
||||
* how much data from an iobuf has been written and where the next
|
||||
* transmission needs to start from. This iov.base points to the base of
|
||||
* the iobuf, iov.len is the size of iobuf being used for the message
|
||||
* from the total size in the iobuf.
|
||||
*/
|
||||
struct iovec buf;
|
||||
/* offset is the point from where the next transmission for this buffer
|
||||
* should start.
|
||||
*/
|
||||
size_t offset;
|
||||
|
||||
/* This is a special field that tells us what kind of transmission
|
||||
* behaviour to provide to a particular buffer.
|
||||
* See the RPCSVC_TXB_* defines for more info.
|
||||
*/
|
||||
int txbehave;
|
||||
} rpcsvc_txbuf_t;
|
||||
|
||||
extern int
|
||||
rpcsvc_error_reply (rpcsvc_request_t *req);
|
||||
|
||||
#define RPCSVC_PEER_STRLEN 1024
|
||||
#define RPCSVC_AUTH_ACCEPT 1
|
||||
#define RPCSVC_AUTH_REJECT 2
|
||||
#define RPCSVC_AUTH_DONTCARE 3
|
||||
|
||||
extern int
|
||||
rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen);
|
||||
|
||||
extern int
|
||||
rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen,
|
||||
struct sockaddr *returnsa, socklen_t sasize);
|
||||
|
||||
extern int
|
||||
rpcsvc_conn_peer_check (dict_t *options, char *volname, rpcsvc_conn_t *conn);
|
||||
|
||||
extern int
|
||||
rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, rpcsvc_conn_t *conn);
|
||||
#define rpcsvc_request_seterr(req, err) (req)->rpc_err = err
|
||||
#define rpcsvc_request_set_autherr(req, err) (req)->auth_err = err
|
||||
|
||||
extern void
|
||||
rpcsvc_conn_deinit (rpcsvc_conn_t *conn);
|
||||
extern void rpcsvc_conn_ref (rpcsvc_conn_t *conn);
|
||||
extern void rpcsvc_conn_unref (rpcsvc_conn_t *conn);
|
||||
|
||||
extern int rpcsvc_submit_vectors (rpcsvc_request_t *req);
|
||||
|
||||
extern int rpcsvc_request_attach_vector (rpcsvc_request_t *req,
|
||||
struct iovec msgvec, struct iobuf *iob,
|
||||
struct iobref *ioref, int finalvector);
|
||||
|
||||
|
||||
typedef int (*auth_init_conn) (rpcsvc_conn_t *conn, void *priv);
|
||||
typedef int (*auth_init_request) (rpcsvc_request_t *req, void *priv);
|
||||
typedef int (*auth_request_authenticate) (rpcsvc_request_t *req, void *priv);
|
||||
|
||||
/* This structure needs to be registered by every authentication scheme.
|
||||
* Our authentication schemes are stored per connection because
|
||||
* each connection will end up using a different authentication scheme.
|
||||
*/
|
||||
typedef struct rpcsvc_auth_ops {
|
||||
auth_init_conn conn_init;
|
||||
auth_init_request request_init;
|
||||
auth_request_authenticate authenticate;
|
||||
} rpcsvc_auth_ops_t;
|
||||
|
||||
typedef struct rpcsvc_auth_flavour_desc {
|
||||
char authname[RPCSVC_NAME_MAX];
|
||||
int authnum;
|
||||
rpcsvc_auth_ops_t *authops;
|
||||
void *authprivate;
|
||||
} rpcsvc_auth_t;
|
||||
|
||||
typedef void * (*rpcsvc_auth_initer_t) (rpcsvc_t *svc, dict_t *options);
|
||||
|
||||
struct rpcsvc_auth_list {
|
||||
struct list_head authlist;
|
||||
rpcsvc_auth_initer_t init;
|
||||
/* Should be the name with which we identify the auth scheme given
|
||||
* in the volfile options.
|
||||
* This should be different from the authname in rpc_auth_t
|
||||
* in way that makes it easier to specify this scheme in the volfile.
|
||||
* This is because the technical names of the schemes can be a bit
|
||||
* arcane.
|
||||
*/
|
||||
char name[RPCSVC_NAME_MAX];
|
||||
rpcsvc_auth_t *auth;
|
||||
int enable;
|
||||
};
|
||||
|
||||
extern int
|
||||
rpcsvc_auth_request_init (rpcsvc_request_t *req);
|
||||
|
||||
extern int
|
||||
rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options);
|
||||
|
||||
extern int
|
||||
rpcsvc_auth_conn_init (rpcsvc_conn_t *conn);
|
||||
|
||||
extern int
|
||||
rpcsvc_authenticate (rpcsvc_request_t *req);
|
||||
|
||||
extern int
|
||||
rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
|
||||
|
||||
/* If the request has been sent using AUTH_UNIX, this function returns the
|
||||
* auxiliary gids as an array, otherwise, it returns NULL.
|
||||
* Move to auth-unix specific source file when we need to modularize the
|
||||
* authentication code even further to support mode auth schemes.
|
||||
*/
|
||||
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);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user