15 m_tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
17 if (m_tcpSocket >= 0) {
20 bool connectedFlag =
false;
21 const char *ipAddr =
"127.0.0.1";
22 m_serverAddress.sin_family = AF_INET;
23 m_serverAddress.sin_port = htons(DOIP_UDP_DISCOVERY_PORT);
24 inet_aton(ipAddr, &(m_serverAddress.sin_addr));
26 while (!connectedFlag) {
27 m_connected = connect(m_tcpSocket,
reinterpret_cast<struct sockaddr *
>(&m_serverAddress),
sizeof(m_serverAddress));
28 if (m_connected != -1) {
38 m_udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
40 if (m_udpSocket >= 0) {
43 m_serverAddress.sin_family = AF_INET;
44 m_serverAddress.sin_port = htons(DOIP_UDP_DISCOVERY_PORT);
45 m_serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
47 m_clientAddress.sin_family = AF_INET;
48 m_clientAddress.sin_port = htons(DOIP_UDP_DISCOVERY_PORT);
49 m_clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
52 bind(m_udpSocket,
reinterpret_cast<struct sockaddr *
>(&m_clientAddress),
sizeof(m_clientAddress));
57 m_udpAnnouncementSocket = socket(AF_INET, SOCK_DGRAM, 0);
59 if (m_udpAnnouncementSocket >= 0) {
60 LOG_UDP_INFO(
"Client-Announcement-Socket created successfully");
64 setsockopt(m_udpAnnouncementSocket, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse));
68 if (setsockopt(m_udpAnnouncementSocket, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast)) < 0) {
69 LOG_UDP_ERROR(
"Failed to enable broadcast reception: {}", strerror(errno));
71 LOG_UDP_INFO(
"Broadcast reception enabled for announcements");
74 m_announcementAddress.sin_family = AF_INET;
75 m_announcementAddress.sin_port = htons(DOIP_UDP_TEST_EQUIPMENT_REQUEST_PORT);
76 m_announcementAddress.sin_addr.s_addr = htonl(INADDR_ANY);
79 if (bind(m_udpAnnouncementSocket,
reinterpret_cast<struct sockaddr *
>(&m_announcementAddress),
sizeof(m_announcementAddress)) < 0) {
80 LOG_UDP_ERROR(
"Failed to bind announcement socket to port {}: {}", DOIP_UDP_TEST_EQUIPMENT_REQUEST_PORT, strerror(errno));
82 LOG_UDP_INFO(
"Announcement socket bound to port {} successfully", DOIP_UDP_TEST_EQUIPMENT_REQUEST_PORT);
85 LOG_UDP_ERROR(
"Failed to create announcement socket: {}", strerror(errno));
98 if (m_udpAnnouncementSocket >= 0) {
99 close(m_udpAnnouncementSocket);
111 return write(m_tcpSocket, routingActReq.
data(), routingActReq.
size());
118 return write(m_tcpSocket, msg.
data(), msg.
size());
124 return write(m_tcpSocket, msg.
data(), msg.
size());
132 ssize_t bytesRead = recv(m_tcpSocket, m_receiveBuf.data(),
_maxDataSize, 0);
141 emptyMessageCounter++;
143 if (emptyMessageCounter == 5) {
144 LOG_DOIP_WARN(
"Received too many empty messages. Reconnect TCP connection");
145 emptyMessageCounter = 0;
152 if (!optMmsg.has_value()) {
153 LOG_DOIP_ERROR(
"Failed to parse DoIP message from received data");
162 unsigned int length =
sizeof(m_clientAddress);
165 struct timeval timeout;
168 setsockopt(m_udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
171 bytesRead = recvfrom(m_udpSocket, m_receiveBuf.data(),
_maxDataSize, 0,
reinterpret_cast<struct sockaddr *
>(&m_clientAddress), &length);
174 if (errno == EAGAIN) {
177 LOG_UDP_ERROR(
"Error receiving UDP message: {}", strerror(errno));
185 if (!optMmsg.has_value()) {
196 unsigned int length =
sizeof(m_announcementAddress);
199 LOG_UDP_DEBUG(
"Listening for Vehicle Announcements on port {}", DOIP_UDP_TEST_EQUIPMENT_REQUEST_PORT);
202 struct timeval timeout;
205 setsockopt(m_udpAnnouncementSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout));
207 bytesRead = recvfrom(m_udpAnnouncementSocket, m_receiveBuf.data(),
_maxDataSize, 0,
208 reinterpret_cast<struct sockaddr *
>(&m_announcementAddress), &length);
210 if (errno == EAGAIN) {
211 LOG_UDP_WARN(
"Timeout waiting for Vehicle Announcement");
213 LOG_UDP_ERROR(
"Error receiving Vehicle Announcement: {}", strerror(errno));
219 if (!optMsg.has_value()) {
220 LOG_UDP_ERROR(
"Failed to parse Vehicle Announcement message");
228 parseVehicleIdentificationResponse(msg);
236 int setAddressError = inet_aton(inet_address, &(m_serverAddress.sin_addr));
238 if (setAddressError != 0) {
244 int socketError = setsockopt(m_udpSocket, SOL_SOCKET, SO_BROADCAST, &m_broadcast,
sizeof(m_broadcast));
246 if (socketError == 0) {
252 ssize_t bytesSent = sendto(m_udpSocket, vehicleIdReq.
data(), vehicleIdReq.
size(), 0,
reinterpret_cast<struct sockaddr *
>(&m_serverAddress),
sizeof(m_serverAddress));
253 LOG_UDP_INFO(
"Sent Vehicle Identification Request to {}:{}", inet_address, ntohs(m_serverAddress.sin_port));
267 m_sourceAddress = address;
284 void DoIPClient::parseVehicleIdentificationResponse(
const DoIPMessage &msg) {
285 auto optVin = msg.
getVin();
286 auto optEid = msg.
getEid();
287 auto optGid = msg.
getGid();
291 if (!optVin || !optEid || !optGid || !optLogicalAddress || !optFurtherAction) {
292 LOG_DOIP_WARN(
"Incomplete Vehicle Identification Response received: Missing VIN, EID, GID, Logical Address or Further Action Request");
295 m_vin = optVin.value();
296 m_eid = optEid.value();
297 m_gid = optGid.value();
298 m_logicalAddress = optLogicalAddress.value();
299 m_furtherActionReqResult = optFurtherAction.value();
303 std::ostringstream ss;
313 ss = std::ostringstream{};
322 ss = std::ostringstream{};
331 ss = std::ostringstream{};
340 ss = std::ostringstream{};
#define LOG_TCP_INFO(...)
#define LOG_UDP_ERROR(...)
#define LOG_UDP_WARN(...)
#define LOG_UDP_INFO(...)
#define LOG_DOIP_WARN(...)
#define LOG_DOIP_ERROR(...)
#define LOG_UDP_DEBUG(...)
#define LOG_DOIP_INFO(...)
bool receiveVehicleAnnouncement()
void printVehicleInformationResponse()
void startTcpConnection()
void closeUdpConnection()
void startUdpConnection()
ssize_t sendVehicleIdentificationRequest(const char *inet_address)
ssize_t sendAliveCheckResponse()
Sends a alive check response containing the clients source address to the server.
void startAnnouncementListener()
void setSourceAddress(const DoIPAddress &address)
Sets the source address for this client.
ssize_t sendDiagnosticMessage(const ByteArray &payload)
Sends a diagnostic message to the server.
void closeTcpConnection()
ssize_t sendRoutingActivationRequest()
Represents a complete DoIP message with internal ByteArray representation.
static std::optional< DoIPMessage > tryParse(const uint8_t *data, size_t length)
Parse a DoIP message from raw data.
std::optional< DoIPAddress > getLogicalAddress() const
Get the Logical Address of the message (if message is a Vehicle Identification Response).
size_t size() const
Gets the size for use with legacy APIs.
std::optional< DoIpEid > getEid() const
Get the entity id (EID) if message is a Vehicle Identification Response.
std::optional< DoIpVin > getVin() const
Get the vehicle identification number (VIN) if message is a Vehicle Identification Response.
const uint8_t * data() const
Gets direct pointer to the message data (for legacy APIs).
std::optional< DoIPFurtherAction > getFurtherActionRequest() const
Get the Further Action Request object if message is a Vehicle Identification Response.
DoIPPayloadType getPayloadType() const
Gets the payload type of this message.
std::optional< DoIpGid > getGid() const
Get the group id (GID) if message is a Vehicle Identification Response.
static bool colorsSupported()
constexpr const char * reset
constexpr const char * bold_green
DoIPMessage makeAliveCheckResponse(const DoIPAddress &sa)
Create an 'alive check' response.
DoIPMessage makeVehicleIdentificationRequest()
Creates a vehicle identification request message.
DoIPMessage makeDiagnosticMessage(const DoIPAddress &sa, const DoIPAddress &ta, const ByteArray &msg_payload)
Creates a diagnostic message.
DoIPMessage makeRoutingActivationRequest(const DoIPAddress &ea, DoIPRoutingActivationType actType=DoIPRoutingActivationType::Default)
Creates a routing activation request message.
uint16_t DoIPAddress
Represents a 16-bit DoIP address consisting of high and low significant bytes.
@ VehicleIdentificationResponse
Vehicle Identification Response (Vehicle Announcement) Response to a Vehicle Identification Request o...
streamed_t< T > streamed(const T &v)
A dynamic array of bytes with utility methods for network protocol handling.