libdoip  0.1.0
DoIP (Diagnostics over Internet Protocol) ISO 13400 C++17 Library
DoIPServer.h
Go to the documentation of this file.
1 #ifndef DOIPSERVER_H
2 #define DOIPSERVER_H
3 
4 #include <arpa/inet.h>
5 #include <atomic>
6 #include <functional>
7 #include <iostream>
8 #include <memory>
9 #include <net/if.h>
10 #include <netinet/in.h>
11 #include <optional>
12 #include <string.h>
13 #include <string>
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <thread>
17 #include <unistd.h>
18 #include <vector>
19 
20 #include "ByteArray.h"
21 #include "DoIPConfig.h"
22 #include "DoIPConnection.h"
23 #include "DoIPFurtherAction.h"
24 #include "DoIPIdentifiers.h"
25 #include "DoIPNegativeAck.h"
26 #include "DoIPServerModel.h"
27 #include "MacAddress.h"
28 
29 namespace doip {
30 
31 /**
32  * @brief Server configuration structure used to initialize a DoIP server.
33  */
34 struct ServerConfig {
35  // EID and GID as fixed identifiers (6 bytes). Default: zeros.
38 
39  // VIN as fixed identifier (17 bytes). Default: zeros.
41 
42  // Logical/server address (default 0x0E00)
44 
45  // Use loopback announcements instead of broadcast
46  bool loopback = false;
47 
48  // Run the server as a daemon by default
49  bool daemonize = false;
50 
51  int announceCount = 3; // Default Value = 3
52  unsigned int announceInterval = 500; // Default Value = 500ms
53 };
54 
56 
57 constexpr int DOIP_SERVER_TCP_PORT = 13400;
58 
59 /**
60  * @brief Callback invoked when a new TCP connection is established
61  * @return DoIPServerModel to use for this connection, or std::nullopt to reject
62  */
63 using ConnectionAcceptedHandler = std::function<std::optional<DoIPServerModel>(DoIPConnection *)>;
64 
65 /**
66  * @brief DoIP Server class to handle incoming DoIP connections and UDP messages.
67  *
68  * This class manages the low-level TCP/UDP socket handling.
69  */
70 class DoIPServer {
71 
72  public:
73  /**
74  * @brief Construct a DoIP server with the given configuration.
75  * @param config Server configuration (EID/GID/VIN, announce params, etc.).
76  */
77  explicit DoIPServer(const ServerConfig &config = DefaultServerConfig);
78 
79  /**
80  * @brief Destructor. Ensures sockets/threads are closed/stopped.
81  */
82  ~DoIPServer();
83 
84  DoIPServer(const DoIPServer &) = delete;
85  DoIPServer &operator=(const DoIPServer &) = delete;
86  DoIPServer(DoIPServer &&) = delete;
88 
89  [[nodiscard]]
90  /**
91  * @brief Initialize and bind the TCP socket for DoIP.
92  * @return true on success, false otherwise.
93  */
94  bool setupTcpSocket();
95 
96  template <typename Model = DefaultDoIPServerModel>
97  /**
98  * @brief Block until a TCP client connects and create a DoIP connection.
99  * @tparam Model Server model type used by the connection (default `DefaultDoIPServerModel`).
100  * @return Unique pointer to established `DoIPConnection`, or nullptr on failure.
101  */
102  std::unique_ptr<DoIPConnection> waitForTcpConnection();
103 
104  [[nodiscard]]
105  /**
106  * @brief Initialize and bind the UDP socket for announcements and UDP messages.
107  * @return true on success, false otherwise.
108  */
109  bool setupUdpSocket();
110 
111  /**
112  * @brief Check if the server is currently running
113  */
114  [[nodiscard]]
115  bool isRunning() const { return m_running.load(); }
116 
117  /**
118  * @brief Set the number of vehicle announcements to send.
119  * @param Num Count of announcements.
120  */
121  void setAnnounceNum(int Num);
122  /**
123  * @brief Set the interval between announcements in milliseconds.
124  * @param Interval Interval in ms.
125  */
126  void setAnnounceInterval(unsigned int Interval);
127  /**
128  * @brief Enable/disable loopback mode for announcements (no broadcast).
129  * @param useLoopback True to use loopback, false for broadcast.
130  */
131  void setLoopbackMode(bool useLoopback);
132 
133  /**
134  * @brief Close the TCP socket if open.
135  */
136  void closeTcpSocket();
137  /**
138  * @brief Close the UDP socket if open.
139  */
140  void closeUdpSocket();
141 
142  /**
143  * @brief Set the logical DoIP gateway address.
144  * @param logicalAddress Logical address value.
145  */
146  void setLogicalGatewayAddress(DoIPAddress logicalAddress);
147 
148  /**
149  * @brief Sets the EID to a default value based on the MAC address.
150  *
151  * @return true if the EID was successfully set to the default value.
152  * @return false if the default EID could not be set.
153  */
154  bool setDefaultEid();
155 
156  /**
157  * @brief Set VIN from a 17-character string.
158  * @param VINString VIN string (17 bytes expected).
159  */
160  void setVin(const std::string &VINString);
161  /**
162  * @brief Set VIN from a `DoIpVin` instance.
163  * @param vin VIN value.
164  */
165  void setVin(const DoIpVin &vin);
166  /**
167  * @brief Get current VIN.
168  * @return Reference to configured VIN.
169  */
170  const DoIpVin &getVin() const { return m_config.vin; }
171 
172  /**
173  * @brief Set EID value.
174  * @param nputEID EID as 64-bit value (lower 48 bits used).
175  */
176  void setEid(uint64_t nputEID);
177  /**
178  * @brief Get current EID.
179  * @return Reference to configured EID.
180  */
181  const DoIpEid &getEid() const { return m_config.eid; }
182 
183  /**
184  * @brief Set GID value.
185  * @param inputGID GID as 64-bit value (lower 48 bits used).
186  */
187  void setGid(uint64_t inputGID);
188  /**
189  * @brief Get current GID.
190  * @return Reference to configured GID.
191  */
192  const DoIpGid &getGid() const { return m_config.gid; }
193 
194  /**
195  * @brief Get current further action requirement status.
196  * @return Current `DoIPFurtherAction` value.
197  */
198  DoIPFurtherAction getFurtherActionRequired() const { return m_FurtherActionReq; }
199  /**
200  * @brief Set further action requirement status.
201  * @param furtherActionRequired Value to set.
202  */
203  void setFurtherActionRequired(DoIPFurtherAction furtherActionRequired);
204 
205  /**
206  * @brief Get last accepted client IP (string form).
207  * @return IP address string.
208  */
209  std::string getClientIp() const { return m_clientIp; }
210  /**
211  * @brief Get last accepted client TCP port.
212  * @return Client port number.
213  */
214  int getClientPort() const { return m_clientPort; }
215 
216  private:
217  int m_tcp_sock{-1};
218  int m_udp_sock{-1};
219  struct sockaddr_in m_serverAddress{};
220  struct sockaddr_in m_clientAddress{};
221  ByteArray m_receiveBuf{};
222  std::string m_clientIp{};
223  int m_clientPort{};
225 
226  // Automatic mode state
227  std::atomic<bool> m_running{false};
228  std::vector<std::thread> m_workerThreads;
229  std::mutex m_mutex;
230 
231  // Server configuration
232  ServerConfig m_config;
233 
234  void stop();
235  void daemonize();
236 
237  void setMulticastGroup(const char *address) const;
238 
239  ssize_t sendNegativeUdpAck(DoIPNegativeAck ackCode);
240 
241  template <typename Model>
242  void tcpListenerThread();
243 
244  void connectionHandlerThread(std::unique_ptr<DoIPConnection> connection);
245 
246  void udpListenerThread();
247  void udpAnnouncementThread();
248  ssize_t sendVehicleAnnouncement();
249 
250  ssize_t sendUdpResponse(DoIPMessage msg);
251 };
252 
253 // Template implementation must be in header for external linkage
254 template <typename Model>
255 std::unique_ptr<DoIPConnection> DoIPServer::waitForTcpConnection() {
256  static_assert(std::is_default_constructible<Model>::value,
257  "Model must be default-constructible");
258 
259  // waits till client approach to make connection
260  if (listen(m_tcp_sock, 5) < 0) {
261  return nullptr;
262  }
263 
264  int tcpSocket = accept(m_tcp_sock, nullptr, nullptr);
265  if (tcpSocket < 0) {
266  return nullptr;
267  }
268 
269  return std::unique_ptr<DoIPConnection>(new DoIPConnection(tcpSocket, std::make_unique<Model>()));
270 }
271 
272 /*
273  * Background thread: TCP connection acceptor
274  */
275 template <typename Model>
276 void DoIPServer::tcpListenerThread() {
277  LOG_DOIP_INFO("TCP listener thread started");
278 
279  while (m_running.load()) {
280  auto connection = waitForTcpConnection<Model>();
281 
282  if (!connection) {
283  if (m_running.load()) {
284  LOG_TCP_DEBUG("Failed to accept connection, retrying...");
285  std::this_thread::sleep_for(std::chrono::milliseconds(100));
286  }
287  continue;
288  }
289 
290  // Spawn a dedicated thread for this connection
291  // Note: We detach because the connection thread manages its own lifecycle
292  std::thread(&DoIPServer::connectionHandlerThread, this, std::move(connection)).detach();
293  }
294 
295  LOG_DOIP_INFO("TCP listener thread stopped");
296 }
297 
298 } // namespace doip
299 
300 #endif /* DOIPSERVER_H */
Defines the ByteArray type and utility functions for byte manipulation.
DoIPNegativeAck
#define LOG_TCP_DEBUG(...)
Definition: Logger.h:141
#define LOG_DOIP_INFO(...)
Definition: Logger.h:126
DoIP Server class to handle incoming DoIP connections and UDP messages.
Definition: DoIPServer.h:70
void setLoopbackMode(bool useLoopback)
Enable/disable loopback mode for announcements (no broadcast).
Definition: DoIPServer.cpp:275
DoIPServer(const DoIPServer &)=delete
bool setupTcpSocket()
Initialize and bind the TCP socket for DoIP.
Definition: DoIPServer.cpp:132
void setAnnounceNum(int Num)
Set the number of vehicle announcements to send.
Definition: DoIPServer.cpp:267
DoIPServer & operator=(const DoIPServer &)=delete
void setAnnounceInterval(unsigned int Interval)
Set the interval between announcements in milliseconds.
Definition: DoIPServer.cpp:271
DoIPFurtherAction getFurtherActionRequired() const
Get current further action requirement status.
Definition: DoIPServer.h:198
void setVin(const std::string &VINString)
Set VIN from a 17-character string.
Definition: DoIPServer.cpp:242
std::string getClientIp() const
Get last accepted client IP (string form).
Definition: DoIPServer.h:209
bool isRunning() const
Check if the server is currently running.
Definition: DoIPServer.h:115
void setEid(uint64_t nputEID)
Set EID value.
Definition: DoIPServer.cpp:255
DoIPServer & operator=(DoIPServer &&)=delete
DoIPServer(DoIPServer &&)=delete
const DoIpEid & getEid() const
Get current EID.
Definition: DoIPServer.h:181
void setGid(uint64_t inputGID)
Set GID value.
Definition: DoIPServer.cpp:259
void closeTcpSocket()
Close the TCP socket if open.
Definition: DoIPServer.cpp:164
std::unique_ptr< DoIPConnection > waitForTcpConnection()
Block until a TCP client connects and create a DoIP connection.
Definition: DoIPServer.h:255
void setFurtherActionRequired(DoIPFurtherAction furtherActionRequired)
Set further action requirement status.
Definition: DoIPServer.cpp:263
const DoIpVin & getVin() const
Get current VIN.
Definition: DoIPServer.h:170
~DoIPServer()
Destructor.
Definition: DoIPServer.cpp:18
DoIPServer(const ServerConfig &config=DefaultServerConfig)
Construct a DoIP server with the given configuration.
Definition: DoIPServer.cpp:24
bool setDefaultEid()
Sets the EID to a default value based on the MAC address.
Definition: DoIPServer.cpp:230
const DoIpGid & getGid() const
Get current GID.
Definition: DoIPServer.h:192
bool setupUdpSocket()
Initialize and bind the UDP socket for announcements and UDP messages.
Definition: DoIPServer.cpp:168
int getClientPort() const
Get last accepted client TCP port.
Definition: DoIPServer.h:214
void setLogicalGatewayAddress(DoIPAddress logicalAddress)
Set the logical DoIP gateway address.
Definition: DoIPServer.cpp:251
void closeUdpSocket()
Close the UDP socket if open.
Definition: DoIPServer.cpp:220
static const GenericFixedId Zero
Static instance containing only zeros.
Definition: AnsiColors.h:3
const ServerConfig DefaultServerConfig
Definition: DoIPServer.h:55
uint16_t DoIPAddress
Represents a 16-bit DoIP address consisting of high and low significant bytes.
Definition: DoIPAddress.h:26
std::function< std::optional< DoIPServerModel >(DoIPConnection *)> ConnectionAcceptedHandler
Callback invoked when a new TCP connection is established.
Definition: DoIPServer.h:63
constexpr int DOIP_SERVER_TCP_PORT
Definition: DoIPServer.h:57
Server configuration structure used to initialize a DoIP server.
Definition: DoIPServer.h:34
unsigned int announceInterval
Definition: DoIPServer.h:52
DoIPAddress logicalAddress
Definition: DoIPServer.h:43