From 03e3881043de68f371883fdb82a1d2bebf4179ed Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 18 Jul 2013 16:23:48 -0400 Subject: [PATCH] Tests for connection_write_ext_or_command. --- src/or/connection.c | 6 +-- src/or/connection.h | 4 +- src/or/ext_orport.c | 3 +- src/or/ext_orport.h | 7 ++++ src/test/test_extorport.c | 87 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/or/connection.c b/src/or/connection.c index f1d7961a17..6c95245b57 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -3714,9 +3714,9 @@ connection_flush(connection_t *conn) * it all, so we don't end up with many megabytes of controller info queued at * once. */ -void -connection_write_to_buf_impl_(const char *string, size_t len, - connection_t *conn, int zlib) +MOCK_IMPL(void, +connection_write_to_buf_impl_,(const char *string, size_t len, + connection_t *conn, int zlib)) { /* XXXX This function really needs to return -1 on failure. */ int r; diff --git a/src/or/connection.h b/src/or/connection.h index 19f11c7439..0454ac2f36 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -130,8 +130,8 @@ int connection_outbuf_too_full(connection_t *conn); int connection_handle_write(connection_t *conn, int force); int connection_flush(connection_t *conn); -void connection_write_to_buf_impl_(const char *string, size_t len, - connection_t *conn, int zlib); +MOCK_DECL(void, connection_write_to_buf_impl_, + (const char *string, size_t len, connection_t *conn, int zlib)); /* DOCDOC connection_write_to_buf */ static void connection_write_to_buf(const char *string, size_t len, connection_t *conn); diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c index e0980dedac..b1bb11bd46 100644 --- a/src/or/ext_orport.c +++ b/src/or/ext_orport.c @@ -6,6 +6,7 @@ * \brief Code implementing the Extended ORPort. */ +#define EXT_ORPORT_PRIVATE #include "or.h" #include "connection.h" #include "connection_or.h" @@ -52,7 +53,7 @@ connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out) * command as the command type, bodylen as the body * length, and body, if it's present, as the body of the * message. */ -static int +STATIC int connection_write_ext_or_command(connection_t *conn, uint16_t command, const char *body, diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h index 92ace7779c..35b92ad63f 100644 --- a/src/or/ext_orport.h +++ b/src/or/ext_orport.h @@ -22,5 +22,12 @@ int connection_ext_or_process_inbuf(or_connection_t *or_conn); int init_ext_or_cookie_authentication(int is_enabled); char *get_ext_or_auth_cookie_file_name(void); +#ifdef EXT_ORPORT_PRIVATE +STATIC int connection_write_ext_or_command(connection_t *conn, + uint16_t command, + const char *body, + size_t bodylen); +#endif + #endif diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index cfe810ef0b..525ac4f191 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -2,7 +2,9 @@ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE +#define EXT_ORPORT_PRIVATE #include "or.h" +#include "buffers.h" #include "connection.h" #include "ext_orport.h" #include "test.h" @@ -59,7 +61,92 @@ test_ext_or_id_map(void *arg) connection_or_clear_ext_or_id_map(); } +/* Simple connection_write_to_buf_impl_ replacement that unconditionally + * writes to outbuf. */ +static void +connection_write_to_buf_impl_replacement(const char *string, size_t len, + connection_t *conn, int zlib) +{ + (void) zlib; + + tor_assert(string); + tor_assert(conn); + write_to_buf(string, len, conn->outbuf); +} + +static char * +buf_get_contents(buf_t *buf, size_t *sz_out) +{ + char *out; + *sz_out = buf_datalen(buf); + if (*sz_out >= ULONG_MAX) + return NULL; /* C'mon, really? */ + out = tor_malloc(*sz_out + 1); + if (fetch_from_buf(out, (unsigned long)*sz_out, buf) != 0) { + tor_free(out); + return NULL; + } + out[*sz_out] = '\0'; /* Hopefully gratuitous. */ + return out; +} + +static void +test_ext_or_write_command(void *arg) +{ + or_connection_t *c1; + char *cp = NULL; + char *buf = NULL; + size_t sz; + + (void) arg; + MOCK(connection_write_to_buf_impl_, + connection_write_to_buf_impl_replacement); + + c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET); + tt_assert(c1); + + /* Length too long */ + tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000), + <, 0); + + /* Empty command */ + tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0), + ==, 0); + cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); + tt_int_op(sz, ==, 4); + test_mem_op(cp, ==, "\x00\x99\x00\x00", 4); + tor_free(cp); + + /* Medium command. */ + tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, + "Wai\0Hello", 9), ==, 0); + cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); + tt_int_op(sz, ==, 13); + test_mem_op(cp, ==, "\x00\x99\x00\x09Wai\x00Hello", 13); + tor_free(cp); + + /* Long command */ + buf = tor_malloc(65535); + memset(buf, 'x', 65535); + tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d, + buf, 65535), ==, 0); + cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz); + tt_int_op(sz, ==, 65539); + test_mem_op(cp, ==, "\xf0\x0d\xff\xff", 4); + test_mem_op(cp+4, ==, buf, 65535); + tor_free(cp); + + done: + if (c1) + connection_free_(TO_CONN(c1)); + tor_free(cp); + tor_free(buf); + UNMOCK(connection_write_to_buf_impl_); +} + struct testcase_t extorport_tests[] = { { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL }, + { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; +