summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/iobuf.h
blob: 03aa954bbdda36d53a20951fd0ffb1a1d0b50bab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
  Copyright (c) 2008-2012 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 _IOBUF_H_
#define _IOBUF_H_

#include "list.h"
#include "common-utils.h"
#include <pthread.h>
#include <sys/mman.h>
#include <sys/uio.h>

#define GF_VARIABLE_IOBUF_COUNT 32

#define GF_RDMA_DEVICE_COUNT 8

/* Lets try to define the new anonymous mapping
 * flag, in case the system is still using the
 * now deprecated MAP_ANON flag.
 *
 * Also, this should ideally be in a centralized/common
 * header which can be used by other source files also.
 */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif

#define GF_ALIGN_BUF(ptr,bound) ((void *)((unsigned long)(ptr + bound - 1) & \
                                          (unsigned long)(~(bound - 1))))

#define GF_IOBUF_ALIGN_SIZE 512

/* one allocatable unit for the consumers of the IOBUF API */
/* each unit hosts @page_size bytes of memory */
struct iobuf;

/* one region of memory MMAPed from the operating system */
/* each region MMAPs @arena_size bytes of memory */
/* each arena hosts @arena_size / @page_size IOBUFs */
struct iobuf_arena;

/* expandable and contractable pool of memory, internally broken into arenas */
struct iobuf_pool;

struct iobuf_init_config {
        size_t   pagesize;
        int32_t  num_pages;
};

struct iobuf {
        union {
                struct list_head      list;
                struct {
                        struct iobuf *next;
                        struct iobuf *prev;
                };
        };
        struct iobuf_arena  *iobuf_arena;

        gf_lock_t            lock; /* for ->ptr and ->ref */
        int                  ref;  /* 0 == passive, >0 == active */

        void                *ptr;  /* usable memory region by the consumer */

        void                *free_ptr; /* in case of stdalloc, this is the
                                          one to be freed */
};


struct iobuf_arena {
        union {
                struct list_head            list;
                struct {
                        struct iobuf_arena *next;
                        struct iobuf_arena *prev;
                };
        };

        struct list_head    all_list;
        size_t              page_size;  /* size of all iobufs in this arena */
        size_t              arena_size;
        /* this is equal to rounded_size * num_iobufs.
           (rounded_size comes with gf_iobuf_get_pagesize().) */
        size_t              page_count;

        struct iobuf_pool  *iobuf_pool;

        void               *mem_base;
        struct iobuf       *iobufs;     /* allocated iobufs list */

        int                 active_cnt;
        struct iobuf        active;     /* head node iobuf
                                           (unused by itself) */
        int                 passive_cnt;
        struct iobuf        passive;    /* head node iobuf
                                           (unused by itself) */
        uint64_t            alloc_cnt;  /* total allocs in this pool */
        int                 max_active; /* max active buffers at a given time */
};


struct iobuf_pool {
        pthread_mutex_t     mutex;
        size_t              arena_size; /* size of memory region in
                                           arena */
        size_t              default_page_size; /* default size of iobuf */

        int                 arena_cnt;
        struct list_head    all_arenas;
        struct list_head    arenas[GF_VARIABLE_IOBUF_COUNT];
        /* array of arenas. Each element of the array is a list of arenas
           holding iobufs of particular page_size */

        struct list_head    filled[GF_VARIABLE_IOBUF_COUNT];
        /* array of arenas without free iobufs */

        struct list_head    purge[GF_VARIABLE_IOBUF_COUNT];
        /* array of of arenas which can be purged */

        uint64_t            request_misses; /* mostly the requests for higher
                                              value of iobufs */
        int                 rdma_device_count;
        struct list_head    *mr_list[GF_RDMA_DEVICE_COUNT];
        void                *device[GF_RDMA_DEVICE_COUNT];
        int (*rdma_registration)(void **, void*);
        int (*rdma_deregistration)(struct list_head**, struct iobuf_arena *);

};


