FW: Memcached and local/unix domain sockets

Nathan Neulinger nneul at umr.edu
Wed Jul 26 23:23:26 UTC 2006


Here's an updated patch against the current SVN trunk.

Is the development of the perl client available via svn or cvs anywhere?

-- Nathan

On Wed, Jul 26, 2006 at 12:34:02PM -0500, Neulinger, Nathan wrote:
> 
> FYI in case anyone is interested. I sent the author a couple of simple
> patches to add unix domain socket support. This would allow secure
> local-server installation of memcached on multi-user servers. Patch
> included for perl client and the memcached daemon itself, others should
> be similarly easy to implement.
> 
> -- Nathan
> 
> ------------------------------------------------------------
> Nathan Neulinger                       EMail:  nneul at umr.edu
> University of Missouri - Rolla         Phone: (573) 341-6679
> UMR Information Technology             Fax: (573) 341-4216
>  
> 
> > -----Original Message-----
> > From: Neulinger, Nathan 
> > Sent: Wednesday, July 26, 2006 12:31 PM
> > To: 'brad at danga.com'
> > Subject: RE: Memcached and local/unix domain sockets
> > 
> > Here's the patches to the perl client and memcached.
> > 
> > -- Nathan
> >  
> > ------------------------------------------------------------
> > Nathan Neulinger                       EMail:  nneul at umr.edu
> > University of Missouri - Rolla         Phone: (573) 341-6679
> > UMR Information Technology             Fax: (573) 341-4216
> >  
> > 
> > > -----Original Message-----
> > > From: Neulinger, Nathan 
> > > Sent: Wednesday, July 26, 2006 11:36 AM
> > > To: 'brad at danga.com'
> > > Subject: RE: Memcached and local/unix domain sockets
> > > 
> > > Alternatively, would you be willing to integrate a patch to 
> > > add this support? From a quick look at the code, looks like 
> > > it would be relatively trivial to code.
> > > 
> > > -- Nathan
> > >  
> > > ------------------------------------------------------------
> > > Nathan Neulinger                       EMail:  nneul at umr.edu
> > > University of Missouri - Rolla         Phone: (573) 341-6679
> > > UMR Information Technology             Fax: (573) 341-4216
> > >  
> > > 
> > > > -----Original Message-----
> > > > From: Neulinger, Nathan 
> > > > Sent: Wednesday, July 26, 2006 11:11 AM
> > > > To: 'brad at danga.com'
> > > > Subject: Memcached and local/unix domain sockets
> > > > 
> > > > Are you aware of any patches or enhancements to memcached to 
> > > > allow it to use a unix domain socket instead of a IP socket? 
> > > > This feature would allow for secure deployments of memcached 
> > > > on machines with more than one userid.
> > > > 
> > > > -- Nathan
> > > >  
> > > > ------------------------------------------------------------
> > > > Nathan Neulinger                       EMail:  nneul at umr.edu
> > > > University of Missouri - Rolla         Phone: (573) 341-6679
> > > > UMR Information Technology             Fax: (573) 341-4216
> > > > 

