diff --git a/CMakeLists.txt b/CMakeLists.txt
index ebb2958aa3609182860d8e66f145071fc83eaa48..ee9f9944fc2f4c9dcca9f84c4243ce7191daadd7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -183,6 +183,7 @@ endif()
 
 add_subdirectory(third_party)
 add_subdirectory(cfg)
+add_subdirectory(connector)
 add_subdirectory(core)
 add_subdirectory(mod)
 add_subdirectory(test)
diff --git a/connector/CMakeLists.txt b/connector/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20bc4cc4b07a491ca4695a290e08096f65ce7a3f
--- /dev/null
+++ b/connector/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(c)
diff --git a/connector/c/CMakeLists.txt b/connector/c/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d7e8123b282210fcc20a0bce100118b86bdabdff
--- /dev/null
+++ b/connector/c/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(client client.c)
diff --git a/connector/c/client.c b/connector/c/client.c
new file mode 100644
index 0000000000000000000000000000000000000000..4597f2feeefa23c31bbd36c72f0d879b62ad986b
--- /dev/null
+++ b/connector/c/client.c
@@ -0,0 +1,85 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <connector/c/client.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+static
+struct sockaddr_in
+get_sockaddr_in(const char *hostname, unsigned short port) {
+  struct sockaddr_in result;
+
+  memset((void*)(&result), 0, sizeof(result));
+  result.sin_family = AF_INET;
+  result.sin_port   = htons(port);
+
+  struct hostent *host = gethostbyname(hostname);
+  if (host != 0)
+	  memcpy((void*)(&result.sin_addr),
+		 (void*)(host->h_addr), host->h_length);
+
+  return result;
+}
+
+struct tnt_connection *tnt_connect(const char *hostname, int port) {
+  int fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (fd < 0)
+	  return NULL;
+
+  int opt = 1;
+  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1)
+	  return NULL;
+
+  struct sockaddr_in addr = get_sockaddr_in(hostname, port);
+  if (connect(fd, (struct sockaddr*)&addr, sizeof addr))
+	  return NULL;
+
+  struct tnt_connection *conn = malloc(sizeof(struct tnt_connection));
+  conn->data_port = fd;
+  return conn;
+}
+
+void tnt_disconnect(struct tnt_connection *conn) {
+  close(conn->data_port);
+  free(conn);
+}
+
+int tnt_execute_raw(struct tnt_connection *conn, const char *message,
+		    size_t len) {
+  if (send(conn->data_port, message, len, 0) < 0)
+	  return 3;
+
+  char buf[2048];
+  if (recv(conn->data_port, buf, 2048, 0) < 16)
+	  return 3;
+
+  return buf[12]; // return_code: 0,1,2
+}
diff --git a/connector/c/client.h b/connector/c/client.h
new file mode 100644
index 0000000000000000000000000000000000000000..034ba5cc00b756f02e1b858e35d22385e3ea586d
--- /dev/null
+++ b/connector/c/client.h
@@ -0,0 +1,69 @@
+#ifndef TARANTOOL_CONNECTOR_CLIENT_H_INCLUDED
+# define TARANTOOL_CONNECTOR_CLIENT_H_INCLUDED
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * C client library for tarantool.
+ */
+
+#include <stddef.h>
+
+/**
+ * A connection with a Tarantool server.
+ */
+struct tnt_connection {
+	int data_port;
+};
+
+/**
+ * Open a connection with a Tarantool server.
+ *
+ * @param hostname the hostname of the server.
+ * @param port the port of the server.
+ *
+ * @return a newly opened connection or NULL if there was an error.
+ */
+struct tnt_connection *tnt_connect(const char *hostname, int port);
+
+/**
+ * Close a connection.
+ *
+ * @param conn the connection.
+ */
+void tnt_disconnect(struct tnt_connection *conn);
+
+/**
+ * Execute a statement on a connection
+ *
+ * @param conn the connection.
+ * @param message a raw message following Tarantool protocol.
+ * @param len the length of the message.
+ *
+ * @return the status code: 0,1,2 if the statement was successufully
+ * sent (see Tarantool protocol) or 3 if an error occured.
+ */
+int tnt_execute_raw(struct tnt_connection *conn, const char *message,
+		    size_t len);
+
+#endif /* TARANTOOL_CONNECTOR_CLIENT_H_INCLUDED */
diff --git a/mod/box/box.c b/mod/box/box.c
index a86d9675dd6688a18c9109b3f0bd433f06d5bf97..d501e85b5d5fd9c5d773991d077c69aa98a4bf1d 100644
--- a/mod/box/box.c
+++ b/mod/box/box.c
@@ -560,6 +560,9 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 	struct box_tuple *tuple;
 	uint32_t *found;
 	u32 count = read_u32(data);
