0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-25 22:30:51 +08:00
libzmq/tests/test_socks.cpp
Nehal Patel 8cdc4ed71a
Problem: unused variables warnings
Solution: fix them
2023-10-04 09:51:43 +01:00

868 lines
31 KiB
C++

/* SPDX-License-Identifier: MPL-2.0 */
#ifdef _WIN32
#include "../src/windows.hpp"
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include "testutil.hpp"
#include "testutil_unity.hpp"
SETUP_TEARDOWN_TESTCONTEXT
void recvall (int sock_fd, char *buffer, int len)
{
int res;
int total = 0;
while (len - total > 0) {
res = recv (sock_fd, buffer + total, len - total, 0);
if (res == -1)
fprintf (stderr, "socks_server: error receiving %d bytes: %d %d\n",
len, res, errno);
TEST_ASSERT_SUCCESS_RAW_ERRNO (res);
TEST_ASSERT (res != 0);
total += res;
}
TEST_ASSERT (total == len);
}
int recvonce (int sock_fd, char *buffer, int len)
{
int res;
res = recv (sock_fd, buffer, len, 0);
if (res == -1)
fprintf (stderr, "socks_server: error receiving bytes: %d %d\n", res,
errno);
TEST_ASSERT_SUCCESS_RAW_ERRNO (res);
return res;
}
void sendall (int sock_fd, char *buffer, int len)
{
int res;
int total = 0;
while (len - total > 0) {
res = send (sock_fd, buffer + total, len - total, 0);
if (res == -1)
fprintf (stderr, "socks_server: error sending %d bytes: %d %d\n",
len, res, errno);
TEST_ASSERT_SUCCESS_RAW_ERRNO (res);
TEST_ASSERT (res != 0);
total += res;
}
}
int remote_connect (int socket, uint32_t addr, uint16_t port)
{
int res;
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_addr.s_addr = htonl (addr);
ip4addr.sin_port = htons (port);
res = connect (socket, (struct sockaddr *) &ip4addr, sizeof ip4addr);
return res;
}
void *setup_socks_server (char *socks_server_address,
int socks_server_address_len)
{
LIBZMQ_UNUSED (socks_server_address_len);
fprintf (stderr, "socks_server: setup socks server\n");
int server_fd =
bind_socket_resolve_port ("127.0.0.1", "0", socks_server_address);
memmove (socks_server_address, strchr (socks_server_address, '/') + 2,
strlen (strchr (socks_server_address, '/') + 1));
fprintf (stderr, "socks_server: bound to: tcp://%s\n",
socks_server_address);
return (void *) (intptr_t) server_fd;
}
void socks_server_task (void *socks_server,
const char *username,
const char *password,
int max_client_connect)
{
int server_fd = (int) (intptr_t) socks_server;
fprintf (stderr, "socks_server: starting server thread\n");
int res;
res = listen (server_fd, max_client_connect);
TEST_ASSERT_SUCCESS_RAW_ERRNO (res);
int auth_method;
if (username == NULL || username[0] == '\0') {
auth_method = 0x0; /* No auth */
} else {
auth_method = 0x2; /* Basic auth */
if (password == NULL)
password = "";
}
int count = 0;
while (count < max_client_connect) {
int client = -1;
do {
char buffer[4096];
fprintf (stderr, "socks_server: waiting for connection\n");
client = accept (server_fd, NULL, NULL);
TEST_ASSERT_SUCCESS_RAW_ERRNO (client);
count++;
fprintf (stderr, "socks_server: accepted client connection %d/%d\n",
count, max_client_connect);
/* Greetings [version, nmethods, methods...]. */
recvall (client, buffer, 2);
TEST_ASSERT (buffer[0] == 0x5);
int nmethods = buffer[1];
int method = 0xff;
recvall (client, buffer, nmethods);
for (int i = 0; i < nmethods; i++) {
if (buffer[i] == auth_method)
method = auth_method;
}
fprintf (stderr, "socks_server: received greetings\n");
/* Greetings response [version, method]. */
buffer[0] = 0x5;
buffer[1] = method;
sendall (client, buffer, 2);
fprintf (stderr,
"socks_server: answered greetings (method: 0x%x)\n",
method);
if (method == 0xff)
break; /* Out of client connection */
if (method == 0x2) {
int len;
int err = 0;
recvall (client, buffer, 1);
if (buffer[0] != 0x1) {
err = 1;
} else {
recvall (client, buffer, 1);
len = (unsigned char) buffer[0];
recvall (client, buffer, len);
buffer[len] = '\0';
if (strcmp (username, buffer) != 0) {
fprintf (stderr,
"socks_server: error on username check: '%s', "
"expected: '%s'\n",
buffer, username);
err = 1;
}
recvall (client, buffer, 1);
len = (unsigned char) buffer[0];
recvall (client, buffer, len);
buffer[len] = '\0';
if (strcmp (password, buffer) != 0) {
fprintf (stderr,
"socks_server: error on password check: '%s', "
"expected: '%s'\n",
buffer, password);
err = 1;
}
}
fprintf (stderr, "socks_server: received credentials\n");
buffer[0] = 0x1;
buffer[1] = err;
sendall (client, buffer, 2);
fprintf (stderr,
"socks_server: answered credentials (err: 0x%x)\n",
err);
if (err != 0)
break; /* Out of client connection. */
}
/* Request [version, cmd, rsv, atype, dst.addr, dst.port */
/* Test only tcp connect on top of IPV4 */
recvall (client, buffer, 4);
TEST_ASSERT (buffer[0] == 0x5);
TEST_ASSERT (buffer[1] == 0x1); /* CONNECT cmd */
TEST_ASSERT (buffer[2] == 0x0); /* reserved, ensure we send 0 */
fprintf (stderr,
"socks_server: received command (cmd: %d, atype: %d)\n",
buffer[1], buffer[3]);
/* IPv4 ADDR & PORT */
uint32_t naddr = 0, bind_naddr = 0;
uint16_t nport = 0, bind_nport = 0;
int remote = -1;
int err = 0;
int request_atype = buffer[3];
if (request_atype == 0x1) /* ATYPE IPv4 */ {
recvall (client, (char *) &naddr, 4);
fprintf (stderr,
"socks_server: received address (addr: 0x%x)\n",
ntohl (naddr));
} else if (request_atype == 0x3) /* ATYPE DOMAINNAME */ {
int len;
recvall (client, buffer, 1);
len = (unsigned char) buffer[0];
recvall (client, buffer, len);
buffer[len] = '\0';
fprintf (stderr,
"socks_server: received domainname (hostname: %s)\n",
buffer);
/* For the test we support static resolution of
hostname "somedomainnmame.org" to localhost */
if (strcmp ("somedomainname.org", buffer) == 0) {
naddr = htonl (0x7f000001); /* 127.0.0.1 */
} else {
err = 0x4; /* Host unreachable */
}
} else if (request_atype == 0x4) {
/* For the test we simulate IPV6 connection request ::1, but connect to IPv4 localhost */
unsigned char nipv6local[16] = {0};
nipv6local[15] = 1;
recvall (client, buffer, 16);
fprintf (stderr,
"socks_server: received ipv6 address (buffer:");
for (int i = 0; i < 16; i++)
fprintf (stderr, " 0x%x", (unsigned char) buffer[i]);
fprintf (stderr, ")\n");
if (memcmp (buffer, nipv6local, 16) == 0) {
naddr = htonl (0x7f000001); /* 127.0.0.1 */
} else {
err = 0x4; /* Host unreachable */
}
} else {
err = 0x8; /* ATYPE not supported */
}
recvall (client, (char *) &nport, 2);
fprintf (stderr, "socks_server: received port (port: %d)\n",
ntohs (nport));
if (err == 0) {
fprintf (stderr, "socks_server: trying to connect to %x:%d\n",
ntohl (naddr), ntohs (nport));
remote = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
res = remote_connect (remote, ntohl (naddr), ntohs (nport));
if (res != 0) {
err = 0x5; /* Connection refused */
} else {
struct sockaddr_in ip4addr;
socklen_t len = sizeof (ip4addr);
res =
getsockname (remote, (struct sockaddr *) &ip4addr, &len);
TEST_ASSERT_SUCCESS_RAW_ERRNO (res);
fprintf (stderr,
"socks_server: connected and bound at: %x:%d\n",
ntohl (ip4addr.sin_addr.s_addr),
ntohs (ip4addr.sin_port));
bind_naddr = ip4addr.sin_addr.s_addr;
bind_nport = ip4addr.sin_port;
}
}
/* Reply request */
buffer[0] = 0x5;
buffer[1] = err;
buffer[2] = 0;
buffer[3] = request_atype;
sendall (client, buffer, 4);
if (request_atype == 0x1) /* ATYPE IPv4 */ {
sendall (client, (char *) &bind_naddr, 4);
} else if (request_atype == 0x3) {
/* This is just for testing reply with a hostname,
normally a resolved address is passed in return to connect. */
buffer[0] = strlen ("localhost");
sendall (client, buffer, 1);
strcpy (buffer, "localhost");
sendall (client, buffer, strlen ("localhost"));
} else if (request_atype == 0x4) {
/* We simulate a bind to ::1, though the actual connection is IPv4 */
char nipv6local[16] = {0};
nipv6local[15] = 1;
sendall (client, nipv6local, sizeof nipv6local);
}
sendall (client, (char *) &bind_nport, 2);
fprintf (stderr, "socks_server: replied to request (err: 0x%x)\n",
err);
if (err != 0)
break; /* Out of client connection. */
/* Communication loop */
zmq_pollitem_t items[] = {
{NULL, client, ZMQ_POLLIN, 0},
{NULL, remote, ZMQ_POLLIN, 0},
};
fprintf (stderr,
"socks_server: waiting for input (client fd: %d, remote "
"fd: %d)\n",
client, remote);
while (1) {
if (client == -1 || remote == -1)
break;
if (zmq_poll (items, 2, -1) < 0)
break;
int nbytes;
for (int i = 0; i < 2; i++) {
if ((items[i].revents & ZMQ_POLLIN) == 0)
continue;
fprintf (stderr, "socks_server: ready to read from fd %d\n",
items[i].fd);
int write_fd, read_fd = items[i].fd;
if (read_fd == client) {
write_fd = remote;
} else {
write_fd = client;
}
nbytes = recvonce (read_fd, buffer, sizeof buffer);
fprintf (stderr, "socks_server: read returned: %d\n",
nbytes);
if (nbytes == 0 || nbytes == -1) {
/* End of stream or error */
if (read_fd == client) {
close (client);
client = -1;
}
if (read_fd == remote) {
close (remote);
remote = -1;
}
break;
}
sendall (write_fd, buffer, nbytes);
}
}
if (remote != -1) {
close (remote);
remote = -1;
}
fprintf (stderr, "socks_server: closed remote connection %d/%d\n",
count, max_client_connect);
} while (0); /* Client socket scope. */
if (client != -1) {
close (client);
client = -1;
}
fprintf (stderr, "socks_server: closed client connection %d/%d\n",
count, max_client_connect);
}
close (server_fd);
fprintf (stderr, "socks_server: closed server\n");
}
void socks_server_no_auth (void *socks_server)
{
socks_server_task (socks_server, NULL, NULL, 1);
}
void socks_server_no_auth_delay (void *socks_server)
{
fprintf (stderr, "socks_server: delay no auth socks server start\n");
// Enough delay to have client connecting before proxy listens
msleep (SETTLE_TIME * 10);
socks_server_task (socks_server, NULL, NULL, 1);
}
void socks_server_basic_auth (void *socks_server)
{
socks_server_task (socks_server, "someuser", "somepass", 1);
}
void socks_server_basic_auth_delay (void *socks_server)
{
fprintf (stderr, "socks_server: delay basic auth socks server start\n");
// Enough delay to have client connecting before proxy listens
msleep (SETTLE_TIME * 10);
socks_server_task (socks_server, "someuser", "somepass", 1);
}
void socks_server_basic_auth_no_pass (void *socks_server)
{
socks_server_task (socks_server, "someuser", NULL, 1);
}
void *setup_push_server (char *connect_address, int connect_address_size)
{
int res;
const char *bind_address = "tcp://127.0.0.1:*";
void *push = test_context_socket (ZMQ_PUSH);
res = zmq_bind (push, bind_address);
TEST_ASSERT_SUCCESS_ERRNO (res);
size_t len = connect_address_size;
res = zmq_getsockopt (push, ZMQ_LAST_ENDPOINT, connect_address, &len);
TEST_ASSERT_SUCCESS_ERRNO (res);
fprintf (stderr, "push_server: bound to: %s\n", connect_address);
return push;
}
void *setup_pull_client (const char *connect_address, const char *socks_proxy)
{
int res;
void *pull = test_context_socket (ZMQ_PULL);
if (socks_proxy != NULL) {
res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy,
strlen (socks_proxy));
TEST_ASSERT_SUCCESS_ERRNO (res);
fprintf (stderr, "pull_client: use socks proxy: tcp://%s\n",
socks_proxy);
}
res = zmq_connect (pull, connect_address);
TEST_ASSERT_SUCCESS_ERRNO (res);
fprintf (stderr, "pull_client: connected to: %s\n", connect_address);
return pull;
}
#ifdef ZMQ_BUILD_DRAFT_API
void *setup_pull_client_with_auth (const char *connect_address,
const char *socks_proxy,
const char *username,
const char *password)
{
int res;
void *pull = test_context_socket (ZMQ_PULL);
if (socks_proxy != NULL) {
res = zmq_setsockopt (pull, ZMQ_SOCKS_PROXY, socks_proxy,
strlen (socks_proxy));
TEST_ASSERT_SUCCESS_ERRNO (res);
fprintf (stderr, "pull_client: use socks proxy: tcp://%s\n",
socks_proxy);
}
res = zmq_setsockopt (pull, ZMQ_SOCKS_USERNAME, username,
username == NULL ? 0 : strlen (username));
TEST_ASSERT_SUCCESS_ERRNO (res);
res = zmq_setsockopt (pull, ZMQ_SOCKS_PASSWORD, password,
password == NULL ? 0 : strlen (password));
TEST_ASSERT_SUCCESS_ERRNO (res);
res = zmq_connect (pull, connect_address);
TEST_ASSERT_SUCCESS_ERRNO (res);
fprintf (stderr, "pull_client: connected to: %s\n", connect_address);
return pull;
}
#endif
void communicate (void *push, void *pull)
{
fprintf (stderr, "push_server: sending 2 messages\n");
s_send_seq (push, "ABC", SEQ_END);
s_send_seq (push, "DEF", SEQ_END);
fprintf (stderr, "pull_client: receiving 2 messages\n");
s_recv_seq (pull, "ABC", SEQ_END);
s_recv_seq (pull, "DEF", SEQ_END);
}
void test_socks_no_socks (void)
{
char connect_address[MAX_SOCKET_STRING];
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client (connect_address, NULL);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
}
void test_socks (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client (connect_address, socks_server_address);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_delay (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client (connect_address, socks_server_address);
void *thread = zmq_threadstart (&socks_server_no_auth_delay, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_domainname (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
char connect_address_hostname[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
// Will be resolved by the proxy test server to 127.0.0.1
strcpy (connect_address_hostname, "tcp://somedomainname.org");
strcat (connect_address_hostname, strrchr (connect_address, ':'));
void *pull =
setup_pull_client (connect_address_hostname, socks_server_address);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_ipv6 (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
char connect_address_hostname[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
// Will be resolved by the proxy test server to 127.0.0.1
strcpy (connect_address_hostname, "tcp://::1");
strcat (connect_address_hostname, strrchr (connect_address, ':'));
void *pull =
setup_pull_client (connect_address_hostname, socks_server_address);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_ipv6_sb (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
char connect_address_hostname[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
// Will be resolved by the proxy test server to 127.0.0.1
strcpy (connect_address_hostname, "tcp://[::1]");
strcat (connect_address_hostname, strrchr (connect_address, ':'));
void *pull =
setup_pull_client (connect_address_hostname, socks_server_address);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_bind_before_connect (void)
{
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
char socks_address_bind_before_connect[MAX_SOCKET_STRING * 2];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
// Will do a bind before connect when connecting to proxy
strcpy (socks_address_bind_before_connect, "127.0.0.1:0;");
strcat (socks_address_bind_before_connect, socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull =
setup_pull_client (connect_address, socks_address_bind_before_connect);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
}
void test_socks_basic_auth (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (
connect_address, socks_server_address, "someuser", "somepass");
void *thread = zmq_threadstart (&socks_server_basic_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_socks_basic_auth_delay (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (
connect_address, socks_server_address, "someuser", "somepass");
void *thread = zmq_threadstart (&socks_server_basic_auth_delay, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_socks_basic_auth_empty_user (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (connect_address,
socks_server_address, "", NULL);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_socks_basic_auth_null_user (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (connect_address,
socks_server_address, NULL, NULL);
void *thread = zmq_threadstart (&socks_server_no_auth, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_socks_basic_auth_empty_pass (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (
connect_address, socks_server_address, "someuser", "");
void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_socks_basic_auth_null_pass (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char socks_server_address[MAX_SOCKET_STRING];
char connect_address[MAX_SOCKET_STRING];
void *socks =
setup_socks_server (socks_server_address, sizeof socks_server_address);
void *push = setup_push_server (connect_address, sizeof connect_address);
void *pull = setup_pull_client_with_auth (
connect_address, socks_server_address, "someuser", NULL);
void *thread = zmq_threadstart (&socks_server_basic_auth_no_pass, socks);
communicate (push, pull);
test_context_socket_close_zero_linger (push);
test_context_socket_close_zero_linger (pull);
zmq_threadclose (thread);
#else
TEST_IGNORE_MESSAGE (
"libzmq without DRAFT support, ignoring socks basic auth test");
#endif
}
void test_string_opt_ok (const char *msg, int opt, const char *value)
{
int res;
void *sub = test_context_socket (ZMQ_SUB);
fprintf (stderr, "test_string_opt_ok: testing %s\n", msg);
res = zmq_setsockopt (sub, opt, value, strlen (value));
TEST_ASSERT_SUCCESS_ERRNO (res);
char buffer[1024];
size_t res_len = (size_t) sizeof buffer;
res = zmq_getsockopt (sub, opt, buffer, &res_len);
TEST_ASSERT_SUCCESS_ERRNO (res);
TEST_ASSERT_EQUAL (strlen (value) + 1, res_len);
TEST_ASSERT (strcmp (buffer, value) == 0);
test_context_socket_close_zero_linger (sub);
}
void test_opt_ok (const char *msg,
int opt,
const char *value,
size_t len,
const char *expected_value,
size_t expected_len)
{
int res;
void *sub = test_context_socket (ZMQ_SUB);
fprintf (stderr, "test_opt_ok: testing %s\n", msg);
res = zmq_setsockopt (sub, opt, value, len);
TEST_ASSERT_SUCCESS_ERRNO (res);
char buffer[1024];
size_t res_len = (size_t) sizeof buffer;
res = zmq_getsockopt (sub, opt, buffer, &res_len);
TEST_ASSERT_SUCCESS_ERRNO (res);
TEST_ASSERT_EQUAL (expected_len + 1, res_len);
TEST_ASSERT_EQUAL (expected_len, strlen (buffer));
TEST_ASSERT (strncmp (buffer, expected_value, expected_len) == 0);
test_context_socket_close_zero_linger (sub);
}
void test_opt_invalid (const char *msg, int opt, const char *value, int len)
{
int res;
void *sub = test_context_socket (ZMQ_SUB);
fprintf (stderr, "test_opt_invalid: testing %s\n", msg);
res = zmq_setsockopt (sub, opt, value, len);
TEST_ASSERT_FAILURE_ERRNO (EINVAL, res);
test_context_socket_close_zero_linger (sub);
}
void test_socks_proxy_options (void)
{
// NULL is equivalent to not set and returns empty string
test_opt_ok ("NULL proxy", ZMQ_SOCKS_PROXY, NULL, 0, "", 0);
test_string_opt_ok ("valid proxy", ZMQ_SOCKS_PROXY, "somehost:1080");
// Empty value not allowed for proxy server
test_opt_invalid ("empty proxy", ZMQ_SOCKS_PROXY, "", 0);
}
void test_socks_userpass_options (void)
{
#ifdef ZMQ_BUILD_DRAFT_API
char buffer[1024];
for (int i = 0; i < (int) sizeof buffer; i++) {
buffer[i] = 'a' + i % 26;
}
// NULL is equivalent to not-set or ""
test_opt_ok ("NULL username", ZMQ_SOCKS_USERNAME, NULL, 0, "", 0);
// Empty value is allowed for username, means no authentication
test_string_opt_ok ("empty username", ZMQ_SOCKS_USERNAME, "");
test_string_opt_ok ("valid username", ZMQ_SOCKS_USERNAME, "someuser");
test_opt_ok ("255 bytes username", ZMQ_SOCKS_USERNAME, buffer, 255, buffer,
255);
test_opt_invalid ("too long username", ZMQ_SOCKS_USERNAME, buffer, 256);
// NULL is equivalent to not-set or ""
test_opt_ok ("NULL password", ZMQ_SOCKS_PASSWORD, NULL, 0, "", 0);
// Empty value allowed for password
test_string_opt_ok ("empty password", ZMQ_SOCKS_PASSWORD, "");
test_string_opt_ok ("valid password", ZMQ_SOCKS_PASSWORD, "someuser");
test_opt_ok ("255 bytes password", ZMQ_SOCKS_PASSWORD, buffer, 255, buffer,
255);
test_opt_invalid ("too long password", ZMQ_SOCKS_PASSWORD, buffer, 256);
#else
TEST_IGNORE_MESSAGE ("libzmq without DRAFT support, ignoring socks setopt "
"username/password test");
#endif
}
int main ()
{
setup_test_environment (180);
UNITY_BEGIN ();
RUN_TEST (test_socks_proxy_options);
RUN_TEST (test_socks_userpass_options);
RUN_TEST (test_socks_no_socks);
RUN_TEST (test_socks);
RUN_TEST (test_socks_delay);
RUN_TEST (test_socks_domainname);
RUN_TEST (test_socks_ipv6);
RUN_TEST (test_socks_ipv6_sb);
RUN_TEST (test_socks_bind_before_connect);
RUN_TEST (test_socks_basic_auth);
RUN_TEST (test_socks_basic_auth_delay);
RUN_TEST (test_socks_basic_auth_empty_user);
RUN_TEST (test_socks_basic_auth_null_user);
RUN_TEST (test_socks_basic_auth_empty_pass);
RUN_TEST (test_socks_basic_auth_null_pass);
return UNITY_END ();
}