10 : m_serverModel(std::move(model)),
26 [
this]() noexcept { m_aliveCheckRetry = 0; }),
32 [
this]() { ++m_aliveCheckRetry;
LOG_DOIP_WARN(
"Alive check #{}/{}", m_aliveCheckRetry, m_aliveCheckRetryCount); }),
50 m_serverModel->onOpenConnection(*
this);
51 m_state = &STATE_DESCRIPTORS[0];
53 LOG_DOIP_INFO(
"Default connection created, transitioning to SocketInitialized state...");
54 transitionTo(DoIPServerState::WaitRoutingActivation);
57 ssize_t DoIPDefaultConnection::sendProtocolMessage(
const DoIPMessage &msg) {
59 return static_cast<ssize_t
>(msg.
size());
65 transitionTo(DoIPServerState::Closed);
66 m_closeReason = reason;
67 m_timerManager.stopAll();
68 notifyConnectionClosed(reason);
69 }
catch (
const std::exception &e) {
73 int frames = backtrace(callstack, 128);
74 char **strs = backtrace_symbols(callstack, frames);
78 for (
int i = 0; i < frames; ++i) {
87 return m_serverModel->serverAddress;
91 return m_routedClientAddress;
94 void DoIPDefaultConnection::setClientAddress(
const DoIPAddress &address) {
95 m_routedClientAddress = address;
98 void DoIPDefaultConnection::handleMessage2(
const DoIPMessage &message) {
99 m_state->messageHandler(message);
103 if (m_state->state == newState) {
107 auto it = std::find_if(
108 STATE_DESCRIPTORS.begin(),
109 STATE_DESCRIPTORS.end(),
110 [newState](
const StateDescriptor &desc) {
111 return desc.state == newState;
113 if (it != STATE_DESCRIPTORS.end()) {
116 startStateTimer(m_state);
117 if (m_state->enterStateHandler) {
119 m_state->enterStateHandler();
126 std::chrono::milliseconds DoIPDefaultConnection::getTimerDuration(StateDescriptor
const *stateDesc) {
128 switch (stateDesc->timer) {
129 case ConnectionTimers::AliveCheck:
130 return m_aliveCheckTimeout;
131 case ConnectionTimers::InitialInactivity:
132 return m_initialInactivityTimeout;
133 case ConnectionTimers::GeneralInactivity:
134 return m_generalInactivityTimeout;
135 case ConnectionTimers::DownstreamResponse:
136 return m_downstreamResponseTimeout;
137 case ConnectionTimers::UserDefined:
138 return stateDesc->timeoutDurationUser;
144 void DoIPDefaultConnection::startStateTimer(StateDescriptor
const *stateDesc) {
145 assert(stateDesc !=
nullptr);
146 if (stateDesc ==
nullptr) {
150 m_timerManager.stopAll();
152 std::chrono::milliseconds duration = getTimerDuration(m_state);
154 if (duration.count() == 0) {
155 LOG_DOIP_DEBUG(
"User-defined timer duration is zero, transitioning immediately to state {}",
fmt::streamed(stateDesc->stateAfterTimeout));
156 transitionTo(stateDesc->stateAfterTimeout);
163 if (stateDesc->timeoutHandler !=
nullptr) {
164 timeoutHandler = stateDesc->timeoutHandler;
167 auto id = m_timerManager.addTimer(
168 m_state->timer, duration, timeoutHandler,
false);
170 if (
id.has_value()) {
177 void DoIPDefaultConnection::restartStateTimer() {
178 assert(m_state !=
nullptr);
179 if (!m_timerManager.restartTimer(m_state->timer)) {
188 transitionTo(DoIPServerState::WaitRoutingActivation);
197 closeConnection(DoIPCloseReason::SocketError);
201 auto sourceAddress = msg->getSourceAddress();
202 bool hasAddress = sourceAddress.has_value();
203 bool rightPayloadType = (msg->getPayloadType() == DoIPPayloadType::RoutingActivationRequest);
205 if (!hasAddress || !rightPayloadType) {
207 closeConnection(DoIPCloseReason::InvalidMessage);
212 setClientAddress(sourceAddress.value());
214 sendRoutingActivationResponse(sourceAddress.value(), DoIPRoutingActivationResult::RouteActivated);
216 transitionTo(DoIPServerState::RoutingActivated);
223 closeConnection(DoIPCloseReason::SocketError);
227 auto message = msg.value();
229 switch (message.getPayloadType()) {
230 case DoIPPayloadType::DiagnosticMessage:
232 case DoIPPayloadType::AliveCheckResponse:
237 sendDiagnosticMessageResponse(
ZERO_ADDRESS, DoIPNegativeDiagnosticAck::TransportProtocolError);
241 auto sourceAddress = message.getSourceAddress();
242 if (!sourceAddress.has_value()) {
243 closeConnection(DoIPCloseReason::InvalidMessage);
246 if (sourceAddress.value() != getClientAddress()) {
248 sendDiagnosticMessageResponse(sourceAddress.value(), DoIPNegativeDiagnosticAck::InvalidSourceAddress);
253 auto ack = notifyDiagnosticMessage(message);
254 sendDiagnosticMessageResponse(sourceAddress.value(), ack);
260 if (ack.has_value()) {
261 transitionTo(DoIPServerState::RoutingActivated);
265 if (hasDownstreamHandler()) {
266 auto result = notifyDownstreamRequest(message);
268 if (result == DoIPDownstreamResult::Pending) {
270 transitionTo(DoIPServerState::WaitDownstreamResponse);
271 }
else if (result == DoIPDownstreamResult::Handled) {
273 transitionTo(DoIPServerState::RoutingActivated);
274 }
else if (result == DoIPDownstreamResult::Error) {
276 sendDiagnosticMessageResponse(sourceAddress.value(), DoIPNegativeDiagnosticAck::TargetUnreachable);
277 transitionTo(DoIPServerState::RoutingActivated);
290 closeConnection(DoIPCloseReason::SocketError);
294 auto message = msg.value();
296 switch (message.getPayloadType()) {
297 case DoIPPayloadType::DiagnosticMessage:
298 case DoIPPayloadType::AliveCheckResponse:
299 transitionTo(DoIPServerState::RoutingActivated);
302 LOG_DOIP_WARN(
"Received unsupported message type {} in Wait Alive Check Response state",
fmt::streamed(message.getPayloadType()));
303 sendDiagnosticMessageResponse(
ZERO_ADDRESS, DoIPNegativeDiagnosticAck::TransportProtocolError);
322 transitionTo(DoIPServerState::Closed);
329 case ConnectionTimers::InitialInactivity:
332 case ConnectionTimers::GeneralInactivity:
333 sendAliveCheckRequest();
334 transitionTo(DoIPServerState::WaitAliveCheckResponse);
336 case ConnectionTimers::AliveCheck:
337 if (m_aliveCheckRetry < m_aliveCheckRetryCount) {
338 transitionTo(DoIPServerState::WaitAliveCheckResponse);
340 closeConnection(DoIPCloseReason::AliveCheckTimeout);
343 case ConnectionTimers::DownstreamResponse:
345 transitionTo(DoIPServerState::RoutingActivated);
347 case ConnectionTimers::UserDefined:
348 LOG_DOIP_WARN(
"User-defined timer -> must be handled separately");
364 payload.push_back(
static_cast<uint8_t
>(response_code));
366 payload.insert(payload.end(), {0x00, 0x00, 0x00, 0x00});
368 DoIPMessage response(DoIPPayloadType::RoutingActivationResponse, std::move(payload));
369 return sendProtocolMessage(response);
372 ssize_t DoIPDefaultConnection::sendAliveCheckRequest() {
374 return sendProtocolMessage(request);
382 if (ack.has_value()) {
396 sentBytes = sendProtocolMessage(message);
397 notifyDiagnosticAckSent(ack);
401 ssize_t DoIPDefaultConnection::sendDownstreamResponse(
const DoIPAddress &sourceAddress,
const ByteArray& payload) {
405 return sendProtocolMessage(message);
409 if (m_serverModel->onDiagnosticMessage) {
410 return m_serverModel->onDiagnosticMessage(*
this, msg);
416 if (m_serverModel && m_serverModel->onCloseConnection) {
417 m_serverModel->onCloseConnection(*
this, reason);
422 if (m_serverModel->onDiagnosticNotification) {
423 m_serverModel->onDiagnosticNotification(*
this, ack);
427 bool DoIPDefaultConnection::hasDownstreamHandler()
const {
428 return m_serverModel->hasDownstreamHandler();
434 if (m_serverModel->onDownstreamRequest) {
436 this->receiveDownstreamResponse(response, result);
438 return m_serverModel->onDownstreamRequest(*
this, msg, handler);
440 return DoIPDownstreamResult::Error;
447 if (result == DoIPDownstreamResult::Handled) {
452 transitionTo(DoIPServerState::RoutingActivated);
#define LOG_DOIP_CRITICAL(...)
#define LOG_DOIP_WARN(...)
#define LOG_DOIP_ERROR(...)
#define LOG_DOIP_INFO(...)
#define LOG_DOIP_DEBUG(...)
void handleWaitAliveCheckResponse(DoIPServerEvent event, OptDoIPMessage msg)
void handleRoutingActivated(DoIPServerEvent event, OptDoIPMessage msg)
void handleSocketInitialized(DoIPServerEvent event, OptDoIPMessage msg)
void handleWaitRoutingActivation(DoIPServerEvent event, OptDoIPMessage msg)
void handleWaitDownstreamResponse(DoIPServerEvent event, OptDoIPMessage msg)
DoIPDefaultConnection(UniqueServerModelPtr model)
Constructs a DoIPDefaultConnection.
void handleFinalize(DoIPServerEvent event, OptDoIPMessage msg)
Represents a complete DoIP message with internal ByteArray representation.
size_t size() const
Gets the size for use with legacy APIs.
DoIPMessage makeDiagnosticPositiveResponse(const DoIPAddress &sa, const DoIPAddress &ta, const ByteArray &msg_payload)
void b
DoIPMessage makeAliveCheckRequest()
Create an 'alive check' request.
DoIPMessage makeDiagnosticNegativeResponse(const DoIPAddress &sa, const DoIPAddress &ta, DoIPNegativeDiagnosticAck nack, const ByteArray &msg_payload)
Creates a diagnostic negative ACK message (NACK).
DoIPMessage makeDiagnosticMessage(const DoIPAddress &sa, const DoIPAddress &ta, const ByteArray &msg_payload)
Creates a diagnostic message.
constexpr std::chrono::milliseconds InitialInactivityTimeout(200)
Maximum inactivity time in ms after a TCP connection was accepted.
uint16_t DoIPAddress
Represents a 16-bit DoIP address consisting of high and low significant bytes.
std::optional< DoIPNegativeDiagnosticAck > DoIPDiagnosticAck
Alias for diagnostic acknowledgment type.
DoIPRoutingActivationResult
constexpr DoIPAddress ZERO_ADDRESS
DoIPDownstreamResult
Result of a downstream request initiation.
std::optional< DoIPMessage > OptDoIPMessage
DoIPCloseReason
Reason for connection closure.
std::unique_ptr< DoIPServerModel > UniqueServerModelPtr
streamed_t< T > streamed(const T &v)
A dynamic array of bytes with utility methods for network protocol handling.
void writeU16BE(uint16_t value)
Appends a 16-bit unsigned integer in big-endian format to the end.