Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ if(AE_BUILD_EXAMPLES)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

add_subdirectory(examples/cloud)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_subdirectory(examples/windows_message_receiver)
endif()
add_subdirectory(examples/capi/oddity)
add_subdirectory(examples/benches/send_message_delays)
add_subdirectory(examples/benches/send_messages_bandwidth)
Expand Down
3 changes: 3 additions & 0 deletions aether/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ list(APPEND aether_srcs

list(APPEND aether_srcs
"server_connections/client_server_connection.cpp"
"prepared_packet/prepared_send_message.cpp"
"prepared_packet/prepare_send_message.cpp"
"prepared_packet/packet_encoder.cpp"
"server_connections/channel_connection.cpp"
"server_connections/server_connection.cpp")

Expand Down
35 changes: 35 additions & 0 deletions aether/client_messages/p2p_message_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "aether/cloud_connections/cloud_request.h"
#include "aether/cloud_connections/cloud_subscription.h"
#include "aether/cloud_connections/cloud_server_connection.h"

#include "aether/client_messages/client_messages_tele.h"

Expand All @@ -48,6 +49,30 @@ class MessageSendStream final : public IStream<AeMessage, AeMessage> {
}},
request_policy_);
}

std::optional<prepared_packet::PreparedSendMessageBlock>
ExportPreparedSendMessageBlock(Uid target_uid,
std::uint32_t reserve_nonce_count) {
for (auto* sc : cloud_connection_->servers()) {
if (sc == nullptr) {
continue;
}

auto* conn = sc->client_connection();
if (conn == nullptr) {
continue;
}

auto block = conn->ExportPreparedSendMessageBlock(target_uid,
reserve_nonce_count);
if (block) {
return block;
}
}

return std::nullopt;
}

