diff --git a/connector/c/include/tp.h b/connector/c/include/tp.h
index 72a6aef92e0e4180f04f609e690b3ad97f93d1db..a73e2b5aca1b48ee8f6033e2da61f89403b12c0b 100644
--- a/connector/c/include/tp.h
+++ b/connector/c/include/tp.h
@@ -5,6 +5,9 @@
  * TP - Tarantool Protocol request constructor
  * (http://tarantool.org)
  *
+ * protocol description:
+ * https://github.com/mailru/tarantool/blob/master/doc/box-protocol.txt
+ *
  * Copyright (c) 2012-2013 Mail.Ru Group 
  *
  * Redistribution and use in source and binary forms, with or
@@ -41,6 +44,7 @@
 
 #define tp_function_unused __attribute__((unused))
 #define tp_packed __attribute__((packed))
+#define tp_inline __attribute__((forceinline))
 #define tp_noinline __attribute__((noinline))
 
 #define tp_likely(expr)   __builtin_expect(!! (expr), 1)
@@ -101,6 +105,7 @@ struct tp {
 	char *s, *p, *e;
 	char *t, *f, *u;
 	char *c;
+	uint32_t tsz, fsz, tc;
 	uint32_t code;
 	uint32_t cnt;
 	tp_resizer resizer;
@@ -124,11 +129,17 @@ tp_unused(struct tp *p) {
 
 tp_function_unused static char*
 tp_reallocator(struct tp *p, size_t req, size_t *size) {
-	size_t nsz = tp_size(p) * 2;
-	if (tp_unlikely(nsz < req))
-		nsz = req;
-	*size = nsz;
-	return realloc(p->s, nsz);
+	size_t toalloc = tp_size(p) * 2;
+	if (tp_unlikely(toalloc < req))
+		toalloc = req;
+	*size = toalloc;
+	return realloc(p->s, toalloc);
+}
+
+tp_function_unused static char*
+tp_reallocator_noloss(struct tp *p, size_t req, size_t *size) {
+	*size = tp_size(p) + (req - tp_unused(p));
+	return realloc(p->s, *size);
 }
 
 static inline void
@@ -142,6 +153,8 @@ tp_init(struct tp *p, char *buf, size_t size,
 	p->u = NULL;
 	p->c = NULL;
 	p->h = NULL;
+	p->tsz = 0;
+	p->fsz = 0;
 	p->cnt = 0;
 	p->code = 0;
 	p->resizer = resizer;
@@ -159,9 +172,10 @@ tp_ensure(struct tp *p, size_t size) {
 	if (tp_unlikely(np == NULL))
 		return -1;
 	p->p = np + (p->p - p->s);
-	p->t = np + (p->t - p->s);
 	if (tp_likely(p->h))
 		p->h = (struct tp_h*)(np + (((char*)p->h) - p->s));
+	if (tp_likely(p->t))
+		p->t = np + (p->t - p->s);
 	if (tp_unlikely(p->f))
 		p->f = (np + (p->f - p->s));
 	if (tp_unlikely(p->u))
@@ -171,13 +185,18 @@ tp_ensure(struct tp *p, size_t size) {
 	return sz;
 }
 
+static inline ssize_t
+tp_use(struct tp *p, size_t size) {
+	p->p += size;
+	return tp_used(p);
+}
+
 static inline ssize_t
 tp_append(struct tp *p, void *data, size_t size) {
 	if (tp_unlikely(tp_ensure(p, size) == -1))
 		return -1;
 	memcpy(p->p, data, size);
-	p->p += size;
-	return tp_used(p);
+	return tp_use(p, size);
 }
 
 static inline void
@@ -239,6 +258,46 @@ tp_leb128save(struct tp *p, uint32_t value) {
 	*(p->p++) = ((value) & 0x7F);
 }
 
+static tp_noinline int
+tp_leb128load_slowpath(struct tp *p, uint32_t *value) {
+	if (tp_likely(! (p->f[2] & 0x80))) {
+		*value = (p->f[0] & 0x7f) << 14 |
+		         (p->f[1] & 0x7f) << 7  |
+		         (p->f[2] & 0x7f);
+		p->f += 3;
+	} else
+	if (! (p->f[3] & 0x80)) {
+		*value = (p->f[0] & 0x7f) << 21 |
+		         (p->f[1] & 0x7f) << 14 |
+		         (p->f[2] & 0x7f) << 7  |
+		         (p->f[3] & 0x7f);
+		p->f += 4;
+	} else
+	if (! (p->f[4] & 0x80)) {
+		*value = (p->f[0] & 0x7f) << 28 |
+		         (p->f[1] & 0x7f) << 21 |
+		         (p->f[2] & 0x7f) << 14 |
+		         (p->f[3] & 0x7f) << 7  |
+		         (p->f[4] & 0x7f);
+		p->f += 5;
+	} else
+		return -1;
+	return 0;
+}
+
+static inline int
+tp_leb128load(struct tp *p, uint32_t *value) {
+	if (tp_likely(! (p->f[0] & 0x80))) {
+		*value = *(p->f++) & 0x7f;
+	} else
+	if (tp_likely(! (p->f[1] & 0x80))) {
+		*value = (p->f[0] & 0x7f) << 7 | (p->f[1] & 0x7f);
+		p->f += 2;
+	} else
+		return tp_leb128load_slowpath(p, value);
+	return 0;
+}
+
 static inline ssize_t
 tp_field(struct tp *p, char *data, size_t size) {
 	assert(p->h != NULL);
@@ -424,9 +483,10 @@ tp_sz(struct tp *p, char *sz) {
 
 static ssize_t
 tp_required(struct tp *p) {
-	size_t used = tp_used(p);
+	register size_t used = tp_used(p);
 	if (tp_unlikely(used < sizeof(struct tp_h)))
 		return sizeof(struct tp_h) - used;
+	used -= sizeof(struct tp_h);
 	register struct tp_h *h = (struct tp_h*)p->s;
 	return (tp_likely(used < h->len)) ?
 	                  h->len - used : used - h->len;
@@ -450,6 +510,11 @@ tp_replyerror(struct tp *p) {
 	return p->c;
 }
 
+static inline int
+tp_replyerrorlen(struct tp *p) {
+	return tp_unfetched(p) + tp_required(p);
+}
+
 static inline uint32_t
 tp_replycount(struct tp *p) {
 	return p->cnt;
@@ -489,56 +554,85 @@ tp_reply(struct tp *p) {
 	if (tp_unlikely(tp_unfetched(p) == 0))
 		return p->code;
 	p->cnt = *(uint32_t*)tp_fetch(p, sizeof(uint32_t));
-	p->t = p->c;
 	return p->code;
 }
 
 static inline void
 tp_rewind(struct tp *p) {
-	p->t = p->c;
+	p->t = NULL;
+	p->f = NULL;
 }
 
 static inline void
 tp_rewindfield(struct tp *p) {
-	p->f = p->t;
+	p->f = NULL;
 }
 
 static inline uint32_t
-tp_fqtuplesize(char *p) {
-	return *(uint32_t*)p;
+tp_tuplesize(struct tp *p) {
+	return *(uint32_t*)(p->t - 4);
 }
 
-static inline uint32_t
-tp_fqtuplecount(char *p) {
-	return *(uint32_t*)(p + 4);
+static inline char*
+tp_tupleend(struct tp *p) {
+	/* tuple_size + p->t + cardinaltiy_size +
+	 * fields_size */
+	return p->t + p->tsz + 4;
+}
+
+static inline int
+tp_hasdata(struct tp *p) {
+	return tp_unfetched(p) > 0;
+}
+
+static inline int
+tp_hasnext(struct tp *p) {
+	assert(p->t != NULL);
+	return (p->e - tp_tupleend(p)) >= 4;
+}
+
+static inline int
+tp_hasnextfield(struct tp *p) {
+	assert(p->t != NULL);
+	register char *f = p->f + p->fsz;
+	if (tp_unlikely(p->f == NULL))
+		f = p->t + 4;
+	return (tp_tupleend(p) - f) >= 1;
 }
 
 static inline char*
 tp_next(struct tp *p) {
-	assert(p->t != NULL);
-	if ((p->t - p->e) < sizeof(uint32_t))
+	if (tp_unlikely(p->t == NULL)) {
+		if (tp_unlikely(! tp_hasdata(p)))
+				return NULL;
+		p->t = p->c + 4;
+		goto fetch;
+	}
+	if (tp_unlikely(! tp_hasnext(p)))
 		return NULL;
-	char *c = p->t;
-	uint32_t size = tp_fqtuplesize(c);
-	/* tuple size + tuple cardinality */
-	p->f = p->t + 8;
-	p->t += size;
-	return c;
+	p->t = tp_tupleend(p) + 4;
+fetch:
+	p->tsz = *(uint32_t*)(p->t - 4);
+	p->f = NULL;
+	return p->t;
 }
 
 static inline char*
-tp_nextfield(struct tp *p, size_t *sz) {
+tp_nextfield(struct tp *p, uint32_t *sz) {
 	assert(p->t != NULL);
-	assert(p->f != NULL);
-	if ((p->f - p->t) <= 1)
+	if (tp_unlikely(p->f == NULL)) {
+		p->f = p->t + 4;
+		goto fetch;
+	}
+	if (tp_unlikely(! tp_hasnextfield(p)))
+		return NULL;
+	p->f += p->fsz;
+fetch:;
+	register int rc = tp_leb128load(p, &p->fsz);
+	if (tp_unlikely(rc == -1))
 		return NULL;
-	(void)sz;
-	/* loadsize
-	 * set size
-	 * set return data
-	 * inc pointer
-	 */
-	return NULL;
+	*sz = p->fsz;
+	return p->f;
 }
 
 #endif /* TP_H_INCLUDED */
diff --git a/test/connector_c/tp.c b/test/connector_c/tp.c
index 9dc8bf48d38d4f0499ae21e4dc9e044eaa0eb710..7a2db8bf5873b856c023e35b18307ccb4f50f4d8 100644
--- a/test/connector_c/tp.c
+++ b/test/connector_c/tp.c
@@ -2,26 +2,90 @@
 #include <stdio.h>
 #include <tp.h>
 
-int main(void)
+static void reply_print(struct tp *rep) {
+	char *tu;
+	while ((tu = tp_next(rep))) {
+		printf("tuple fields: %d\n", tp_tuplecount(rep));
+		printf("tuple size: %d\n", tp_tuplesize(rep));
+		printf("[");
+		char *field;
+		uint32_t field_size;
+		while ((field = tp_nextfield(rep, &field_size))) {
+			printf("%-.*s", field_size, field);
+			if (tp_hasnextfield(rep))
+				printf(", ");
+		}
+		printf("]\n");
+	}
+}
+
+static int reply(void) {
+	struct tp rep;
+	tp_init(&rep, NULL, 0, tp_reallocator_noloss, NULL);
+
+	while (1) {
+		ssize_t to_read = tp_required(&rep);
+		printf("to_read: %zu\n", to_read);
+		if (to_read <= 0)
+			break;
+		ssize_t new_size = tp_ensure(&rep, to_read);
+		printf("new_size: %zu\n", new_size);
+		if (new_size == -1)
+			return -1;
+		int rc = fread(rep.p, to_read, 1, stdin);
+		if (rc != 1)
+			return 1;
+		tp_use(&rep, to_read);
+	}
+
+	ssize_t server_code = tp_reply(&rep);
+
+	printf("op:    %d\n", tp_replyop(&rep));
+	printf("count: %d\n", tp_replycount(&rep));
+	printf("code:  %zu\n", server_code);
+
+	if (server_code != 0) {
+		printf("error: %-.*s\n", tp_replyerrorlen(&rep),
+		       tp_replyerror(&rep));
+		return 1;
+	}
+
+	reply_print(&rep);
+
+	/*
+	tp_rewind(&rep);
+	reply_print(&rep);
+	*/
+
+	return 0;
+}
+
+int
+main(int argc, char *argv[])
 {
-	char buf[128];
+	if (argc == 2 && !strcmp(argv[1], "--reply"))
+		return reply();
 
+	char buf[128];
 	struct tp req;
 	tp_init(&req, buf, sizeof(buf), NULL, NULL);
-	/*tp_ping(&req);*/
 
 	/*
-	tp_insert(&req, 0, 0);
+	tp_insert(&req, 0, TP_FRET);
 	tp_tuple(&req);
 	tp_sz(&req, "key");
 	tp_sz(&req, "value");
 	*/
 
 	/*
-	tp_select(&req, 0, 0, 0, 1);
+	tp_ping(&req);
+	*/
+
+	tp_select(&req, 0, 1, 0, 10);
 	tp_tuple(&req);
 	tp_sz(&req, "key");
-	tp_sz(&req, "key");
+
+	/*
 	*/
 
 	/*