blob: e11b85b32193a8c069e39778ef927def4fa45182 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/impl/tls_connection_posix.h"
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <openssl/ssl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <memory>
#include "absl/types/optional.h"
#include "absl/types/span.h"
#include "platform/api/logging.h"
#include "platform/base/error.h"
#include "platform/impl/stream_socket.h"
#include "util/crypto/openssl_util.h"
namespace openscreen {
namespace platform {
// TODO(jophba, rwkeane): implement reading
// TODO(jophba, rwkeane): implement write blocking/unblocking
TlsConnectionPosix::TlsConnectionPosix(IPEndpoint local_address,
TaskRunner* task_runner)
: TlsConnection(task_runner),
socket_(std::make_unique<StreamSocketPosix>(local_address)),
buffer_(this) {}
TlsConnectionPosix::TlsConnectionPosix(IPAddress::Version version,
TaskRunner* task_runner)
: TlsConnection(task_runner),
socket_(std::make_unique<StreamSocketPosix>(version)),
buffer_(this) {}
TlsConnectionPosix::TlsConnectionPosix(std::unique_ptr<StreamSocket> socket,
TaskRunner* task_runner)
: TlsConnection(task_runner), socket_(std::move(socket)), buffer_(this) {}
TlsConnectionPosix::~TlsConnectionPosix() = default;
void TlsConnectionPosix::Write(const void* data, size_t len) {
// TODO(jophba, rwkeane): implement this method.
OSP_UNIMPLEMENTED();
}
const IPEndpoint& TlsConnectionPosix::local_address() const {
const absl::optional<IPEndpoint> endpoint = socket_->local_address();
OSP_DCHECK(endpoint.has_value());
return endpoint.value();
}
const IPEndpoint& TlsConnectionPosix::remote_address() const {
const absl::optional<IPEndpoint> endpoint = socket_->remote_address();
OSP_DCHECK(endpoint.has_value());
return endpoint.value();
}
void TlsConnectionPosix::NotifyWriteBufferFill(double fraction) {
constexpr double kBlockBufferPercentage = 0.5;
if (fraction > kBlockBufferPercentage && !is_buffer_blocked_) {
OnWriteBlocked();
is_buffer_blocked_ = true;
} else if (fraction < kBlockBufferPercentage && is_buffer_blocked_) {
OnWriteUnblocked();
is_buffer_blocked_ = false;
} else if (fraction >= 0.99 && is_buffer_blocked_) {
OnError(Error::Code::kInsufficientBuffer);
}
}
void TlsConnectionPosix::SendAvailableBytes() {
absl::Span<const uint8_t> sendable_bytes = buffer_.GetReadableRegion();
if (sendable_bytes.empty()) {
return;
}
const int result =
SSL_write(ssl_.get(), sendable_bytes.data(), sendable_bytes.size());
if (result <= 0) {
const Error result_error = GetSSLError(ssl_.get(), result);
if (!result_error.ok() && (result_error.code() != Error::Code::kAgain)) {
OnError(result_error);
}
} else {
buffer_.Consume(static_cast<size_t>(result));
}
}
} // namespace platform
} // namespace openscreen