blob: 2f44baf1d922c13e802da413a70e21c2dec2b66e [file] [log] [blame]
// Copyright (C) 2014 BMW Group
// Author: Lutz Bichler (lutz.bichler@bmw.de)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <iomanip>
#include <boost/asio/write.hpp>
#include <vsomeip/constants.hpp>
#include <vsomeip/defines.hpp>
#include <vsomeip/logger.hpp>
#include "../include/endpoint_host.hpp"
#include "../include/tcp_client_endpoint_impl.hpp"
#include "../../utility/include/utility.hpp"
namespace ip = boost::asio::ip;
namespace vsomeip {
tcp_client_endpoint_impl::tcp_client_endpoint_impl(
std::shared_ptr< endpoint_host > _host, endpoint_type _remote, boost::asio::io_service &_io)
: tcp_client_endpoint_base_impl(_host, _remote, _io) {
is_supporting_magic_cookies_ = true;
}
tcp_client_endpoint_impl::~tcp_client_endpoint_impl() {
}
void tcp_client_endpoint_impl::start() {
connect();
}
void tcp_client_endpoint_impl::connect() {
socket_.open(remote_.protocol());
// Nagle algorithm off
ip::tcp::no_delay option;
socket_.set_option(option);
socket_.async_connect(
remote_,
std::bind(
&tcp_client_endpoint_base_impl::connect_cbk,
shared_from_this(),
std::placeholders::_1
)
);
}
void tcp_client_endpoint_impl::receive() {
packet_buffer_ptr_t its_buffer
= std::make_shared< packet_buffer_t >();
socket_.async_receive(
boost::asio::buffer(*its_buffer),
std::bind(
&tcp_client_endpoint_impl::receive_cbk,
std::dynamic_pointer_cast< tcp_client_endpoint_impl >(shared_from_this()),
its_buffer,
std::placeholders::_1,
std::placeholders::_2
)
);
}
void tcp_client_endpoint_impl::send_queued(message_buffer_ptr_t _buffer) {
if (has_enabled_magic_cookies_)
send_magic_cookie(_buffer);
boost::asio::async_write(
socket_,
boost::asio::buffer(*_buffer),
std::bind(
&tcp_client_endpoint_base_impl::send_cbk,
shared_from_this(),
_buffer,
std::placeholders::_1,
std::placeholders::_2
)
);
}
unsigned short tcp_client_endpoint_impl::get_port() const {
return socket_.local_endpoint().port();
}
bool tcp_client_endpoint_impl::is_reliable() const {
return true;
}
bool tcp_client_endpoint_impl::is_magic_cookie() const {
return (0 == std::memcmp(SERVICE_COOKIE, &message_[0], sizeof(SERVICE_COOKIE)));
}
void tcp_client_endpoint_impl::send_magic_cookie(message_buffer_ptr_t &_buffer) {
if (VSOMEIP_MAX_TCP_MESSAGE_SIZE - _buffer->size() >=
VSOMEIP_SOMEIP_HEADER_SIZE + VSOMEIP_SOMEIP_MAGIC_COOKIE_SIZE) {
_buffer->insert(
_buffer->begin(),
CLIENT_COOKIE,
CLIENT_COOKIE + sizeof(CLIENT_COOKIE)
);
} else {
VSOMEIP_WARNING << "Packet full. Cannot insert magic cookie!";
}
}
void tcp_client_endpoint_impl::receive_cbk(
packet_buffer_ptr_t _buffer,
boost::system::error_code const &_error, std::size_t _bytes) {
#if 0
std::stringstream msg;
msg << "cei::rcb (" << _error.message() << "): ";
for (std::size_t i = 0; i < _bytes; ++i)
msg << std::hex << std::setw(2) << std::setfill('0') << (int)(*_buffer)[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
if (!_error && 0 < _bytes) {
this->message_.insert(this->message_.end(), _buffer->begin(), _buffer->begin() + _bytes);
bool has_full_message;
do {
uint32_t current_message_size = utility::get_message_size(this->message_);
has_full_message = (current_message_size > 0 && current_message_size <= this->message_.size());
if (has_full_message) {
if (is_magic_cookie()) {
has_enabled_magic_cookies_ = true;
} else {
host_->on_message(&this->message_[0], current_message_size, this);
}
this->message_.erase(this->message_.begin(), this->message_.begin() + current_message_size);
} else if (has_enabled_magic_cookies_ && this->message_.size() > 0){
// Note that the following will be done each time a message
// is not (yet) completely available. If no magic cookie can
// be found, the message data is not touched.
has_full_message = resync_on_magic_cookie(message_);
} else if (message_.size() > VSOMEIP_MAX_TCP_MESSAGE_SIZE) {
VSOMEIP_ERROR << "Message exceeds maximum message size. Resetting receiver.";
this->message_.clear();
}
} while (has_full_message);
restart();
} else {
receive();
}
}
} // namespace vsomeip