struct iobuf_pool *iobuf_pool_new (void);
void iobuf_pool_destroy (struct iobuf_pool *iobuf_pool);
struct iobuf *iobuf_get (struct iobuf_pool *iobuf_pool);
void iobuf_unref (struct iobuf *iobuf);
struct iobuf *iobuf_ref (struct iobuf *iobuf);
void iobuf_pool_destroy (struct iobuf_pool *iobuf_pool);
void iobuf_to_iovec(struct iobuf *iob, struct iovec *iov);

#define iobuf_ptr(iob) ((iob)->ptr)
#define iobpool_default_pagesize(iobpool) ((iobpool)->default_page_size)
#define iobuf_pagesize(iob) (iob->iobuf_arena->page_size)


struct iobref {
        gf_lock_t          lock;
        int                ref;
        struct iobuf     **iobrefs;
	int                alloced;
	int                used;
};

struct iobref *iobref_new (void);
struct iobref *iobref_ref (struct iobref *iobref);
void iobref_unref (struct iobref *iobref);
int iobref_add (struct iobref *iobref, struct iobuf *iobuf);
int iobref_merge (struct iobref *to, struct iobref *from);
void iobref_clear (struct iobref *iobref);

size_t iobuf_size (struct iobuf *iobuf);
size_t iobref_size (struct iobref *iobref);
void   iobuf_stats_dump (struct iobuf_pool *iobuf_pool);

struct iobuf *
iobuf_get2 (struct iobuf_pool *iobuf_pool, size_t page_size);

struct iobuf *
iobuf_get_page_aligned (struct iobuf_pool *iobuf_pool, size_t page_size,
                        size_t align_size);
