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