libdoip  0.1.0
DoIP (Diagnostics over Internet Protocol) ISO 13400 C++17 Library
DoIPConnection.cpp
Go to the documentation of this file.
1 #include "DoIPConnection.h"
2 #include "DoIPMessage.h"
3 #include "DoIPPayloadType.h"
4 #include "Logger.h"
5 
6 #include <iomanip>
7 #include <iostream>
8 
9 namespace doip {
10 
12  : DoIPDefaultConnection(std::move(model)),
13  m_logicalAddress(ZERO_ADDRESS),
14  m_tcpSocket(tcpSocket) {
15 }
16 
17 /*
18  * Closes the socket for this server (private method)
19  */
20 void DoIPConnection::closeSocket() {
22 }
23 
24 /*
25  * Receives a message from the client and calls reactToReceivedTcpMessage method
26  * @return amount of bytes which were send back to client
27  * or -1 if error occurred
28  */
30  LOG_DOIP_INFO("Waiting for DoIP Header...");
31  uint8_t genericHeader[DOIP_HEADER_SIZE];
32  unsigned int readBytes = receiveFixedNumberOfBytesFromTCP(genericHeader, DOIP_HEADER_SIZE);
33  if (readBytes == DOIP_HEADER_SIZE /*&& !m_aliveCheckTimer.hasTimeout()*/) {
34  LOG_DOIP_INFO("Received DoIP Header.");
35 
36  auto optHeader = DoIPMessage::tryParseHeader(genericHeader, DOIP_HEADER_SIZE);
37  if (!optHeader.has_value()) {
38  // m_stateMachine.processEvent(DoIPServerEvent::InvalidMessage);
39  // TODO: Notify application of invalid message?
40  LOG_DOIP_ERROR("DoIP message header parsing failed");
41  closeSocket();
42  return -2;
43  }
44 
45  auto plType = optHeader->first;
46  auto payloadLength = optHeader->second;
47 
48  LOG_DOIP_INFO("Payload Type: {}, length: {} ", fmt::streamed(plType), payloadLength);
49 
50  if (payloadLength > 0) {
51  LOG_DOIP_DEBUG("Waiting for {} bytes of payload...", payloadLength);
52  unsigned int receivedPayloadBytes = receiveFixedNumberOfBytesFromTCP(m_receiveBuf.data(), payloadLength);
53  if (receivedPayloadBytes < payloadLength) {
54  LOG_DOIP_ERROR("DoIP message incomplete");
55  // m_stateMachine.processEvent(DoIPServerEvent::InvalidMessage);
56  // todo: Notify application of invalid message?
57  closeSocket();
58  return -2;
59  }
60 
61  DoIPMessage msg = DoIPMessage(plType, m_receiveBuf.data(), receivedPayloadBytes);
62  LOG_DOIP_INFO("RX: {}", fmt::streamed(msg));
63  }
64 
65  DoIPMessage message(plType, m_receiveBuf.data(), payloadLength);
66  handleMessage2(message);
67 
68  return 1;
69  } else {
70  closeSocket();
71  return 0;
72  }
73  return -1;
74 }
75 
76 /**
77  * Receive exactly payloadLength bytes from the TCP stream and put them into receivedData.
78  * The method blocks until receivedData bytes are received or the socket is closed.
79  *
80  * The parameter receivedData needs to point to a readily allocated array with
81  * at least payloadLength items.
82  *
83  * @return number of bytes received
84  */
85 size_t DoIPConnection::receiveFixedNumberOfBytesFromTCP(uint8_t *receivedData, size_t payloadLength) {
86  size_t payloadPos = 0;
87  size_t remainingPayload = payloadLength;
88 
89  while (remainingPayload > 0) {
90  ssize_t result = recv(m_tcpSocket, &receivedData[payloadPos], remainingPayload, 0);
91  if (result <= 0) {
92  return payloadPos;
93  }
94  size_t readBytes = static_cast<size_t>(result);
95  payloadPos += readBytes;
96  remainingPayload -= readBytes;
97  }
98 
99  return payloadPos;
100 }
101 
103  LOG_DOIP_INFO("Application requested to disconnect Client from Server");
104  closeSocket();
105 }
106 
107 /**
108  * Sends a message back to the connected client
109  * @param message contains generic header and payload specific content
110  * @param messageLength length of the complete message
111  * @return number of bytes written is returned,
112  * or -1 if error occurred
113  */
114 ssize_t DoIPConnection::sendMessage(const uint8_t *message, size_t messageLength) {
115  ssize_t result = write(m_tcpSocket, message, messageLength);
116  return result;
117 }
118 
119 // === IConnectionContext interface implementation ===
121  ssize_t sentBytes = sendMessage(msg.data(), msg.size());
122  if (sentBytes < 0) {
123  LOG_DOIP_ERROR("Error sending message to client: {}", fmt::streamed(msg));
124  } else {
125  LOG_DOIP_INFO("Sent {} bytes to client: {}", sentBytes, fmt::streamed(msg));
126  }
127  return sentBytes;
128 }
129 
131  // Guard against recursive calls
132  if (m_isClosing) {
133  LOG_DOIP_DEBUG("Connection already closing - ignoring recursive call");
134  return;
135  }
136 
137  m_isClosing = true;
138  LOG_DOIP_INFO("Closing connection, reason: {}", fmt::streamed(reason));
139 
140  // Call base class to handle state machine and notification
142 
143  close(m_tcpSocket);
144  m_tcpSocket = 0;
145 }
146 
148  return m_serverModel->serverAddress;
149 }
150 
152  return m_logicalAddress;
153 }
154 
156  m_logicalAddress = address;
157 }
158 
160  // Forward to application callback
161  if (m_serverModel->onDiagnosticMessage) {
162  return m_serverModel->onDiagnosticMessage(*this, msg);
163  }
164  // Default: ACK
165  return std::nullopt;
166 }
167 
169  (void)reason; // Could extend DoIPServerModel to include close reason
170  if (m_serverModel->onCloseConnection) {
171  m_serverModel->onCloseConnection(*this, reason);
172  }
173 }
174 
176  if (m_serverModel->onDiagnosticNotification) {
177  m_serverModel->onDiagnosticNotification(*this, ack);
178  }
179 }
180 
182  return m_serverModel->hasDownstreamHandler();
183 }
184 
185 } // namespace doip
#define LOG_DOIP_ERROR(...)
Definition: Logger.h:128
#define LOG_DOIP_INFO(...)
Definition: Logger.h:126
#define LOG_DOIP_DEBUG(...)
Definition: Logger.h:125
bool hasDownstreamHandler() const override
Check if downstream forwarding is available.
DoIPAddress getClientAddress() const override
Get the currently client (active source) address.
DoIPDiagnosticAck notifyDiagnosticMessage(const DoIPMessage &msg) override
Handle an incoming diagnostic message (application callback)
void notifyDiagnosticAckSent(DoIPDiagnosticAck ack) override
Notify application that diagnostic ACK/NACK was sent.
ssize_t sendProtocolMessage(const DoIPMessage &msg) override
Send a DoIP protocol message to the client.
void setClientAddress(const DoIPAddress &address) override
Set the client (active source) address after routing activation.
void closeConnection(DoIPCloseReason reason) override
Close the TCP connection.
size_t receiveFixedNumberOfBytesFromTCP(uint8_t *receivedData, size_t payloadLength)
Receive exactly payloadLength bytes from the TCP stream and put them into receivedData.
DoIPConnection(int tcpSocket, UniqueServerModelPtr model)
void notifyConnectionClosed(DoIPCloseReason reason) override
Notify application that connection is closing.
DoIPAddress getServerAddress() const override
Get the server's logical address.
Default implementation of IConnectionContext.
void closeConnection(DoIPCloseReason reason) override
Closes the connection.
void handleMessage2(const DoIPMessage &message)
Handles a message (internal helper)
UniqueServerModelPtr m_serverModel
Represents a complete DoIP message with internal ByteArray representation.
Definition: DoIPMessage.h:82
static std::optional< std::pair< DoIPPayloadType, uint32_t > > tryParseHeader(const uint8_t *data, size_t length)
Gets the payload type from raw data.
Definition: DoIPMessage.h:399
size_t size() const
Gets the size for use with legacy APIs.
Definition: DoIPMessage.h:231
const uint8_t * data() const
Gets direct pointer to the message data (for legacy APIs).
Definition: DoIPMessage.h:222
Definition: AnsiColors.h:3
uint16_t DoIPAddress
Represents a 16-bit DoIP address consisting of high and low significant bytes.
Definition: DoIPAddress.h:26
std::optional< DoIPNegativeDiagnosticAck > DoIPDiagnosticAck
Alias for diagnostic acknowledgment type.
constexpr size_t DOIP_HEADER_SIZE
Size of the DoIP header.
Definition: DoIPMessage.h:57
constexpr DoIPAddress ZERO_ADDRESS
Definition: DoIPAddress.h:28
DoIPCloseReason
Reason for connection closure.
std::unique_ptr< DoIPServerModel > UniqueServerModelPtr
streamed_t< T > streamed(const T &v)
Definition: Logger.h:24