#endif /* !_IOBUF_H_ */
, 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;
+}
+
diff --git a/xlators/nfs/lib/src/rpc-socket.c b/xlators/nfs/lib/src/rpc-socket.c
new file mode 100644
index 00000000000..01f114a8530
--- /dev/null
+++ b/xlators/nfs/lib/src/rpc-socket.c
@@ -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;
+}
+
diff --git a/xlators/nfs/lib/src/rpc-socket.h b/xlators/nfs/lib/src/rpc-socket.h
new file mode 100644
index 00000000000..3a50c97a98d
--- /dev/null
+++ b/xlators/nfs/lib/src/rpc-socket.h
@@ -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
diff --git a/xlators/nfs/lib/src/rpcsvc-auth.c b/xlators/nfs/lib/src/rpcsvc-auth.c
new file mode 100644
index 00000000000..38697965bbd
--- /dev/null
+++ b/xlators/nfs/lib/src/rpcsvc-auth.c
@@ -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];
+}
+
diff --git a/xlators/nfs/lib/src/rpcsvc.c b/xlators/nfs/lib/src/rpcsvc.c
new file mode 100644
index 00000000000..e76ee16087a
--- /dev/null
+++ b/xlators/nfs/lib/src/rpcsvc.c
@@ -0,0 +1,2743 @@
+/*
+ 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 "rpc-socket.h"
+#include "dict.h"
+#include "logging.h"
+#include "byte-order.h"
+#include "common-utils.h"
+#include "compat-errno.h"
+#include "list.h"
+#include "xdr-rpc.h"
+#include "iobuf.h"
+#include "globals.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <arpa/inet.h>
+#include <rpc/xdr.h>
+#include <fnmatch.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+#define rpcsvc_alloc_request(con, request) \
+ do { \
+ request = (rpcsvc_request_t *) mem_get ((con)->rxpool); \
+ memset (request, 0, sizeof (rpcsvc_request_t)); \
+ } while (0) \
+
+/* The generic event handler for every stage */
+void *
+rpcsvc_stage_proc (void *arg)
+{
+ rpcsvc_stage_t *stg = (rpcsvc_stage_t *)arg;
+
+ if (!stg)
+ return NULL;
+
+ event_dispatch (stg->eventpool);
+ return NULL;
+}
+
+
+rpcsvc_stage_t *
+rpcsvc_stage_init (rpcsvc_t *svc)
+{
+ rpcsvc_stage_t *stg = NULL;
+ int ret = -1;
+ size_t stacksize = RPCSVC_THREAD_STACK_SIZE;
+ pthread_attr_t stgattr;
+ unsigned int eventpoolsize = 0;
+
+ if (!svc)
+ return NULL;
+
+ stg = CALLOC (1, sizeof(*stg));
+ if (!stg)
+ return NULL;
+
+ eventpoolsize = svc->memfactor * RPCSVC_EVENTPOOL_SIZE_MULT;
+ gf_log (GF_RPCSVC, GF_LOG_TRACE, "event pool size: %d", eventpoolsize);
+ stg->eventpool = event_pool_new (eventpoolsize);
+ if (!stg->eventpool)
+ goto free_stg;
+
+ pthread_attr_init (&stgattr);
+ ret = pthread_attr_setstacksize (&stgattr, stacksize);
+ if (ret == EINVAL)
+ gf_log (GF_RPCSVC, GF_LOG_WARNING,
+ "Using default thread stack size");
+
+ ret = pthread_create (&stg->tid, &stgattr, rpcsvc_stage_proc,
+ (void *)stg);
+ if (ret != 0) {
+ ret = -1;
+ gf_log (GF_RPCSVC, GF_LOG_ERROR, "Stage creation failed");
+ goto free_stg;
+ }
+
+ stg->svc = svc;
+ ret = 0;
+free_stg:
+ if (ret == -1) {
+ FREE (stg);
+ stg = NULL;
+ }
+
+ return stg;
+}
+
+
+int
+rpcsvc_init_options (rpcsvc_t *svc, dict_t *options)
+{
+ svc->memfactor = RPCSVC_DEFAULT_MEMFACTOR;
+ return 0;
+}
+
+
+/* The global RPC service initializer.
+ * Starts up the stages and then waits for RPC program registrations
+ * to come in.
+ */
+rpcsvc_t *
+rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options)
+{
+ rpcsvc_t *svc = NULL;
+ int ret = -1;
+
+ if ((!ctx) || (!options))
+ return NULL;
+
+ svc = CALLOC (1, sizeof (*svc));
+ if (!svc)
+ return NULL;
+
+ pthread_mutex_init (&svc->rpclock, NULL);
+ INIT_LIST_HEAD (&svc->stages);
+ INIT_LIST_HEAD (&svc->authschemes);
+
+ ret = rpcsvc_init_options (svc, options);
+ if (ret == -1) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init options");
+ goto free_svc;
+ }
+
+ ret = rpcsvc_auth_init (svc, options);
+ if (ret == -1) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init "
+ "authentication");
+ goto free_svc;
+ }
+
+ ret = -1;
+ svc->defaultstage = rpcsvc_stage_init (svc);
+ if (!svc->defaultstage) {
+ gf_log (GF_RPCSVC, GF_LOG_ERROR,"RPC service init failed.");
+ goto free_svc;
+ }
+ svc->options = options;
+ svc->ctx = ctx;
+ gf_log (GF_RPCSVC, GF_LOG_DEBUG, "RPC service inited.");
+
+ ret = 0;
+free_svc:
+ if (ret == -1) {
+ FREE (svc);
+ svc = NULL;
+ }
+
+ return svc;
+}
+
+
+/* Once multi-threaded support is complete, we'll be able to round-robin
+ * the various incoming connections over the many available stages. This
+ * function selects one from among all the stages.
+ */
+rpcsvc_stage_t *
+rpcsvc_select_stage (rpcsvc_t *rpcservice)
+{
+ if (!rpcservice)
+ return NULL;
+
+ return rpcservice->defaultstage;
+}
+
+
+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 = 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)
+ 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 = 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)
+ 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;
+}