summaryrefslogtreecommitdiff
path: root/filesystems/glusterfs/files/ssl.patch
diff options
context:
space:
mode:
Diffstat (limited to 'filesystems/glusterfs/files/ssl.patch')
-rw-r--r--filesystems/glusterfs/files/ssl.patch1131
1 files changed, 1131 insertions, 0 deletions
diff --git a/filesystems/glusterfs/files/ssl.patch b/filesystems/glusterfs/files/ssl.patch
new file mode 100644
index 00000000000..7c2f2b6321b
--- /dev/null
+++ b/filesystems/glusterfs/files/ssl.patch
@@ -0,0 +1,1131 @@
+$NetBSD: ssl.patch,v 1.1 2011/12/09 16:57:44 manu Exp $
+
+SSL support pulled from not yet committed upstream patch
+http://review.gluster.com/#change,362
+
+--- rpc/rpc-transport/socket/src/Makefile.am.orig 2011-11-14 14:46:00.000000000 +0100
++++ rpc/rpc-transport/socket/src/Makefile.am 2011-12-03 06:46:39.000000000 +0100
+@@ -2,9 +2,9 @@
+
+ rpctransport_LTLIBRARIES = socket.la
+ rpctransportdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport
+
+-socket_la_LDFLAGS = -module -avoidversion
++socket_la_LDFLAGS = -module -avoidversion -lssl
+
+ socket_la_SOURCES = socket.c name.c
+ socket_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
+
+--- rpc/rpc-transport/socket/src/Makefile.in.orig 2011-11-14 14:46:14.000000000 +0100
++++ rpc/rpc-transport/socket/src/Makefile.in 2011-12-03 06:46:39.000000000 +0100
+@@ -226,9 +226,9 @@
+ target_alias = @target_alias@
+ noinst_HEADERS = socket.h name.h
+ rpctransport_LTLIBRARIES = socket.la
+ rpctransportdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/rpc-transport
+-socket_la_LDFLAGS = -module -avoidversion
++socket_la_LDFLAGS = -module -avoidversion -lssl
+ socket_la_SOURCES = socket.c name.c
+ socket_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
+ AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\
+ -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src/ \
+--- rpc/rpc-transport/socket/src/socket.c.orig 2011-12-07 02:20:01.000000000 +0100
++++ rpc/rpc-transport/socket/src/socket.c 2011-12-07 02:19:21.000000000 +0100
+@@ -42,12 +42,36 @@
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <netinet/tcp.h>
+ #include <rpc/xdr.h>
++#include <sys/ioctl.h>
+
+ #define GF_LOG_ERRNO(errno) ((errno == ENOTCONN) ? GF_LOG_DEBUG : GF_LOG_ERROR)
+ #define SA(ptr) ((struct sockaddr *)ptr)
+
++#define SSL_ENABLED_OPT "transport.socket.ssl-enabled"
++#define SSL_OWN_CERT_OPT "transport.socket.ssl-own-cert"
++#define SSL_PRIVATE_KEY_OPT "transport.socket.ssl-private-key"
++#define SSL_CA_LIST_OPT "transport.socket.ssl-ca-list"
++#define OWN_THREAD_OPT "transport.socket.own-thread"
++
++#if !defined(DEFAULT_CERT_PATH)
++#define DEFAULT_CERT_PATH "/etc/ssl/glusterfs.pem"
++#endif
++#if !defined(DEFAULT_KEY_PATH)
++#define DEFAULT_KEY_PATH "/etc/ssl/glusterfs.key"
++#endif
++#if !defined(DEFAULT_CA_PATH)
++#define DEFAULT_CA_PATH "/etc/ssl/glusterfs.ca"
++#endif
++
++#define POLL_MASK_INPUT (POLLIN | POLLPRI)
++#define POLL_MASK_OUTPUT (POLLOUT)
++#define POLL_MASK_ERROR (POLLERR | POLLHUP | POLLNVAL)
++
++typedef int SSL_unary_func (SSL *);
++typedef int SSL_trinary_func (SSL *, void *, int);
++
+
+ #define __socket_proto_reset_pending(priv) do { \
+ memset (&priv->incoming.frag.vector, 0, \
+ sizeof (priv->incoming.frag.vector)); \
+@@ -132,11 +156,143 @@
+ } \
+ __socket_proto_update_priv_after_read (priv, ret, bytes_read); \
+ }
+
+-
+ int socket_init (rpc_transport_t *this);
+
++void
++ssl_dump_error_stack (const char *caller)
++{
++ unsigned long errnum = 0;
++ char errbuf[120] = {0,};
++
++ /* OpenSSL docs explicitly give 120 as the error-string length. */
++
++ while ((errnum = ERR_get_error())) {
++ ERR_error_string(errnum,errbuf);
++ gf_log(caller,GF_LOG_ERROR," %s",errbuf);
++ }
++}
++
++int
++ssl_do (rpc_transport_t *this, void *buf, size_t len, SSL_trinary_func *func)
++{
++ int r = (-1);
++ struct pollfd pfd = {-1,};
++ socket_private_t *priv = NULL;
++
++ GF_VALIDATE_OR_GOTO(this->name,this->private,out);
++ priv = this->private;
++
++ for (;;) {
++ if (buf) {
++ r = func(priv->ssl_ssl,buf,len);
++ }
++ else {
++ r = ((SSL_unary_func *)func)(priv->ssl_ssl);
++ }
++ switch (SSL_get_error(priv->ssl_ssl,r)) {
++ case SSL_ERROR_NONE:
++ return r;
++ case SSL_ERROR_WANT_READ:
++ pfd.fd = priv->sock;
++ pfd.events = POLLIN;
++ if (poll(&pfd,1,-1) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,"poll error %d",
++ errno);
++ }
++ break;
++ case SSL_ERROR_WANT_WRITE:
++ pfd.fd = priv->sock;
++ pfd.events = POLLOUT;
++ if (poll(&pfd,1,-1) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,"poll error %d",
++ errno);
++ }
++ break;
++ case SSL_ERROR_SYSCALL:
++ /* This is what we get when remote disconnects. */
++ gf_log(this->name,GF_LOG_DEBUG,
++ "syscall error (probably remote disconnect)");
++ errno = ENODATA;
++ goto out;
++ default:
++ errno = EIO;
++ goto out; /* "break" would just loop again */
++ }
++ }
++out:
++ return -1;
++}
++
++#define ssl_connect_one(t) ssl_do((t),NULL,0,(SSL_trinary_func *)SSL_connect)
++#define ssl_accept_one(t) ssl_do((t),NULL,0,(SSL_trinary_func *)SSL_accept)
++#define ssl_read_one(t,b,l) ssl_do((t),(b),(l),(SSL_trinary_func *)SSL_read)
++#define ssl_write_one(t,b,l) ssl_do((t),(b),(l),(SSL_trinary_func *)SSL_write)
++
++int
++ssl_setup_connection (rpc_transport_t *this, int server)
++{
++ X509 *peer = NULL;
++ char peer_CN[256] = "";
++ int ret = -1;
++ socket_private_t *priv = NULL;
++
++ GF_VALIDATE_OR_GOTO(this->name,this->private,done);
++ priv = this->private;
++
++ priv->ssl_ssl = SSL_new(priv->ssl_ctx);
++ if (!priv->ssl_ssl) {
++ gf_log(this->name,GF_LOG_ERROR,"SSL_new failed");
++ ssl_dump_error_stack(this->name);
++ goto done;
++ }
++ priv->ssl_sbio = BIO_new_socket(priv->sock,BIO_NOCLOSE);
++ if (!priv->ssl_sbio) {
++ gf_log(this->name,GF_LOG_ERROR,"BIO_new_socket failed");
++ ssl_dump_error_stack(this->name);
++ goto free_ssl;
++ }
++ SSL_set_bio(priv->ssl_ssl,priv->ssl_sbio,priv->ssl_sbio);
++
++ if (server) {
++ ret = ssl_accept_one(this);
++ }
++ else {
++ ret = ssl_connect_one(this);
++ }
++
++ /* Make sure _the call_ succeeded. */
++ if (ret < 0) {
++ goto ssl_error;
++ }
++
++ /* Make sure _SSL verification_ succeeded, yielding an identity. */
++ if (SSL_get_verify_result(priv->ssl_ssl) != X509_V_OK) {
++ goto ssl_error;
++ }
++ peer = SSL_get_peer_certificate(priv->ssl_ssl);
++ if (!peer) {
++ goto ssl_error;
++ }
++
++ /* Finally, everything seems OK. */
++ X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
++ NID_commonName, peer_CN, sizeof(peer_CN)-1);
++ peer_CN[sizeof(peer_CN)-1] = '\0';
++ gf_log(this->name,GF_LOG_INFO,"peer CN = %s", peer_CN);
++ return 0;
++
++ /* Error paths. */
++ssl_error:
++ gf_log(this->name,GF_LOG_ERROR,"SSL connect error");
++ ssl_dump_error_stack(this->name);
++free_ssl:
++ SSL_free(priv->ssl_ssl);
++done:
++ return ret;
++}
++
+ /*
+ * return value:
+ * 0 = success (completed)
+ * -1 = error
+@@ -167,19 +323,43 @@
+ if (bytes != NULL) {
+ *bytes = 0;
+ }
+
+- while (opcount) {
++ while (opcount > 0) {
++ if (opvector->iov_len == 0) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "would have passed zero length to read/write");
++ ++opvector;
++ --opcount;
++ break;
++ }
+ if (write) {
+- ret = writev (sock, opvector, opcount);
++ if (priv->use_ssl) {
++ ret = ssl_write_one(this,
++ opvector->iov_base, opvector->iov_len);
++ }
++ else {
++ ret = writev (sock, opvector, opcount);
++ }
+
+ if (ret == 0 || (ret == -1 && errno == EAGAIN)) {
+ /* done for now */
+ break;
+ }
+ this->total_bytes_write += ret;
+ } else {
+- ret = readv (sock, opvector, opcount);
++ if (priv->use_ssl) {
++ ret = ssl_read_one(this,
++ opvector->iov_base, opvector->iov_len);
++ }
++ else {
++ ret = readv (sock, opvector, opcount);
++ }
++ if (ret == 0) {
++ gf_log(this->name,GF_LOG_DEBUG,"EOF on socket");
++ errno = ENODATA;
++ ret = -1;
++ }
+ if (ret == -1 && errno == EAGAIN) {
+ /* done for now */
+ break;
+ }
+@@ -201,8 +381,11 @@
+
+ gf_log (this->name, GF_LOG_WARNING,
+ "%s failed (%s)", write ? "writev" : "readv",
+ strerror (errno));
++ if (priv->use_ssl) {
++ ssl_dump_error_stack(this->name);
++ }
+ opcount = -1;
+ break;
+ }
+
+@@ -212,8 +395,19 @@
+
+ moved = 0;
+
+ while (moved < ret) {
++ if (!opcount) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "ran out of iov, moved %d/%d",
++ moved, ret);
++ goto ran_out;
++ }
++ if (!opvector[0].iov_len) {
++ opvector++;
++ opcount--;
++ continue;
++ }
+ if ((ret - moved) >= opvector[0].iov_len) {
+ moved += opvector[0].iov_len;
+ opvector++;
+ opcount--;
+@@ -221,15 +415,13 @@
+ opvector[0].iov_len -= (ret - moved);
+ opvector[0].iov_base += (ret - moved);
+ moved += (ret - moved);
+ }
+- while (opcount && !opvector[0].iov_len) {
+- opvector++;
+- opcount--;
+- }
+ }
+ }
+
++ran_out:
++
+ if (pending_vector)
+ *pending_vector = opvector;
+
+ if (pending_count)
+@@ -287,8 +479,22 @@
+ gf_log (this->name, GF_LOG_DEBUG,
+ "shutdown() returned %d. %s",
+ ret, strerror (errno));
+ }
++ if (priv->use_ssl) {
++ SSL_shutdown(priv->ssl_ssl);
++ SSL_clear(priv->ssl_ssl);
++ SSL_free(priv->ssl_ssl);
++ }
++ if (priv->own_thread) {
++ /*
++ * Without this, reconnect (= disconnect + connect)
++ * won't work except by accident.
++ */
++ close(priv->sock);
++ priv->sock = -1;
++ ++(priv->socket_gen);
++ }
+ }
+
+ out:
+ return ret;
+@@ -364,9 +570,8 @@
+
+ return ret;
+ }
+
+-
+ int
+ __socket_nodelay (int fd)
+ {
+ int on = 1;
+@@ -620,11 +825,13 @@
+ }
+
+
+ int
+-__socket_ioq_churn_entry (rpc_transport_t *this, struct ioq *entry)
++__socket_ioq_churn_entry (rpc_transport_t *this, struct ioq *entry, int direct)
+ {
+- int ret = -1;
++ int ret = -1;
++ socket_private_t *priv = NULL;
++ char a_byte = 0;
+
+ ret = __socket_writev (this, entry->pending_vector,
+ entry->pending_count,
+ &entry->pending_vector,
+@@ -633,8 +840,20 @@
+ if (ret == 0) {
+ /* current entry was completely written */
+ GF_ASSERT (entry->pending_count == 0);
+ __socket_ioq_entry_free (entry);
++ priv = this->private;
++ if (priv->own_thread) {
++ /*
++ * The pipe should only remain readable if there are
++ * more entries after this, so drain the byte
++ * representing this entry.
++ */
++ if (!direct && read(priv->pipe[0],&a_byte,1) < 1) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "read error on pipe");
++ }
++ }
+ }
+
+ return ret;
+ }
+@@ -655,15 +874,15 @@
+ while (!list_empty (&priv->ioq)) {
+ /* pick next entry */
+ entry = priv->ioq_next;
+
+- ret = __socket_ioq_churn_entry (this, entry);
++ ret = __socket_ioq_churn_entry (this, entry, 0);
+
+ if (ret != 0)
+ break;
+ }
+
+- if (list_empty (&priv->ioq)) {
++ if (!priv->own_thread && list_empty (&priv->ioq)) {
+ /* all pending writes done, not interested in POLLOUT */
+ priv->idx = event_select_on (this->ctx->event_pool,
+ priv->sock, priv->idx, -1, 0);
+ }
+@@ -1645,9 +1864,8 @@
+
+ if (pollin != NULL) {
+ ret = rpc_transport_notify (this, RPC_TRANSPORT_MSG_RECEIVED,
+ pollin);
+-
+ rpc_transport_pollin_destroy (pollin);
+ }
+
+ return ret;
+@@ -1730,11 +1948,11 @@
+ int
+ socket_event_handler (int fd, int idx, void *data,
+ int poll_in, int poll_out, int poll_err)
+ {
+- rpc_transport_t *this = NULL;
++ rpc_transport_t *this = NULL;
+ socket_private_t *priv = NULL;
+- int ret = 0;
++ int ret = -1;
+
+ this = data;
+ GF_VALIDATE_OR_GOTO ("socket", this, out);
+ GF_VALIDATE_OR_GOTO ("socket", this->private, out);
+@@ -1742,18 +1960,15 @@
+
+ THIS = this->xl;
+ priv = this->private;
+
+-
+ pthread_mutex_lock (&priv->lock);
+ {
+ priv->idx = idx;
+ }
+ pthread_mutex_unlock (&priv->lock);
+
+- if (!priv->connected) {
+- ret = socket_connect_finish (this);
+- }
++ ret = priv->connected ? 0 : socket_connect_finish(this);
+
+ if (!ret && poll_out) {
+ ret = socket_event_poll_out (this);
+ }
+@@ -1767,15 +1982,114 @@
+ gf_log ("transport", ((ret >= 0) ? GF_LOG_INFO : GF_LOG_DEBUG),
+ "disconnecting now");
+ socket_event_poll_err (this);
+ rpc_transport_unref (this);
+- }
++ }
+
+ out:
+- return 0;
++ return ret;
++}
++
++
++void *
++socket_poller (void *ctx)
++{
++ rpc_transport_t *this = ctx;
++ socket_private_t *priv = this->private;
++ struct pollfd pfd[2] = {{0,},};
++ gf_boolean_t to_write = _gf_false;
++ int ret = 0;
++ int orig_gen;
++
++ orig_gen = ++(priv->socket_gen);
++
++ if (!priv->connected) {
++ THIS = this->xl;
++ ret = socket_connect_finish (this);
++ }
++
++ for (;;) {
++ if (priv->socket_gen != orig_gen) {
++ gf_log(this->name,GF_LOG_DEBUG,
++ "redundant poller exiting");
++ return NULL;
++ }
++ pthread_mutex_lock(&priv->lock);
++ to_write = !list_empty(&priv->ioq);
++ pthread_mutex_unlock(&priv->lock);
++ pfd[0].fd = priv->pipe[0];
++ pfd[0].events = POLL_MASK_ERROR;
++ pfd[0].revents = 0;
++ pfd[1].fd = priv->sock;
++ pfd[1].events = POLL_MASK_INPUT | POLL_MASK_ERROR;
++ pfd[1].revents = 0;
++ if (to_write) {
++ pfd[1].events |= POLL_MASK_OUTPUT;
++ }
++ else {
++ pfd[0].events |= POLL_MASK_INPUT;
++ }
++ if (poll(pfd,2,-1) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,"poll failed");
++ break;
++ }
++ if (pfd[0].revents & POLL_MASK_ERROR) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "poll error on pipe");
++ break;
++ }
++ /* Only glusterd actually seems to need this. */
++ THIS = this->xl;
++ if (pfd[1].revents & POLL_MASK_INPUT) {
++ ret = socket_event_poll_in(this);
++ if (ret >= 0) {
++ /* Suppress errors while making progress. */
++ pfd[1].revents &= ~POLL_MASK_ERROR;
++ }
++ else if (errno == ENOTCONN) {
++ ret = 0;
++ }
++ }
++ else if (pfd[1].revents & POLL_MASK_OUTPUT) {
++ ret = socket_event_poll_out(this);
++ if (ret >= 0) {
++ /* Suppress errors while making progress. */
++ pfd[1].revents &= ~POLL_MASK_ERROR;
++ }
++ else if (errno == ENOTCONN) {
++ ret = 0;
++ }
++ }
++ else {
++ /*
++ * This usually means that we left poll() because
++ * somebody pushed a byte onto our pipe. That wakeup
++ * is why the pipe is there, but once awake we can do
++ * all the checking we need on the next iteration.
++ */
++ ret = 0;
++ }
++ if (pfd[1].revents & POLL_MASK_ERROR) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "poll error on socket");
++ break;
++ }
++ if (ret < 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "error in polling loop");
++ break;
++ }
++ }
++
++ /* All (and only) I/O errors should come here. */
++ __socket_disconnect (this);
++ rpc_transport_notify (this, RPC_TRANSPORT_DISCONNECT, this);
++ rpc_transport_unref (this);
++ return NULL;
+ }
+
+
++
+ int
+ socket_server_event_handler (int fd, int idx, void *data,
+ int poll_in, int poll_out, int poll_err)
+ {
+@@ -1812,21 +2126,8 @@
+ priv->sock, strerror (errno));
+ goto unlock;
+ }
+
+- if (!priv->bio) {
+- ret = __socket_nonblock (new_sock);
+-
+- if (ret == -1) {
+- gf_log (this->name, GF_LOG_WARNING,
+- "NBIO on %d failed (%s)",
+- new_sock, strerror (errno));
+-
+- close (new_sock);
+- goto unlock;
+- }
+- }
+-
+ if (priv->nodelay) {
+ ret = __socket_nodelay (new_sock);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_WARNING,
+@@ -1871,9 +2172,13 @@
+ goto unlock;
+ }
+
+ get_transport_identifiers (new_trans);
+- socket_init (new_trans);
++ ret = socket_init (new_trans);
++ if (ret != 0) {
++ close(new_sock);
++ goto unlock;
++ }
+ new_trans->ops = this->ops;
+ new_trans->init = this->init;
+ new_trans->fini = this->fini;
+ new_trans->ctx = ctx;
+@@ -1882,22 +2187,63 @@
+ new_trans->notify = this->notify;
+ new_trans->listener = this;
+ new_priv = new_trans->private;
+
++ new_priv->use_ssl = priv->use_ssl;
++ new_priv->sock = new_sock;
++ new_priv->own_thread = priv->own_thread;
++
++ if (priv->use_ssl) {
++ new_priv->ssl_ctx = priv->ssl_ctx;
++ if (ssl_setup_connection(new_trans,1) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "server setup failed");
++ close(new_sock);
++ goto unlock;
++ }
++ }
++
++ if (!priv->bio) {
++ ret = __socket_nonblock (new_sock);
++
++ if (ret == -1) {
++ gf_log (this->name, GF_LOG_WARNING,
++ "NBIO on %d failed (%s)",
++ new_sock, strerror (errno));
++
++ close (new_sock);
++ goto unlock;
++ }
++ }
++
+ pthread_mutex_lock (&new_priv->lock);
+ {
+- new_priv->sock = new_sock;
+ new_priv->connected = 1;
+ rpc_transport_ref (new_trans);
+
+- new_priv->idx =
+- event_register (ctx->event_pool,
+- new_sock,
+- socket_event_handler,
+- new_trans, 1, 0);
++ if (new_priv->own_thread) {
++ if (pipe(new_priv->pipe) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not create pipe");
++ }
++ if (pthread_create(&new_priv->thread,
++ NULL, socket_poller,
++ new_trans) != 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not create poll thread");
++ }
++ }
++ else {
++ new_priv->idx =
++ event_register (ctx->event_pool,
++ new_sock,
++ socket_event_handler,
++ new_trans,
++ 1, 0);
++ if (new_priv->idx == -1)
++ ret = -1;
++ }
+
+- if (new_priv->idx == -1)
+- ret = -1;
+ }
+ pthread_mutex_unlock (&new_priv->lock);
+ if (ret == -1) {
+ gf_log ("", GF_LOG_WARNING,
+@@ -1984,8 +2330,24 @@
+
+ if (port > 0)
+ ((struct sockaddr_in *) (&sockaddr))->sin_port = htons (port);
+
++ if (ntohs(((struct sockaddr_in *) (&sockaddr))->sin_port) ==
++ GF_DEFAULT_SOCKET_LISTEN_PORT) {
++ if (priv->use_ssl) {
++ gf_log(this->name,GF_LOG_DEBUG,
++ "disabling SSL for portmapper connection");
++ priv->use_ssl = _gf_false;
++ }
++ }
++ else {
++ if (priv->ssl_enabled && !priv->use_ssl) {
++ gf_log(this->name,GF_LOG_DEBUG,
++ "re-enabling SSL for I/O connection");
++ priv->use_ssl = _gf_true;
++ }
++ }
++
+ pthread_mutex_lock (&priv->lock);
+ {
+ if (priv->sock != -1) {
+ gf_log (this->name, GF_LOG_TRACE,
+@@ -2034,21 +2396,8 @@
+ strerror (errno));
+ }
+ }
+
+- if (!priv->bio) {
+- ret = __socket_nonblock (priv->sock);
+-
+- if (ret == -1) {
+- gf_log (this->name, GF_LOG_ERROR,
+- "NBIO on %d failed (%s)",
+- priv->sock, strerror (errno));
+- close (priv->sock);
+- priv->sock = -1;
+- goto unlock;
+- }
+- }
+-
+ if (priv->keepalive) {
+ ret = __socket_keepalive (priv->sock,
+ priv->keepaliveintvl,
+ priv->keepaliveidle);
+@@ -2082,19 +2431,58 @@
+ priv->sock = -1;
+ goto unlock;
+ }
+
+- priv->connected = 0;
+-
+- rpc_transport_ref (this);
++ if (priv->use_ssl) {
++ ret = ssl_setup_connection(this,0);
++ if (ret < 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "client setup failed");
++ close(priv->sock);
++ priv->sock = -1;
++ goto unlock;
++ }
++ }
++
++ if (!priv->bio) {
++ ret = __socket_nonblock (priv->sock);
++
++ if (ret == -1) {
++ gf_log (this->name, GF_LOG_ERROR,
++ "NBIO on %d failed (%s)",
++ priv->sock, strerror (errno));
++ close (priv->sock);
++ priv->sock = -1;
++ goto unlock;
++ }
++ }
++
++ priv->connected = 0;
++ rpc_transport_ref (this);
++
++ if (priv->own_thread) {
++ if (pipe(priv->pipe) < 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not create pipe");
++ }
++
++ if (pthread_create(&priv->thread,NULL,
++ socket_poller, this) != 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not create poll thread");
++ }
++ }
++ else {
++ priv->idx = event_register (ctx->event_pool, priv->sock,
++ socket_event_handler,
++ this, 1, 1);
++ if (priv->idx == -1) {
++ gf_log ("", GF_LOG_WARNING,
++ "failed to register the event");
++ ret = -1;
++ }
++ }
+
+- priv->idx = event_register (ctx->event_pool, priv->sock,
+- socket_event_handler, this, 1, 1);
+- if (priv->idx == -1) {
+- gf_log ("", GF_LOG_WARNING,
+- "failed to register the event");
+- ret = -1;
+- }
+ }
+ unlock:
+ pthread_mutex_unlock (&priv->lock);
+
+@@ -2258,8 +2646,9 @@
+ char need_poll_out = 0;
+ char need_append = 1;
+ struct ioq *entry = NULL;
+ glusterfs_ctx_t *ctx = NULL;
++ char a_byte = 'j';
+
+ GF_VALIDATE_OR_GOTO ("socket", this, out);
+ GF_VALIDATE_OR_GOTO ("socket", this->private, out);
+
+@@ -2283,23 +2672,33 @@
+ if (!entry)
+ goto unlock;
+
+ if (list_empty (&priv->ioq)) {
+- ret = __socket_ioq_churn_entry (this, entry);
++ ret = __socket_ioq_churn_entry (this, entry, 1);
+
+- if (ret == 0)
++ if (ret == 0) {
+ need_append = 0;
+-
+- if (ret > 0)
++ }
++ if (ret > 0) {
+ need_poll_out = 1;
++ }
+ }
+
+ if (need_append) {
+ list_add_tail (&entry->list, &priv->ioq);
++ if (priv->own_thread) {
++ /*
++ * Make sure the polling thread wakes up, by
++ * writing a byte to represent this entry.
++ */
++ if (write(priv->pipe[1],&a_byte,1) < 1) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "write error on pipe");
++ }
++ }
+ ret = 0;
+ }
+-
+- if (need_poll_out) {
++ if (!priv->own_thread && need_poll_out) {
+ /* first entry to wait. continue writing on POLLOUT */
+ priv->idx = event_select_on (ctx->event_pool,
+ priv->sock,
+ priv->idx, -1, 1);
+@@ -2321,8 +2720,9 @@
+ char need_poll_out = 0;
+ char need_append = 1;
+ struct ioq *entry = NULL;
+ glusterfs_ctx_t *ctx = NULL;
++ char a_byte = 'd';
+
+ GF_VALIDATE_OR_GOTO ("socket", this, out);
+ GF_VALIDATE_OR_GOTO ("socket", this->private, out);
+
+@@ -2339,35 +2739,46 @@
+ priv->submit_log = 1;
+ }
+ goto unlock;
+ }
++
+ priv->submit_log = 0;
+ entry = __socket_ioq_new (this, &reply->msg);
+ if (!entry)
+ goto unlock;
++
+ if (list_empty (&priv->ioq)) {
+- ret = __socket_ioq_churn_entry (this, entry);
++ ret = __socket_ioq_churn_entry (this, entry, 1);
+
+- if (ret == 0)
++ if (ret == 0) {
+ need_append = 0;
+-
+- if (ret > 0)
++ }
++ if (ret > 0) {
+ need_poll_out = 1;
++ }
+ }
+
+ if (need_append) {
+ list_add_tail (&entry->list, &priv->ioq);
++ if (priv->own_thread) {
++ /*
++ * Make sure the polling thread wakes up, by
++ * writing a byte to represent this entry.
++ */
++ if (write(priv->pipe[1],&a_byte,1) < 1) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "write error on pipe");
++ }
++ }
+ ret = 0;
+ }
+-
+- if (need_poll_out) {
++ if (!priv->own_thread && need_poll_out) {
+ /* first entry to wait. continue writing on POLLOUT */
+ priv->idx = event_select_on (ctx->event_pool,
+ priv->sock,
+ priv->idx, -1, 1);
+ }
+ }
+-
+ unlock:
+ pthread_mutex_unlock (&priv->lock);
+
+ out:
+@@ -2513,8 +2924,9 @@
+ uint64_t windowsize = GF_DEFAULT_SOCKET_WINDOW_SIZE;
+ char *optstr = NULL;
+ uint32_t keepalive = 0;
+ uint32_t backlog = 0;
++ int session_id = 0;
+
+ if (this->private) {
+ gf_log_callingfn (this->name, GF_LOG_ERROR,
+ "double init attempted");
+@@ -2627,12 +3039,131 @@
+ priv->backlog = backlog;
+ }
+
+ priv->windowsize = (int)windowsize;
++
++ priv->ssl_enabled = _gf_false;
++ if (dict_get_str(this->options,SSL_ENABLED_OPT,&optstr) == 0) {
++ if (gf_string2boolean (optstr, &priv->ssl_enabled) != 0) {
++ gf_log (this->name, GF_LOG_ERROR,
++ "invalid value given for ssl-enabled boolean");
++ }
++ }
++
++ priv->ssl_own_cert = DEFAULT_CERT_PATH;
++ if (dict_get_str(this->options,SSL_OWN_CERT_OPT,&optstr) == 0) {
++ if (!priv->ssl_enabled) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "%s specified without %s (ignored)",
++ SSL_OWN_CERT_OPT, SSL_ENABLED_OPT);
++ }
++ priv->ssl_own_cert = optstr;
++ }
++ priv->ssl_own_cert = gf_strdup(priv->ssl_own_cert);
++
++ priv->ssl_private_key = DEFAULT_KEY_PATH;
++ if (dict_get_str(this->options,SSL_PRIVATE_KEY_OPT,&optstr) == 0) {
++ if (!priv->ssl_enabled) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "%s specified without %s (ignored)",
++ SSL_PRIVATE_KEY_OPT, SSL_ENABLED_OPT);
++ }
++ priv->ssl_private_key = optstr;
++ }
++ priv->ssl_private_key = gf_strdup(priv->ssl_private_key);
++
++ priv->ssl_ca_list = DEFAULT_CA_PATH;
++ if (dict_get_str(this->options,SSL_CA_LIST_OPT,&optstr) == 0) {
++ if (!priv->ssl_enabled) {
++ gf_log(this->name,GF_LOG_WARNING,
++ "%s specified without %s (ignored)",
++ SSL_CA_LIST_OPT, SSL_ENABLED_OPT);
++ }
++ priv->ssl_ca_list = optstr;
++ }
++ priv->ssl_ca_list = gf_strdup(priv->ssl_ca_list);
++
++ gf_log(this->name,GF_LOG_INFO,"SSL support is %s",
++ priv->ssl_enabled ? "ENABLED" : "NOT enabled");
++ /*
++ * This might get overridden temporarily in socket_connect (q.v.)
++ * if we're using the glusterd portmapper.
++ */
++ priv->use_ssl = priv->ssl_enabled;
++
++ priv->own_thread = priv->use_ssl;
++ if (dict_get_str(this->options,OWN_THREAD_OPT,&optstr) == 0) {
++ if (gf_string2boolean (optstr, &priv->own_thread) != 0) {
++ gf_log (this->name, GF_LOG_ERROR,
++ "invalid value given for own-thread boolean");
++ }
++ }
++ gf_log(this->name,GF_LOG_INFO,"using %s polling thread",
++ priv->own_thread ? "private" : "system");
++
++ if (priv->use_ssl) {
++ SSL_library_init();
++ SSL_load_error_strings();
++ priv->ssl_meth = (SSL_METHOD *)TLSv1_method();
++ priv->ssl_ctx = SSL_CTX_new(priv->ssl_meth);
++
++ if (SSL_CTX_set_cipher_list(priv->ssl_ctx,
++ "HIGH:-SSLv2") == 0) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "failed to find any valid ciphers");
++ goto err;
++ }
++
++ if (!SSL_CTX_use_certificate_chain_file(priv->ssl_ctx,
++ priv->ssl_own_cert)) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not load our cert");
++ goto err;
++ }
++
++ if (!SSL_CTX_use_PrivateKey_file(priv->ssl_ctx,
++ priv->ssl_private_key,
++ SSL_FILETYPE_PEM)) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not load private key");
++ goto err;
++ }
++
++ if (!SSL_CTX_load_verify_locations(priv->ssl_ctx,
++ priv->ssl_ca_list,0)) {
++ gf_log(this->name,GF_LOG_ERROR,
++ "could not load CA list");
++ goto err;
++ }
++
++#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
++ SSL_CTX_set_verify_depth(ctx,1);
++#endif
++
++ priv->ssl_session_id = ++session_id;
++ SSL_CTX_set_session_id_context(priv->ssl_ctx,
++ (void *)&priv->ssl_session_id,
++ sizeof(priv->ssl_session_id));
++
++ SSL_CTX_set_verify(priv->ssl_ctx,SSL_VERIFY_PEER,0);
++ }
++
+ out:
+ this->private = priv;
+-
+ return 0;
++
++err:
++ if (priv->ssl_own_cert) {
++ GF_FREE(priv->ssl_own_cert);
++ }
++ if (priv->ssl_private_key) {
++ GF_FREE(priv->ssl_private_key);
++ }
++ if (priv->ssl_ca_list) {
++ GF_FREE(priv->ssl_ca_list);
++ }
++ GF_FREE(priv);
++ return -1;
+ }
+
+
+ void
+@@ -2656,8 +3187,17 @@
+ gf_log (this->name, GF_LOG_TRACE,
+ "transport %p destroyed", this);
+
+ pthread_mutex_destroy (&priv->lock);
++ if (priv->ssl_private_key) {
++ GF_FREE(priv->ssl_private_key);
++ }
++ if (priv->ssl_own_cert) {
++ GF_FREE(priv->ssl_own_cert);
++ }
++ if (priv->ssl_ca_list) {
++ GF_FREE(priv->ssl_ca_list);
++ }
+ GF_FREE (priv);
+ }
+
+ this->private = NULL;
+@@ -2731,6 +3271,18 @@
+ },
+ { .key = {"transport.socket.listen-backlog"},
+ .type = GF_OPTION_TYPE_INT
+ },
++ { .key = {SSL_OWN_CERT_OPT},
++ .type = GF_OPTION_TYPE_STR
++ },
++ { .key = {SSL_PRIVATE_KEY_OPT},
++ .type = GF_OPTION_TYPE_STR
++ },
++ { .key = {SSL_CA_LIST_OPT},
++ .type = GF_OPTION_TYPE_STR
++ },
++ { .key = {OWN_THREAD_OPT},
++ .type = GF_OPTION_TYPE_BOOL
++ },
+ { .key = {NULL} }
+ };
+--- rpc/rpc-transport/socket/src/socket.h.orig 2011-11-14 14:46:00.000000000 +0100
++++ rpc/rpc-transport/socket/src/socket.h 2011-12-03 06:46:39.000000000 +0100
+@@ -19,8 +19,10 @@
+
+ #ifndef _SOCKET_H
+ #define _SOCKET_H
+
++#include <openssl/ssl.h>
++#include <openssl/err.h>
+
+ #ifndef _CONFIG_H
+ #define _CONFIG_H
+ #include "config.h"
+@@ -192,8 +194,22 @@
+ int keepalive;
+ int keepaliveidle;
+ int keepaliveintvl;
+ uint32_t backlog;
++ gf_boolean_t ssl_enabled;
++ gf_boolean_t use_ssl;
++ SSL_METHOD *ssl_meth;
++ SSL_CTX *ssl_ctx;
++ int ssl_session_id;
++ BIO *ssl_sbio;
++ SSL *ssl_ssl;
++ char *ssl_own_cert;
++ char *ssl_private_key;
++ char *ssl_ca_list;
++ pthread_t thread;
++ int pipe[2];
++ gf_boolean_t own_thread;
++ volatile int socket_gen;
+ } socket_private_t;
+
+
+ #endif
+--- xlators/mgmt/glusterd/src/glusterd-volgen.c.orig 2011-11-14 14:46:02.000000000 +0100
++++ xlators/mgmt/glusterd/src/glusterd-volgen.c 2011-12-03 06:46:39.000000000 +0100
+@@ -187,8 +187,12 @@
+
+ {VKEY_FEATURES_QUOTA, "features/marker", "quota", "off", NO_DOC, OPT_FLAG_FORCE},
+ {VKEY_FEATURES_LIMIT_USAGE, "features/quota", "limit-set", NULL, NO_DOC, 0},
+ {"features.quota-timeout", "features/quota", "timeout", "0", DOC, 0},
++ { "server.ssl", "protocol/server",
++"transport.socket.ssl-enabled", NULL, NO_DOC, 0},
++ { "client.ssl", "protocol/client",
++"transport.socket.ssl-enabled", NULL, NO_DOC, 0},
+ {NULL, }
+ };
+
+