StreamInfo stream_info() const override { return stream_info_; }
OutDataEvent::Subscriber out_data_event() override { return out_data_event_; }
StreamUpdateEvent::Subscriber stream_update_event() override {
Expand Down Expand Up @@ -203,6 +228,16 @@ void P2pStream::WriteOut(DataBuffer const& data) {

Uid const& P2pStream::destination() const { return destination_; }

std::optional<prepared_packet::PreparedSendMessageBlock>
P2pStream::ExportPreparedSendMessageBlock(std::uint32_t reserve_nonce_count) {
if (message_send_stream_ == nullptr) {
return std::nullopt;
}

return message_send_stream_->ExportPreparedSendMessageBlock(
destination_, reserve_nonce_count);
}

void P2pStream::ConnectReceive() {
out_data_sub_ =
handle_.out_data_event().Subscribe(MethodPtr<&P2pStream::WriteOut>{this});
Expand Down
7 changes: 7 additions & 0 deletions aether/client_messages/p2p_message_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#ifndef AETHER_CLIENT_MESSAGES_P2P_MESSAGE_STREAM_H_
#define AETHER_CLIENT_MESSAGES_P2P_MESSAGE_STREAM_H_

#include <cstdint>
#include <optional>

#include "aether/common.h"

#include "aether/ae_context.h"
Expand All @@ -28,6 +31,7 @@
#include "aether/client_messages/p2p_port_handle.h"
#include "aether/cloud_connections/cloud_server_connections.h"
#include "aether/connection_manager/client_cloud_manager.h"
#include "aether/prepared_packet/prepared_send_message.h"

namespace ae {
class Client;
Expand All @@ -54,6 +58,9 @@ class P2pStream final : public ByteIStream {
void WriteOut(DataBuffer const& data);
Uid const& destination() const;

std::optional<prepared_packet::PreparedSendMessageBlock>
ExportPreparedSendMessageBlock(std::uint32_t reserve_nonce_count);

private:
void ConnectReceive();
void ConnectSend();
Expand Down
73 changes: 73 additions & 0 deletions aether/prepared_packet/packet_encoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "aether/prepared_packet/packet_encoder.h"

#include <memory>
#include <utility>

#include "aether/crypto/ikey_provider.h"
#include "aether/crypto/sync_crypto_provider.h"

#include "aether/api_protocol/api_context.h"
#include "aether/api_protocol/sub_api.h"

#include "aether/work_cloud_api/ae_message.h"
#include "aether/work_cloud_api/work_server_api/authorized_api.h"
#include "aether/work_cloud_api/work_server_api/login_api.h"

namespace ae::prepared_packet {
namespace {

class PreparedSendMessageKeyProvider final : public ISyncKeyProvider {
public:
explicit PreparedSendMessageKeyProvider(PreparedSendMessageBlock& block)
: block_{&block} {}

Key GetKey() const override {
return block_->client_to_server_key;
}

CryptoNonce const& Nonce() const override {
return block_->next_nonce;
}

private:
PreparedSendMessageBlock* block_;
};

} // namespace

EncodePacketResult EncodePacket(PreparedSendMessageBlock& block,
DataBuffer const& payload,
DataBuffer& out) {
if (block.nonce_left == 0) {
out.clear();
return EncodePacketResult{EncodePacketError::kNonceExhausted, 0};
}

// Match the existing ClientKeyProvider semantics:
// consume next nonce before encryption.
block.next_nonce.Next();
--block.nonce_left;

auto key_provider =
std::make_unique<PreparedSendMessageKeyProvider>(block);
SyncEncryptProvider encrypt_provider{std::move(key_provider)};

ProtocolContext protocol_context;
LoginApi login_api{protocol_context, encrypt_provider};

auto api_context = ApiContext{login_api};

api_context->login_by_alias(
block.sender_ephemeral_uid,
SubApi<AuthorizedApi>{
[&block, &payload](ApiContext<AuthorizedApi>& auth_api) {
auth_api->send_message(
AeMessage{block.target_uid, DataBuffer{payload}});
}});

out = std::move(api_context).Pack();

return EncodePacketResult{EncodePacketError::kNone, out.size()};
}

} // namespace ae::prepared_packet
21 changes: 21 additions & 0 deletions aether/prepared_packet/packet_encoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Prepared packet encoder.
*
* EncodePacket only builds Aether packet bytes and advances the reserved nonce
* range. It does not send, open sockets, resolve DNS, or know platform
* transport.
*/
#ifndef AETHER_PREPARED_PACKET_PACKET_ENCODER_H_
#define AETHER_PREPARED_PACKET_PACKET_ENCODER_H_

#include "aether/prepared_packet/prepared_send_message.h"

namespace ae::prepared_packet {

EncodePacketResult EncodePacket(PreparedSendMessageBlock& block,
DataBuffer const& payload,
DataBuffer& out);

} // namespace ae::prepared_packet

#endif // AETHER_PREPARED_PACKET_PACKET_ENCODER_H_
28 changes: 28 additions & 0 deletions aether/prepared_packet/prepare_send_message.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2025 Aethernet Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "aether/prepared_packet/prepare_send_message.h"

#include "aether/client_messages/p2p_message_stream.h"

namespace ae::prepared_packet {

std::optional<PreparedSendMessageBlock> PrepareSendMessage(
P2pStream& stream, std::uint32_t reserve_nonce_count) {
return stream.ExportPreparedSendMessageBlock(reserve_nonce_count);
}

} // namespace ae::prepared_packet
37 changes: 37 additions & 0 deletions aether/prepared_packet/prepare_send_message.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2025 Aethernet Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef AETHER_PREPARED_PACKET_PREPARE_SEND_MESSAGE_H_
#define AETHER_PREPARED_PACKET_PREPARE_SEND_MESSAGE_H_

#include <cstdint>
#include <optional>

#include "aether/prepared_packet/prepared_send_message.h"

namespace ae {

class P2pStream;

namespace prepared_packet {

std::optional<PreparedSendMessageBlock> PrepareSendMessage(
P2pStream& stream, std::uint32_t reserve_nonce_count);

} // namespace prepared_packet
} // namespace ae

#endif // AETHER_PREPARED_PACKET_PREPARE_SEND_MESSAGE_H_
41 changes: 41 additions & 0 deletions aether/prepared_packet/prepared_send_message.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "aether/prepared_packet/prepared_send_message.h"

#include <type_traits>

namespace ae::prepared_packet {

std::optional<PreparedEndpoint> MakePreparedEndpoint(Endpoint const& endpoint) {
PreparedEndpoint candidate;
candidate.protocol = endpoint.protocol;
candidate.port = endpoint.port;

bool is_ip = false;

std::visit(
[&](auto const& addr) {
using T = std::decay_t<decltype(addr)>;

if constexpr (std::is_same_v<T, IpV4Addr>) {
candidate.version = PreparedIpVersion::kIpV4;
for (std::size_t i = 0; i < 4; ++i) {
candidate.ip[i] = addr.ipv4_value[i];
}
is_ip = true;
} else if constexpr (std::is_same_v<T, IpV6Addr>) {
candidate.version = PreparedIpVersion::kIpV6;
for (std::size_t i = 0; i < 16; ++i) {
candidate.ip[i] = addr.ipv6_value[i];
}
is_ip = true;
}
},
endpoint.address);

if (!is_ip) {
return std::nullopt;
}

return candidate;
}

} // namespace ae::prepared_packet
Loading
Loading