Index: /branches/binary/server/memcached.c
===================================================================
--- /branches/binary/server/memcached.c (revision 731)
+++ /branches/binary/server/memcached.c (revision 732)
@@ -307,4 +307,7 @@
             rv="ascii-udp";
             break;
+        case negotiating_prot:
+            rv="auto-negotiate";
+            break;
     }
     return rv;
@@ -380,4 +383,6 @@
         } else if (prot == ascii_prot) {
             fprintf(stderr, "<%d new ascii client connection\n", sfd);
+        } else if (prot == negotiating_prot) {
+            fprintf(stderr, "<%d new auto-negotiating client connection\n", sfd);
         } else {
             fprintf(stderr, "<%d new unknown (%d) client connection\n",
@@ -515,4 +520,7 @@
         case binary_prot:
             rv=conn_bin_init;
+            break;
+        case negotiating_prot:
+            rv=conn_negotiate;
             break;
         default:
@@ -1366,4 +1374,46 @@
 }
 
+static void reinit_bin_connection(conn *c) {
+    if (settings.verbose > 0)
+        fprintf(stderr, "*** Reinitializing binary connection.\n");
+    c->rlbytes = MIN_BIN_PKT_LENGTH;
+    c->write_and_go = conn_bin_init;
+    c->cmd = -1;
+    c->substate = bin_no_state;
+    c->rbytes = c->wbytes = 0;
+    c->ritem = (char*)c->bin_header;
+    c->rcurr = c->rbuf;
+    c->wcurr = c->wbuf;
+    conn_shrink(c);
+    conn_set_state(c, conn_nread);
+}
+
+/* These do the initial protocol switch.  At this point, we should've read
+ * exactly one byte, and must treat that byte as the beginning of a command. */
+static void setup_bin_protocol(conn *c) {
+    char *loc = (char*)c->bin_header;
+    if (settings.verbose > 0)
+        fprintf(stderr, "Negotiated protocol as binary.\n");
+
+    c->protocol = binary_prot;
+    reinit_bin_connection(c);
+    /* Emulate a read of the first byte */
+    c->ritem[0] = c->rbuf[0];
+    c->ritem++;
+    c->rlbytes--;
+}
+
+static void setup_ascii_protocol(conn *c) {
+    if (settings.verbose > 0)
+        fprintf(stderr, "Negotiated protocol as ascii.\n");
+    c->protocol = ascii_prot;
+
+    /* We've already got the first letter of the command, so pretend like we
+     * Did a single byte read from try_read_command */
+    c->rcurr=c->rbuf;
+    c->rbytes=1;
+    conn_set_state(c, conn_read);
+}
+
 static void complete_nread(conn *c) {
     assert(c != NULL);
@@ -1373,4 +1423,10 @@
     } else if(c->protocol == binary_prot) {
         complete_nread_binary(c);
+    } else if(c->protocol == negotiating_prot) {
+        /* The first byte is either BIN_REQ_MAGIC, or we're speaking ascii */
+        if ((c->rbuf[0] & 0xff) == BIN_REQ_MAGIC)
+            setup_bin_protocol(c);
+        else
+            setup_ascii_protocol(c);
     } else {
         assert(0); /* XXX:  Invalid case.  Should probably do more here. */
@@ -2710,4 +2766,14 @@
             break;
 
+        case conn_negotiate:
+            if (settings.verbose > 0)
+                fprintf(stderr, "Negotiating protocol for a new connection\n");
+            c->rlbytes = 1;
+            c->ritem = c->rbuf;
+            c->rcurr = c->rbuf;
+            c->wcurr = c->wbuf;
+            conn_set_state(c, conn_nread);
+            break;
+
         case conn_read:
             if (try_read_command(c) != 0) {
@@ -2728,14 +2794,5 @@
 
         case conn_bin_init: /* Reinitialize a binary connection */
-            c->rlbytes = MIN_BIN_PKT_LENGTH;
-            c->write_and_go = conn_bin_init;
-            c->cmd = -1;
-            c->substate = bin_no_state;
-            c->rbytes = c->wbytes = 0;
-            c->wcurr = c->wbuf;
-            c->rcurr = c->rbuf;
-            c->ritem = (char*)c->bin_header;
-            conn_set_state(c, conn_nread);
-            conn_shrink(c);
+            reinit_bin_connection(c);
             break;
 
@@ -3728,5 +3785,5 @@
         int udp_port;
 
-        if (server_socket(settings.port, ascii_prot)) {
+        if (server_socket(settings.port, negotiating_prot)) {
             fprintf(stderr, "failed to listen\n");
             exit(EXIT_FAILURE);
Index: /branches/binary/server/memcached.h
===================================================================
--- /branches/binary/server/memcached.h (revision 723)
+++ /branches/binary/server/memcached.h (revision 732)
@@ -186,4 +186,5 @@
     conn_mwrite,     /** writing out many items sequentially */
     conn_bin_init,   /** Reinitializing a binary protocol connection */
+    conn_negotiate,  /** Negotiating a protocol */
 };
 
@@ -201,5 +202,6 @@
     ascii_prot = 3, /* arbitrary value. */
     ascii_udp_prot,
-    binary_prot
+    binary_prot,
+    negotiating_prot, /* Discovering the protocol */
 };
 
