-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
C++ OakSessionClient/OakSessionServer implementations
OakServer provides initialized channels using an underlying OakServerSession. OakClient provides initialized channels using an underlying OakClientSession. Both implementations use an underlying OakChannel implementation. The channel implementation is templatized on send/receive types, so the same implementation can be used for both by switching the send/receive message types, and changing the underlying session type. I wanted to add error contexts in many places, so I created a simple absl::Status annotater to help as part of this CR. Fixed: b/382733114 Fixed: b/356398548 Fixed: b/382481589 Change-Id: I0da73930e9dd9005be2c5803c875f7bb0092196b
- Loading branch information
Showing
13 changed files
with
796 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright 2024 The Project Oak Authors | ||
* | ||
* 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 "cc/client/session_client.h" | ||
|
||
#include "absl/status/status.h" | ||
#include "absl/status/statusor.h" | ||
#include "cc/oak_session/client_session.h" | ||
#include "cc/utils/status/status.h" | ||
#include "proto/session/session.pb.h" | ||
|
||
namespace oak::client { | ||
|
||
absl::StatusOr<std::unique_ptr<OakSessionClient::Channel>> | ||
OakSessionClient::NewChannel(std::unique_ptr<Channel::Transport> transport) { | ||
absl::StatusOr<std::unique_ptr<session::ClientSession>> session = | ||
session::ClientSession::Create(); | ||
|
||
while (!(*session)->IsOpen()) { | ||
absl::StatusOr<std::optional<session::v1::SessionRequest>> init_request = | ||
(*session)->GetOutgoingMessage(); | ||
if (!init_request.ok()) { | ||
return util::status::Annotate( | ||
init_request.status(), | ||
"Failed to get outgoing message from state machine"); | ||
} | ||
|
||
if (*init_request == std::nullopt) { | ||
return absl::InternalError("No outgoing message but session not open"); | ||
} | ||
|
||
absl::Status send_result = transport->Send(**init_request); | ||
if (!send_result.ok()) { | ||
return util::status::Annotate(send_result, | ||
"Failed to send outgoing message"); | ||
} | ||
|
||
// Some initialization seqeuences may end with the client sending a final | ||
// request but not expecting any response from the server. | ||
if ((*session)->IsOpen()) { | ||
break; | ||
} | ||
|
||
absl::StatusOr<session::v1::SessionResponse> init_response = | ||
transport->Receive(); | ||
if (!init_response.ok()) { | ||
return util::status::Annotate( | ||
init_request.status(), | ||
"Failed to get next init response from server"); | ||
} | ||
|
||
absl::Status put_result = (*session)->PutIncomingMessage(*init_response); | ||
if (!put_result.ok()) { | ||
return util::status::Annotate( | ||
put_result, | ||
"Failed to put next init response in session state machine"); | ||
} | ||
} | ||
|
||
// Need to call private constructor, so WrapUnique instead of make_unique. | ||
return absl::WrapUnique( | ||
new Channel(std::move(*session), std::move(transport))); | ||
} | ||
|
||
} // namespace oak::client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright 2024 The Project Oak Authors | ||
* | ||
* 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 CC_CLIENT_SESSION_CLIENT_H_ | ||
#define CC_CLIENT_SESSION_CLIENT_H_ | ||
|
||
#include "absl/status/status.h" | ||
#include "absl/status/statusor.h" | ||
#include "cc/oak_session/channel/oak_session_channel.h" | ||
#include "cc/oak_session/client_session.h" | ||
#include "proto/session/session.pb.h" | ||
|
||
namespace oak::client { | ||
|
||
class OakSessionClient { | ||
public: | ||
// OakClientChannel manages an established connection between a client and | ||
// server that communicate using the Noise Protocol via an Oak Session. | ||
using Channel = | ||
session::channel::OakSessionChannel<session::v1::SessionRequest, | ||
session::v1::SessionResponse, | ||
session::ClientSession>; | ||
|
||
OakSessionClient() = default; | ||
|
||
// Create a new OakClientChannel instance with the provided session and | ||
// transport. | ||
// | ||
// client_session should be a newly created ClientSession instance with a | ||
// configuration that matches the configuration of the target server. | ||
// | ||
// The call will block during the initialization sequence, and return an open | ||
// channel that is ready to use, or return an error if the handshake didn't | ||
// succeed. | ||
absl::StatusOr<std::unique_ptr<OakSessionClient::Channel>> NewChannel( | ||
std::unique_ptr<OakSessionClient::Channel::Transport> transport); | ||
}; | ||
|
||
} // namespace oak::client | ||
|
||
#endif // CC_CLIENT_SESSION_CLIENT_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* Copyright 2024 The Project Oak Authors | ||
* | ||
* 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 "cc/client/session_client.h" | ||
|
||
#include "absl/status/status_matchers.h" | ||
#include "cc/oak_session/client_session.h" | ||
#include "cc/oak_session/server_session.h" | ||
#include "gmock/gmock.h" | ||
#include "gtest/gtest.h" | ||
|
||
namespace oak::client { | ||
namespace { | ||
|
||
using ::absl_testing::IsOk; | ||
using ::testing::Eq; | ||
using ::testing::Ne; | ||
using ::testing::Optional; | ||
|
||
class TestTransport : public OakSessionClient::Channel::Transport { | ||
public: | ||
TestTransport(std::unique_ptr<session::ServerSession> server_session) | ||
: server_session_(std::move(server_session)) {} | ||
absl::Status Send(const session::v1::SessionRequest& request) override { | ||
return server_session_->PutIncomingMessage(request); | ||
} | ||
absl::StatusOr<session::v1::SessionResponse> Receive() override { | ||
absl::StatusOr<std::optional<session::v1::SessionResponse>> msg = | ||
server_session_->GetOutgoingMessage(); | ||
if (!msg.ok()) { | ||
return msg.status(); | ||
} | ||
if (*msg == std::nullopt) { | ||
return absl::FailedPreconditionError("expected outgoing server message"); | ||
} | ||
return **msg; | ||
} | ||
|
||
private: | ||
std::unique_ptr<session::ServerSession> server_session_; | ||
}; | ||
|
||
TEST(OakSessionClientTest, CreateSuccessFullyHandshakes) { | ||
auto server_session = session::ServerSession::Create(); | ||
ASSERT_THAT(server_session, IsOk()); | ||
auto client_session = session::ClientSession::Create(); | ||
ASSERT_THAT(client_session, IsOk()); | ||
auto _ = OakSessionClient().NewChannel( | ||
std::make_unique<TestTransport>(std::move(*server_session))); | ||
} | ||
|
||
TEST(OakSessionClientTest, CreatedSessionCanSend) { | ||
auto server_session = session::ServerSession::Create(); | ||
// Hold a pointer for testing behavior below. | ||
session::ServerSession* server_session_ptr = server_session->get(); | ||
ASSERT_THAT(server_session, IsOk()); | ||
auto client_session = session::ClientSession::Create(); | ||
ASSERT_THAT(client_session, IsOk()); | ||
auto channel = OakSessionClient().NewChannel( | ||
std::make_unique<TestTransport>(std::move(*server_session))); | ||
|
||
std::string test_send_msg = "Testing Send"; | ||
ASSERT_THAT((*channel)->Send(test_send_msg), IsOk()); | ||
absl::StatusOr<std::optional<std::string>> test_send_read_back = | ||
server_session_ptr->Read(); | ||
EXPECT_THAT(test_send_read_back, IsOk()); | ||
EXPECT_THAT(*test_send_read_back, Optional(Eq(test_send_msg))); | ||
} | ||
|
||
TEST(OakSessionClientTest, CreatedSessionCanReceive) { | ||
auto server_session = session::ServerSession::Create(); | ||
// Hold a pointer for testing behavior below. | ||
session::ServerSession* server_session_ptr = server_session->get(); | ||
ASSERT_THAT(server_session, IsOk()); | ||
auto client_session = session::ClientSession::Create(); | ||
ASSERT_THAT(client_session, IsOk()); | ||
auto channel = OakSessionClient().NewChannel( | ||
std::make_unique<TestTransport>(std::move(*server_session))); | ||
|
||
std::string test_recv_msg = "Testing Receive"; | ||
ASSERT_THAT(server_session_ptr->Write(test_recv_msg), IsOk()); | ||
|
||
absl::StatusOr<std::string> server_read = (*channel)->Receive(); | ||
EXPECT_THAT(server_read, IsOk()); | ||
EXPECT_THAT(*server_read, Eq(test_recv_msg)); | ||
} | ||
} // namespace | ||
} // namespace oak::client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# | ||
# Copyright 2022 The Project Oak Authors | ||
# | ||
# 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. | ||
# | ||
|
||
package( | ||
default_visibility = ["//:default_visibility"], | ||
licenses = ["notice"], | ||
) | ||
|
||
cc_library( | ||
name = "channel", | ||
hdrs = ["oak_session_channel.h"], | ||
deps = [ | ||
"//cc/utils/status", | ||
"@com_google_absl//absl/status", | ||
"@com_google_absl//absl/status:statusor", | ||
"@com_google_absl//absl/strings", | ||
], | ||
) |
Oops, something went wrong.