mirror of
https://github.com/oxen-io/oxen-mq.git
synced 2023-12-13 21:00:31 +01:00
57f0ca74da
The existing code was largely set up for SN-to-SN or client-to-SN communications, where messages can always get to the right place because we can always send by pubkey. This doesn't work when we want general communications with a random remote address. This commit overhauls the way loki-mq handles communication in a few important ways: - Listening instances no longer pass bind addresses into the constructor; instead they call `listen_curve()` or `listen_plain()` before invoking `start()`. - `listen_curve()` is equivalent to the existing bind support: it listens on a socket and accepts encrypted handshaked connections from anyone who already knows the server's public key. - `listen_plain()` is all new: it sets up a plain text listening socket over which random clients can connect and talk. End-points aren't verified, and it isn't encrypted, but if you don't know who you are talking to then encryption isn't doing anything anyway. - Connecting to a remote now connections in CURVE encryption or NULL (plain-text) encryption based on whether you provide a remote_pubkey. For CURVE, the connection will fail if the pubkey does not match. - `ConnectionID` objects are now returned when connecting to a remote address; this object is then passed in to send/request/etc. to direct the message. For SN communication, ConnectionID's can be created implicitly from SN pubkey strings, so the existing interface of `lmq.send(pubkey, ...)` will still work in most cases. - A ConnectionID is now passed to the ConnectSuccess and ConnectFailure callbacks. This can be used to uniquely identify which connection succeeded or failed, and can determine whether the remote is a service node (`.sn()`) and/or the pubkey (`.pubkey()`). (Obviously the service node status is only available when the client can do service node lookups, and the pubkey() is only non-empty for encrypted connections).
121 lines
3.5 KiB
C++
121 lines
3.5 KiB
C++
#include "common.h"
|
|
#include <future>
|
|
#include <lokimq/hex.h>
|
|
|
|
using namespace lokimq;
|
|
|
|
TEST_CASE("basic requests", "[requests]") {
|
|
std::string listen = "tcp://127.0.0.1:5678";
|
|
LokiMQ server{
|
|
"", "", // generate ephemeral keys
|
|
false, // not a service node
|
|
[](auto) { return ""; },
|
|
};
|
|
server.listen_curve(listen);
|
|
|
|
std::atomic<int> hellos{0}, his{0};
|
|
|
|
server.add_category("public", Access{AuthLevel::none});
|
|
server.add_request_command("public", "hello", [&](Message& m) {
|
|
m.send_reply("123");
|
|
});
|
|
server.start();
|
|
|
|
LokiMQ client(
|
|
[](LogLevel, const char* file, int line, std::string msg) { std::cerr << file << ":" << line << " --C-- " << msg << "\n"; }
|
|
);
|
|
//client.log_level(LogLevel::trace);
|
|
|
|
client.start();
|
|
|
|
std::atomic<bool> connected{false}, failed{false};
|
|
std::string pubkey;
|
|
|
|
auto c = client.connect_remote(listen,
|
|
[&](auto conn) { pubkey = conn.pubkey(); connected = true; },
|
|
[&](auto, auto) { failed = true; },
|
|
server.get_pubkey());
|
|
|
|
int i;
|
|
for (i = 0; i < 5; i++) {
|
|
if (connected.load())
|
|
break;
|
|
std::this_thread::sleep_for(50ms);
|
|
}
|
|
REQUIRE( connected.load() );
|
|
REQUIRE( !failed.load() );
|
|
REQUIRE( i <= 1 );
|
|
REQUIRE( to_hex(pubkey) == to_hex(server.get_pubkey()) );
|
|
|
|
std::atomic<bool> got_reply{false};
|
|
bool success;
|
|
std::vector<std::string> data;
|
|
client.request(c, "public.hello", [&](bool ok, std::vector<std::string> data_) {
|
|
got_reply = true;
|
|
success = ok;
|
|
data = std::move(data_);
|
|
});
|
|
|
|
std::this_thread::sleep_for(50ms);
|
|
REQUIRE( got_reply.load() );
|
|
REQUIRE( success );
|
|
REQUIRE( data == std::vector<std::string>{{"123"}} );
|
|
}
|
|
|
|
TEST_CASE("request from server to client", "[requests]") {
|
|
std::string listen = "tcp://127.0.0.1:5678";
|
|
LokiMQ server{
|
|
"", "", // generate ephemeral keys
|
|
false, // not a service node
|
|
[](auto) { return ""; },
|
|
};
|
|
server.listen_curve(listen);
|
|
|
|
std::atomic<int> hellos{0}, his{0};
|
|
|
|
server.add_category("public", Access{AuthLevel::none});
|
|
server.add_request_command("public", "hello", [&](Message& m) {
|
|
m.send_reply("123");
|
|
});
|
|
server.start();
|
|
|
|
LokiMQ client(
|
|
[](LogLevel, const char* file, int line, std::string msg) { std::cerr << file << ":" << line << " --C-- " << msg << "\n"; }
|
|
);
|
|
//client.log_level(LogLevel::trace);
|
|
|
|
client.start();
|
|
|
|
std::atomic<bool> connected{false}, failed{false};
|
|
std::string pubkey;
|
|
|
|
auto c = client.connect_remote(listen,
|
|
[&](auto conn) { pubkey = conn.pubkey(); connected = true; },
|
|
[&](auto, auto) { failed = true; },
|
|
server.get_pubkey());
|
|
|
|
int i;
|
|
for (i = 0; i < 5; i++) {
|
|
if (connected.load())
|
|
break;
|
|
std::this_thread::sleep_for(50ms);
|
|
}
|
|
REQUIRE( connected.load() );
|
|
REQUIRE( !failed.load() );
|
|
REQUIRE( i <= 1 );
|
|
REQUIRE( to_hex(pubkey) == to_hex(server.get_pubkey()) );
|
|
|
|
std::atomic<bool> got_reply{false};
|
|
bool success;
|
|
std::vector<std::string> data;
|
|
client.request(c, "public.hello", [&](bool ok, std::vector<std::string> data_) {
|
|
got_reply = true;
|
|
success = ok;
|
|
data = std::move(data_);
|
|
});
|
|
|
|
std::this_thread::sleep_for(50ms);
|
|
REQUIRE( got_reply.load() );
|
|
REQUIRE( success );
|
|
REQUIRE( data == std::vector<std::string>{{"123"}} );
|
|
}
|