Content-Description: cache-memcached-unix-socket.diff
> Only in Cache-Memcached-1.14: blib
> Only in Cache-Memcached-1.14: Makefile
> diff -ur Cache-Memcached-1.14-orig/Memcached.pm Cache-Memcached-1.14/Memcached.pm
> --- Cache-Memcached-1.14-orig/Memcached.pm	2004-07-27 12:07:04.000000000 -0500
> +++ Cache-Memcached-1.14/Memcached.pm	2006-07-26 12:27:50.000000000 -0500
> @@ -10,7 +10,7 @@
>  use strict;
>  no strict 'refs';
>  use Storable ();
> -use Socket qw( MSG_NOSIGNAL PF_INET IPPROTO_TCP SOCK_STREAM );
> +use Socket qw( MSG_NOSIGNAL PF_INET PF_UNIX IPPROTO_TCP SOCK_STREAM );
>  use IO::Handle ();
>  use Time::HiRes ();
>  use String::CRC32;
> @@ -209,22 +209,31 @@
>      my $sin;
>      my $proto = $PROTO_TCP ||= getprotobyname('tcp');
>  
> -    # if a preferred IP is known, try that first.
> -    if ($self && $self->{pref_ip}{$ip}) {
> -        socket($sock, PF_INET, SOCK_STREAM, $proto);
> -        my $prefip = $self->{pref_ip}{$ip};
> -        $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip));
> -        if (_connect_sock($sock,$sin,0.1)) {
> -            $connected = 1;
> -        } else {
> -            close $sock;
> +    # check if unix or inet socket and handle accordingly
> +    if ( $host !~ m{^/} ) {
> +        # if a preferred IP is known, try that first.
> +        if ($self && $self->{pref_ip}{$ip}) {
> +            socket($sock, PF_INET, SOCK_STREAM, $proto);
> +            my $prefip = $self->{pref_ip}{$ip};
> +            $sin = Socket::sockaddr_in($port,Socket::inet_aton($prefip));
> +            if (_connect_sock($sock,$sin,0.1)) {
> +                $connected = 1;
> +            } else {
> +                close $sock;
> +            }
>          }
> -    }
>  
> -    # normal path, or fallback path if preferred IP failed
> -    unless ($connected) {
> -        socket($sock, PF_INET, SOCK_STREAM, $proto);
> -        $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip));
> +        # normal path, or fallback path if preferred IP failed
> +        unless ($connected) {
> +            socket($sock, PF_INET, SOCK_STREAM, $proto);
> +            $sin = Socket::sockaddr_in($port,Socket::inet_aton($ip));
> +            unless (_connect_sock($sock,$sin)) {
> +                return _dead_sock($sock, undef, 20 + int(rand(10)));
> +            }
> +        }
> +    } else { # it's a unix domain/local socket
> +        socket($sock, PF_UNIX, SOCK_STREAM, 0);
> +        $sin = Socket::sockaddr_un($host);
>          unless (_connect_sock($sock,$sin)) {
>              return _dead_sock($sock, undef, 20 + int(rand(10)));
>          }
> @@ -900,7 +909,7 @@
>    use Cache::Memcached;
>  
>    $memd = new Cache::Memcached {
> -    'servers' => [ "10.0.0.15:11211", "10.0.0.15:11212",
> +    'servers' => [ "10.0.0.15:11211", "10.0.0.15:11212", "/var/sock/memcached",
>                     "10.0.0.17:11211", [ "10.0.0.17:11211", 3 ] ],
>      'debug' => 0,
>      'compress_threshold' => 10_000,
> Only in Cache-Memcached-1.14: pm_to_blib

Content-Description: memcached-unix-socket.diff
> diff -ur memcached-1.1.12-orig/memcached.c memcached-1.1.12/memcached.c
> --- memcached-1.1.12-orig/memcached.c	2005-04-04 19:10:26.000000000 -0500
> +++ memcached-1.1.12/memcached.c	2006-07-26 12:00:12.000000000 -0500
> @@ -21,6 +21,7 @@
>  #include <sys/stat.h>
>  #include <sys/time.h>
>  #include <sys/socket.h>
> +#include <sys/un.h>
>  #include <sys/signal.h>
>  #include <sys/resource.h>
>  /* some POSIX systems need the following definition
> @@ -93,6 +94,7 @@
>      settings.verbose = 0;
>      settings.oldest_live = 0;
>      settings.evict_to_free = 1;       /* push old items out of cache when memory runs out */
> +    settings.socketpath = NULL;       /* by default, not using a unix socket */
>  }
>  
>  conn **freeconns;
> @@ -1172,6 +1174,64 @@
>      return sfd;
>  }
>  
> +int new_socket_unix(void) {
> +    int sfd;
> +    int flags;
> +
> +    if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
> +        perror("socket()");
> +        return -1;
> +    }
> +
> +    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
> +        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
> +        perror("setting O_NONBLOCK");
> +        close(sfd);
> +        return -1;
> +    }
> +    return sfd;
> +}
> +
> +int server_socket_unix(char *path) {
> +    int sfd;
> +    struct linger ling = {0, 0};
> +    struct sockaddr_un addr;
> +    int flags =1;
> +    
> +    if (!path) {
> +        return -1;
> +    }
> +    
> +    if ((sfd = new_socket_unix()) == -1) {
> +        return -1;
> +    }
> +
> +    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
> +    setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
> +    setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
> +
> +    /* 
> +     * the memset call clears nonstandard fields in some impementations
> +     * that otherwise mess things up.
> +     */
> +    memset(&addr, 0, sizeof(addr));
> +
> +    addr.sun_family = AF_UNIX;
> +    strcpy(addr.sun_path, path);
> +    if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
> +        perror("bind()");
> +        close(sfd);
> +        return -1;
> +    }
> +    if (listen(sfd, 1024) == -1) {
> +        perror("listen()");
> +        close(sfd);
> +        return -1;
> +    }
> +    return sfd;
> +}
> +
> +
>  /* invoke right before gdb is called, on assert */
>  void pre_gdb () {
>      int i = 0;
> @@ -1221,6 +1281,7 @@
>  void usage(void) {
>      printf(PACKAGE " " VERSION "\n");
>      printf("-p <num>      port number to listen on\n");
> +    printf("-s <file>     unix socket path to listen on (disables network support)\n");
>      printf("-l <ip_addr>  interface to listen on, default is INDRR_ANY\n");
>      printf("-d            run as a daemon\n");
>      printf("-r            maximize core file limit\n");
> @@ -1354,11 +1415,14 @@
>      settings_init();
>  
>      /* process arguments */
> -    while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:P:")) != -1) {
> +    while ((c = getopt(argc, argv, "p:s:m:Mc:khirvdl:u:P:")) != -1) {
>          switch (c) {
>          case 'p':
>              settings.port = atoi(optarg);
>              break;
> +        case 's':
> +            settings.socketpath = optarg;
> +            break;
>          case 'm':
>              settings.maxbytes = atoi(optarg)*1024*1024;
>              break;
> @@ -1461,7 +1525,11 @@
>       */
>  
>      /* create the listening socket and bind it */
> -    l_socket = server_socket(settings.port);
> +    if (settings.socketpath) {
> +        l_socket = server_socket_unix(settings.socketpath);	
> +    } else {
> +        l_socket = server_socket(settings.port);
> +    }
>      if (l_socket == -1) {
>          fprintf(stderr, "failed to listen\n");
>          exit(1);
> diff -ur memcached-1.1.12-orig/memcached.h memcached-1.1.12/memcached.h
> --- memcached-1.1.12-orig/memcached.h	2005-04-04 19:14:55.000000000 -0500
> +++ memcached-1.1.12/memcached.h	2006-07-26 11:50:36.000000000 -0500
> @@ -31,6 +31,7 @@
>      int verbose;
>      time_t oldest_live;   /* ignore existing items older than this */
>      int evict_to_free;
> +    char *socketpath;   /* path to unix socket if using local socket */
>  };
>  
>  extern struct stats stats;


------------------------------------------------------------
Nathan Neulinger                       EMail:  nneul at umr.edu
University of Missouri - Rolla         Phone: (573) 341-6679
UMR Information Technology             Fax: (573) 341-4216
-------------- next part --------------
Index: memcached.c
===================================================================
--- memcached.c	(revision 305)
+++ memcached.c	(working copy)
@@ -21,6 +21,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/signal.h>
 #include <sys/resource.h>
 /* some POSIX systems need the following definition
@@ -96,6 +97,7 @@
     settings.oldest_live = 0;
     settings.evict_to_free = 1;       /* push old items out of cache when memory runs out */
     settings.managed = 0;
+    settings.socketpath = NULL;       /* by default, not using a unix socket */
 }
 
 conn **freeconns;
@@ -1352,6 +1354,64 @@
     return sfd;
 }
 
+int new_socket_unix(void) {
+    int sfd;
+    int flags;
+
+    if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+        perror("socket()");
+        return -1;
+    }
+
+    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
+        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
+        perror("setting O_NONBLOCK");
+        close(sfd);
+        return -1;
+    }
+    return sfd;
+}
+
+int server_socket_unix(char *path) {
+    int sfd;
+    struct linger ling = {0, 0};
+    struct sockaddr_un addr;
+    int flags =1;
+    
+    if (!path) {
+        return -1;
+    }
+    
+    if ((sfd = new_socket_unix()) == -1) {
+        return -1;
+    }
+
+    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
+    setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
+    setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
+
+    /* 
+     * the memset call clears nonstandard fields in some impementations
+     * that otherwise mess things up.
+     */
+    memset(&addr, 0, sizeof(addr));
+
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, path);
+    if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+        perror("bind()");
+        close(sfd);
+        return -1;
+    }
+    if (listen(sfd, 1024) == -1) {
+        perror("listen()");
+        close(sfd);
+        return -1;
+    }
+    return sfd;
+}
+
+
 /* invoke right before gdb is called, on assert */
 void pre_gdb () {
     int i = 0;
@@ -1401,6 +1461,7 @@
 void usage(void) {
     printf(PACKAGE " " VERSION "\n");
     printf("-p <num>      port number to listen on\n");
+    printf("-s <file>     unix socket path to listen on (disables network support)\n");
     printf("-l <ip_addr>  interface to listen on, default is INDRR_ANY\n");
     printf("-d            run as a daemon\n");
     printf("-r            maximize core file limit\n");
@@ -1538,7 +1599,7 @@
     setbuf(stderr, NULL);
 
     /* process arguments */
-    while ((c = getopt(argc, argv, "bp:m:Mc:khirvdl:u:P:")) != -1) {
+    while ((c = getopt(argc, argv, "bp:s:m:Mc:khirvdl:u:P:")) != -1) {
         switch (c) {
         case 'b':
             settings.managed = 1;
@@ -1546,6 +1607,9 @@
         case 'p':
             settings.port = atoi(optarg);
             break;
+        case 's':
+            settings.socketpath = optarg;
+            break;
         case 'm':
             settings.maxbytes = atoi(optarg)*1024*1024;
             break;
@@ -1648,7 +1712,11 @@
      */
 
     /* create the listening socket and bind it */
-    l_socket = server_socket(settings.port);
+    if (settings.socketpath) {
+        l_socket = server_socket_unix(settings.socketpath);	
+    } else {
+        l_socket = server_socket(settings.port);
+    }
     if (l_socket == -1) {
         fprintf(stderr, "failed to listen\n");
         exit(1);
Index: memcached.h
===================================================================
--- memcached.h	(revision 305)
+++ memcached.h	(working copy)
@@ -32,6 +32,7 @@
     int managed;          /* if 1, a tracker manages virtual buckets */
     time_t oldest_live;   /* ignore existing items older than this */
     int evict_to_free;
+    char *socketpath;   /* path to unix socket if using local socket */
 };
 
 extern struct stats stats;


More information about the memcached mailing list