+	if (count == 0)
+		box_raise(ERR_CODE_ILLEGAL_PARAMS,
+			  "tuple count must be greater than zero");
 
 	found = palloc(fiber->pool, sizeof(*found));
 	add_iov(found, sizeof(*found));
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d96c3520ce7462172eb23ab07ee775f09ad63d70..5b6ade761ef95634f94b8ee65a28e55c15e34ab4 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2,6 +2,10 @@ add_custom_target(test
     COMMAND python ${PROJECT_SOURCE_DIR}/test/test-run.py --builddir=${PROJECT_BINARY_DIR} --vardir=${PROJECT_BINARY_DIR}/test/var
     )
 
+add_executable(box/protocol
+  ${CMAKE_SOURCE_DIR}/test/box/protocol.c)
+target_link_libraries (box/protocol client)
+
 install (PROGRAMS tarantool DESTINATION bin)
 install (DIRECTORY lib DESTINATION bin)
 install (FILES box/tarantool.cfg box/00000000000000000001.snap
diff --git a/test/box/protocol.c b/test/box/protocol.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad75a341bcba42e557107eb440e8e88b4ac6076
--- /dev/null
+++ b/test/box/protocol.c
@@ -0,0 +1,33 @@
+#include <connector/c/client.h>
+#include <stdio.h>
+
+int main() {
+  struct tnt_connection *conn = tnt_connect("localhost", 33013);
+  if (conn == NULL)
+	  return 1;
+
+  {
+    const char message[]= {
+	    0xd, 0x0, 0x0, 0x0,    0x11, 0x0, 0x0, 0x0,    0x0, 0x0, 0x0, 0x0,
+	    0x0, 0x0, 0x0, 0x0,    0x0, 0x0, 0x0, 0x0,     0x1, 0x0, 0x0, 0x0,
+	    0x4,    0x1, 0x0, 0x0, 0x0 };
+    int res = tnt_execute_raw(conn, message, sizeof message);
+    printf("return_code: %d\n", res); // =0
+  }
+  {
+    /*
+     * A test case for Bug#702397
+     * https://bugs.launchpad.net/tarantool/+bug/702397
+     * "If SELECT request specifies tuple count 0, no error"
+     */
+    const char message[]= {
+	    0x11, 0x0, 0x0, 0x0,    0x14, 0x0, 0x0, 0x0,    0x0, 0x0, 0x0, 0x0,
+	    0x0, 0x0, 0x0, 0x0,     0x0, 0x0, 0x0, 0x0,     0x0, 0x0, 0x0, 0x0,
+	    0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 };
+    int res = tnt_execute_raw(conn, message, sizeof message);
+    printf("return_code: %d\n", res); // =2
+  }
+
+  tnt_disconnect(conn);
+  return 0;
+}
diff --git a/test/box/protocol.result b/test/box/protocol.result
new file mode 100644
index 0000000000000000000000000000000000000000..309dfed10be212e98be605ace8498f3947ff30c9
--- /dev/null
+++ b/test/box/protocol.result
@@ -0,0 +1,2 @@
+return_code: 0
+return_code: 2
diff --git a/test/box/protocol.test b/test/box/protocol.test
new file mode 100644
index 0000000000000000000000000000000000000000..bde4516a73b77aa76c264e40d826ca79930dceff
--- /dev/null
+++ b/test/box/protocol.test
@@ -0,0 +1,7 @@
+import subprocess
+import sys
+
+p = subprocess.Popen([ "box/protocol" ], stdout=subprocess.PIPE)
+p.wait()
+for line in p.stdout.readlines():
+      sys.stdout.write(line)