Index: memcached.c
===================================================================
--- memcached.c	(revision 572)
+++ memcached.c	(working copy)
@@ -101,6 +101,7 @@
 /** exported globals **/
 struct stats stats;
 struct settings settings;
+bool ipv6=false;
 
 /** file scope variables **/
 static item **todelete = 0;
@@ -167,7 +168,6 @@
 static void settings_init(void) {
     settings.port = 11211;
     settings.udpport = 0;
-    settings.interf.s_addr = htonl(INADDR_ANY);
     settings.maxbytes = 67108864; /* default is 64MB: (64 * 1024 * 1024) */
     settings.maxconns = 1024;         /* to limit connections-related memory to about 5MB */
     settings.verbose = 0;
@@ -1646,9 +1646,17 @@
 
     assert(c != NULL);
 
-    c->request_addr_size = sizeof(c->request_addr);
+if(ipv6) {
+    c->request_addr_size = sizeof(struct in6_addr);
     res = recvfrom(c->sfd, c->rbuf, c->rsize,
-                   0, &c->request_addr, &c->request_addr_size);
+            0, ( struct sockaddr *)&c->request_addr, &c->request_addr_size);
+    }
+    else {
+    c->request_addr_size = sizeof(struct in_addr);
+    res = recvfrom(c->sfd, c->rbuf, c->rsize,
+            0, ( struct sockaddr *)&c->request_addr, &c->request_addr_size);
+    }
+
     if (res > 8) {
         unsigned char *buf = (unsigned char *)c->rbuf;
         STATS_LOCK();
@@ -1713,7 +1721,11 @@
          * is this done for every command?  presumably for UDP
          * mode.  */
         if (!settings.socketpath) {
-            c->request_addr_size = sizeof(c->request_addr);
+          if(ipv6) {
+            c->request_addr_size = sizeof(struct in6_addr);
+            } else {
+            c->request_addr_size = sizeof(struct in_addr);
+            }
         } else {
             c->request_addr_size = 0;
         }
@@ -1846,7 +1858,7 @@
     bool stop = false;
     int sfd, flags = 1;
     socklen_t addrlen;
-    struct sockaddr addr;
+    struct sockaddr_storage addr; 
     int res;
 
     assert(c != NULL);
@@ -1855,8 +1867,16 @@
 
         switch(c->state) {
         case conn_listening:
-            addrlen = sizeof(addr);
-            if ((sfd = accept(c->sfd, &addr, &addrlen)) == -1) {
+        
+        if(ipv6) 
+            {
+            addrlen = sizeof(struct in6_addr);
+            }
+            else {
+            addrlen = sizeof(struct in_addr);
+            }
+            
+        if ((sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)) == -1) {
                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
                     /* these are transient, so don't log anything */
                     stop = true;
@@ -2082,10 +2102,17 @@
     int sfd;
     int flags;
 
-    if ((sfd = socket(AF_INET, is_udp ? SOCK_DGRAM : SOCK_STREAM, 0)) == -1) {
-        perror("socket()");
-        return -1;
-    }
+if(ipv6) {
+      if ((sfd = socket(AF_INET6, is_udp ? SOCK_DGRAM : SOCK_STREAM, 0)) == -1) {
+          perror("socket()");
+          return -1;
+        }
+      } else {
+      if ((sfd = socket(AF_INET, is_udp ? SOCK_DGRAM : SOCK_STREAM, 0)) == -1) {
+          perror("socket()");
+          return -1;
+        }
+      }
 
     if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
         fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
@@ -2131,11 +2158,10 @@
         fprintf(stderr, "<%d send buffer was %d, now %d\n", sfd, old_size, last_good);
 }
 
-
 static int server_socket(const int port, const bool is_udp) {
     int sfd;
     struct linger ling = {0, 0};
-    struct sockaddr_in addr;
+    struct sockaddr_storage addr;
     int flags =1;
 
     if ((sfd = new_socket(is_udp)) == -1) {
@@ -2157,13 +2183,29 @@
      */
     memset(&addr, 0, sizeof(addr));
 
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr = settings.interf;
-    if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
-        perror("bind()");
-        close(sfd);
-        return -1;
+if(ipv6) {
+    struct sockaddr_in6 *addrp=(struct sockaddr_in6 *) &addr;
+
+    addrp->sin6_family = AF_INET6;
+    addrp->sin6_port = htons(port);
+    
+    memcpy(&(addrp->sin6_addr),&(settings.interf),sizeof(struct in6_addr));
+
+    if (bind(sfd, (struct sockaddr *)addrp, sizeof(struct sockaddr_in6)) == -1) {
+          perror("bind()");
+          close(sfd);
+          return -1;
+          }
+    } else {
+    struct sockaddr_in *addrp=(struct sockaddr_in *) &addr;
+    addrp->sin_family = AF_INET;
+    addrp->sin_port = htons(port);
+    memcpy(&(addrp->sin_addr),&(settings.interf),sizeof(struct in_addr));
+      if (bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1) {
+          perror("bind()");
+          close(sfd);
+          return -1;
+          }
     }
     if (!is_udp && listen(sfd, 1024) == -1) {
         perror("listen()");
@@ -2460,7 +2502,7 @@
 
 int main (int argc, char **argv) {
     int c;
-    struct in_addr addr;
+    struct in_any_addr addr;
     bool lock_memory = false;
     bool daemonize = false;
     int maxcore = 0;
@@ -2469,6 +2511,7 @@
     struct passwd *pw;
     struct sigaction sa;
     struct rlimit rlim;
+    char *opt_addr = NULL;
 
     /* handle SIGINT */
     signal(SIGINT, sig_handler);
@@ -2480,7 +2523,7 @@
     setbuf(stderr, NULL);
 
     /* process arguments */
-    while ((c = getopt(argc, argv, "bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:")) != -1) {
+    while ((c = getopt(argc, argv, "bp:s:U:m:Mc:khirvdl:u:P:f:s:n:t:D:6")) != -1) {
         switch (c) {
         case 'U':
             settings.udpport = atoi(optarg);
@@ -2515,13 +2558,10 @@
         case 'v':
             settings.verbose++;
             break;
-        case 'l':
-            if (inet_pton(AF_INET, optarg, &addr) <= 0) {
-                fprintf(stderr, "Illegal address: %s\n", optarg);
-                return 1;
-            } else {
-                settings.interf = addr;
-            }
+        case 'l':          
+            opt_addr=malloc(strlen(optarg)+1);
+            memset(opt_addr,0,strlen(optarg)+1);
+            strcat(opt_addr,optarg);
             break;
         case 'd':
             daemonize = true;
@@ -2564,12 +2604,69 @@
             settings.prefix_delimiter = optarg[0];
             settings.detail_enabled = 1;
             break;
+        case '6':
+            ipv6=true;
+            break;
         default:
             fprintf(stderr, "Illegal argument \"%c\"\n", c);
             return 1;
         }
     }
+    
+    // do default address initialization that was done in settings_init
+    if(ipv6) {
+      memcpy(&settings.interf.s_addr,&in6addr_any,sizeof(struct in6_addr));    
+      } else {
+      struct in_addr *addrp = (struct in_addr *) settings.interf.s_addr;
+      struct in_addr any;
 
+      any.s_addr=htonl(INADDR_ANY);
+      memcpy(addrp,&any,sizeof(struct in_addr));
+      }
+
+
+    if(opt_addr) {
+      if(ipv6) {
+        if (inet_pton(AF_INET6, opt_addr, (void *)&addr) <= 0) {
+            char *addr_buff;
+            int addr_buff_len;
+            struct in6_addr temp;
+
+        // this is not valid IPv6 address, check if this is an IPv4 address      
+            if (inet_pton(AF_INET, opt_addr, (void *)&temp) <= 0) {
+                fprintf(stderr, "Illegal address: %s\n", opt_addr);
+                return 1;
+                }
+                      
+            addr_buff_len=10+strlen(opt_addr);
+            addr_buff=malloc(10+strlen(opt_addr));
+
+            fprintf(stderr, "converting ipv4 address format: %s\n", opt_addr);
+
+            strcat(addr_buff,"::ffff:");
+            strcat(addr_buff,opt_addr);
+                       
+            fprintf(stderr, "to ipv6 address format: %s\n", addr_buff);
+
+            if (inet_pton(AF_INET6, addr_buff, (void *)&addr) <= 0) {
+                fprintf(stderr, "Illegal address: %s\n", opt_addr);
+                return 1;
+                }
+                
+            free(addr_buff);                  
+              }
+            memcpy(&(settings.interf),&addr,sizeof(struct in6_addr));
+            } else {
+
+            if (inet_pton(AF_INET, opt_addr, (void *)&addr) <= 0) {
+                    fprintf(stderr, "Illegal address: %s\n", opt_addr);
+                    return 1;
+                    } else {
+                  memcpy(&(settings.interf),&addr,sizeof(struct in_addr));
+                  }
+                }
+        }
+
     if (maxcore != 0) {
         struct rlimit rlim_new;
         /*
Index: memcached.h
===================================================================
--- memcached.h	(revision 572)
+++ memcached.h	(working copy)
@@ -69,12 +69,17 @@
 
 #define MAX_VERBOSITY_LEVEL 2
 
+struct in_any_addr {
+    unsigned char s_addr[sizeof(struct in6_addr)];
+    };
+
+
 struct settings {
     size_t maxbytes;
     int maxconns;
     int port;
     int udpport;
-    struct in_addr interf;
+    struct in_any_addr interf;    
     int verbose;
     rel_time_t oldest_live; /* ignore existing items older than this */
     bool managed;          /* if 1, a tracker manages virtual buckets */
@@ -89,6 +94,7 @@
 
 extern struct stats stats;
 extern struct settings settings;
+extern bool ipv6;
 
 #define ITEM_LINKED 1
 #define ITEM_DELETED 2
@@ -190,7 +196,7 @@
     /* data for UDP clients */
     bool   udp;       /* is this is a UDP "connection" */
     int    request_id; /* Incoming UDP request ID, if this is a UDP "connection" */
-    struct sockaddr request_addr; /* Who sent the most recent request */
+    struct in_any_addr request_addr; /* Who sent the most recent request */
     socklen_t request_addr_size;
     unsigned char *hdrbuf; /* udp packet headers */
     int    hdrsize;   /* number of headers' worth of space is allocated */
