blob: 65c5dabb6a3a8f3e7b7c6d733dbb82e64f0e025f [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 <sstream>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <vsomeip/defines.hpp>
#include <vsomeip/logger.hpp>
#include "../include/server_endpoint_impl.hpp"
#include "../../configuration/include/internal.hpp"
#include "../../utility/include/byteorder.hpp"
#include "../../utility/include/utility.hpp"
namespace vsomeip {
template<typename Protocol, int MaxBufferSize>
server_endpoint_impl<Protocol, MaxBufferSize>::server_endpoint_impl(
std::shared_ptr<endpoint_host> _host, endpoint_type _local,
boost::asio::io_service &_io)
: endpoint_impl<MaxBufferSize>(_host, _io),
flush_timer_(_io) {
}
template<typename Protocol, int MaxBufferSize>
bool server_endpoint_impl<Protocol, MaxBufferSize>::is_client() const {
return false;
}
template<typename Protocol, int MaxBufferSize>
bool server_endpoint_impl<Protocol, MaxBufferSize>::is_connected() const {
return true;
}
template<typename Protocol, int MaxBufferSize>
bool server_endpoint_impl<Protocol, MaxBufferSize>::send(
const uint8_t *_data, uint32_t _size, bool _flush) {
#if 0
std::stringstream msg;
msg << "sei::send ";
for (uint32_t i = 0; i < _size; i++)
msg << std::setw(2) << std::setfill('0') << (int)_data[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
endpoint_type its_target;
bool is_valid_target(false);
if (VSOMEIP_SESSION_POS_MAX < _size) {
std::unique_lock < std::mutex > its_lock(mutex_);
service_t its_service;
std::memcpy(&its_service, &_data[VSOMEIP_SERVICE_POS_MIN],
sizeof(service_t));
client_t its_client;
std::memcpy(&its_client, &_data[VSOMEIP_CLIENT_POS_MIN], sizeof(client_t));
session_t its_session;
std::memcpy(&its_session, &_data[VSOMEIP_SESSION_POS_MIN],
sizeof(session_t));
auto found_client = clients_.find(its_client);
if (found_client != clients_.end()) {
auto found_session = found_client->second.find(its_session);
if (found_session != found_client->second.end()) {
its_target = found_session->second;
is_valid_target = true;
}
} else {
event_t its_event = VSOMEIP_BYTES_TO_WORD(_data[VSOMEIP_METHOD_POS_MIN],
_data[VSOMEIP_METHOD_POS_MAX]);
is_valid_target = get_multicast(its_service, its_event, its_target);
}
if (is_valid_target) {
is_valid_target = send_intern(its_target, _data, _size, _flush);
}
}
return is_valid_target;
}
template<typename Protocol, int MaxBufferSize>
bool server_endpoint_impl<Protocol, MaxBufferSize>::send_intern(endpoint_type _target,
const byte_t *_data, uint32_t _size, bool _flush) {
std::shared_ptr < std::vector<byte_t> > target_packetizer;
auto found_packetizer = packetizer_.find(_target);
if (found_packetizer != packetizer_.end()) {
target_packetizer = found_packetizer->second;
} else {
target_packetizer = std::make_shared<message_buffer_t>();
packetizer_.insert(
std::make_pair(_target, target_packetizer));
}
if (target_packetizer->size() + _size > MaxBufferSize) {
send_queued(_target, target_packetizer);
packetizer_[_target] = std::make_shared<message_buffer_t>();
}
target_packetizer->insert(
target_packetizer->end(), _data, _data + _size);
if (_flush) {
flush_timer_.cancel();
send_queued(_target, target_packetizer);
packetizer_[_target] = std::make_shared<message_buffer_t>();
} else {
std::chrono::milliseconds flush_timeout(VSOMEIP_DEFAULT_FLUSH_TIMEOUT);
flush_timer_.expires_from_now(flush_timeout); // TODO: use configured value
flush_timer_.async_wait(
std::bind(
&server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk,
this->shared_from_this(), _target,
std::placeholders::_1));
}
return true;
}
template<typename Protocol, int MaxBufferSize>
bool server_endpoint_impl<Protocol, MaxBufferSize>::flush(
endpoint_type _target) {
bool is_flushed = false;
std::unique_lock < std::mutex > its_lock(mutex_);
auto i = packetizer_.find(_target);
if (i != packetizer_.end() && !i->second->empty()) {
send_queued(_target, i->second);
i->second = std::make_shared<message_buffer_t>();
is_flushed = true;
}
return is_flushed;
}
template<typename Protocol, int MaxBufferSize>
void server_endpoint_impl<Protocol, MaxBufferSize>::connect_cbk(
boost::system::error_code const &_error) {
}
template<typename Protocol, int MaxBufferSize>
void server_endpoint_impl<Protocol, MaxBufferSize>::send_cbk(
message_buffer_ptr_t _buffer, boost::system::error_code const &_error,
std::size_t _bytes) {
#if 0
std::stringstream msg;
msg << "sei::scb (" << _error.message() << "): ";
for (std::size_t i = 0; i < _buffer->size(); ++i)
msg << std::hex << std::setw(2) << std::setfill('0') << (int)(*_buffer)[i] << " ";
VSOMEIP_DEBUG << msg.str();
#endif
}
template<typename Protocol, int MaxBufferSize>
void server_endpoint_impl<Protocol, MaxBufferSize>::flush_cbk(
endpoint_type _target, const boost::system::error_code &_error_code) {
if (!_error_code) {
(void) flush(_target);
}
}
// Instantiate template
#ifndef __WINDOWS__
template class server_endpoint_impl<boost::asio::local::stream_protocol,
VSOMEIP_MAX_LOCAL_MESSAGE_SIZE> ;
#else
// TODO: put instantiation for windows here!
#endif
template class server_endpoint_impl<boost::asio::ip::tcp,
VSOMEIP_MAX_TCP_MESSAGE_SIZE> ;
template class server_endpoint_impl<boost::asio::ip::udp,
VSOMEIP_MAX_UDP_MESSAGE_SIZE> ;
} // namespace vsomeip