Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file TraCIServer.h
15 : /// @author Axel Wegener
16 : /// @author Friedemann Wesner
17 : /// @author Christoph Sommer
18 : /// @author Tino Morenz
19 : /// @author Daniel Krajzewicz
20 : /// @author Thimor Bohn
21 : /// @author Sascha Krieg
22 : /// @author Michael Behrisch
23 : /// @author Leonhard Luecken
24 : /// @date 2007/10/24
25 : ///
26 : // TraCI server used to control sumo by a remote TraCI client
27 : /****************************************************************************/
28 : #pragma once
29 : #include <config.h>
30 :
31 : #include <map>
32 : #include <string>
33 : #include <set>
34 :
35 : #define BUILD_TCPIP
36 : #include <foreign/tcpip/socket.h>
37 : #include <foreign/tcpip/storage.h>
38 : #include <utils/common/NamedRTree.h>
39 : #include <utils/common/SUMOTime.h>
40 : #include <utils/common/ToString.h>
41 : #include <utils/geom/Boundary.h>
42 : #include <utils/geom/Position.h>
43 : #include <utils/geom/GeomHelper.h>
44 : #include <utils/options/OptionsCont.h>
45 : #include <microsim/MSNet.h>
46 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
47 : #include <libsumo/TraCIConstants.h>
48 : #include <libsumo/Subscription.h>
49 : #include <libsumo/TraCIDefs.h>
50 : #include "TraCIServerAPI_Lane.h"
51 :
52 :
53 : // ===========================================================================
54 : // class definitions
55 : // ===========================================================================
56 : /** @class TraCIServer
57 : * @brief TraCI server used to control sumo by a remote TraCI client
58 : */
59 : class TraCIServer final : public MSNet::VehicleStateListener, public libsumo::VariableWrapper, public MSNet::TransportableStateListener {
60 : public:
61 : /// @brief Definition of a method to be called for serving an associated commandID
62 : typedef bool(*CmdExecutor)(TraCIServer& server, tcpip::Storage& inputStorage, tcpip::Storage& outputStorage);
63 :
64 : SUMOTime getTargetTime() const {
65 : return myTargetTime;
66 : }
67 :
68 : static TraCIServer* getInstance() {
69 128458072 : return myInstance;
70 : }
71 :
72 : /// @name Initialisation and Shutdown
73 : /// @{
74 :
75 : /** @brief Initialises the server
76 : * @param[in] execs The (additional) command executors to use
77 : */
78 : static void openSocket(const std::map<int, CmdExecutor>& execs);
79 :
80 :
81 : /// @brief request termination of connection
82 : static void close();
83 :
84 :
85 : /** @brief check whether close was requested
86 : * @return Whether the connection was closed
87 : */
88 : static bool wasClosed();
89 : /// @}
90 :
91 :
92 : /// @brief process all commands until the next SUMO simulation step.
93 : /// It is guaranteed that t->getTargetTime() >= myStep after call
94 : /// (except the case that a load or close command is received)s
95 : int processCommands(const SUMOTime step, const bool afterMove = false);
96 :
97 : /// @brief clean up subscriptions
98 : void cleanup();
99 :
100 :
101 : void vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info = "");
102 :
103 : void transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& info = "");
104 :
105 : /// @name Writing Status Messages
106 : /// @{
107 :
108 : /** @brief Writes a status command to the given storage
109 : * @param[in] commandId The id of the command to respond to
110 : * @param[in] status The status to send
111 : * @param[in] description The status description (error message, for example)
112 : * @param[in, filled] outputStorage The storage to write the status into
113 : */
114 : void writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage);
115 :
116 :
117 : /** @brief Writes a status command to myOutputStorage
118 : * @param[in] commandId The id of the command to respond to
119 : * @param[in] status The status to send
120 : * @param[in] description The status description (error message, for example)
121 : */
122 : void writeStatusCmd(int commandId, int status, const std::string& description);
123 :
124 :
125 : /** @brief Writes a status command to the given storage with status = RTYPE_ERR
126 : * @param[in] commandId The id of the command to respond to
127 : * @param[in] description The status description (error message, for example)
128 : * @param[in, filled] outputStorage The storage to write the status into
129 : */
130 : bool writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage);
131 : /// @}
132 :
133 :
134 :
135 : const std::map<MSNet::VehicleState, std::vector<std::string> >& getVehicleStateChanges() const {
136 67655 : if (myCurrentSocket == mySockets.end()) {
137 : // Requested in context of a subscription update
138 15891 : return myVehicleStateChanges;
139 : } else {
140 : // Requested in the context of a custom query by active client
141 51764 : return myCurrentSocket->second->vehicleStateChanges;
142 : }
143 : }
144 :
145 : const std::map<MSNet::TransportableState, std::vector<std::string> >& getTransportableStateChanges() const {
146 60 : if (myCurrentSocket == mySockets.end()) {
147 : // Requested in context of a subscription update
148 12 : return myTransportableStateChanges;
149 : } else {
150 : // Requested in the context of a custom query by active client
151 48 : return myCurrentSocket->second->transportableStateChanges;
152 : }
153 : }
154 :
155 : void writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg);
156 :
157 : void writePositionVector(tcpip::Storage& outputStorage, const libsumo::TraCIPositionVector& shape);
158 :
159 :
160 : /// @name Helpers for reading and checking values
161 : /// @{
162 :
163 : /** @brief Reads the value type and a double, verifying the type
164 : *
165 : * @param[in, changed] inputStorage The storage to read from
166 : * @param[out] into Holder of the read value
167 : * @return Whether a double value was given (by data type)
168 : */
169 : bool readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into);
170 :
171 :
172 : /** @brief Reads the value type and a string, verifying the type
173 : *
174 : * @param[in, changed] inputStorage The storage to read from
175 : * @param[out] into Holder of the read value
176 : * @return Whether a string value was given (by data type)
177 : */
178 : bool readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into);
179 :
180 :
181 : /** @brief Reads the value type and a string list, verifying the type
182 : *
183 : * @param[in, changed] inputStorage The storage to read from
184 : * @param[out] into Holder of the read value
185 : * @return Whether a double value was given (by data type)
186 : */
187 : bool readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into);
188 :
189 :
190 : /** @brief Reads the value type and a double list, verifying the type
191 : *
192 : * @param[in, changed] inputStorage The storage to read from
193 : * @param[out] into Holder of the read value
194 : * @return Whether a double value was given (by data type)
195 : */
196 : bool readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into);
197 :
198 :
199 : /** @brief Reads the value type and a color, verifying the type
200 : *
201 : * @param[in, changed] inputStorage The storage to read from
202 : * @param[out] into Holder of the read value
203 : * @return Whether a color was given (by data type)
204 : */
205 : bool readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into);
206 :
207 :
208 : /** @brief Reads the value type and a 2D position, verifying the type
209 : *
210 : * @param[in, changed] inputStorage The storage to read from
211 : * @param[out] into Holder of the read value
212 : * @return Whether a 2D position was given (by data type)
213 : */
214 : bool readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into);
215 :
216 :
217 : /** @brief Reads the value type and a byte, verifying the type
218 : *
219 : * @param[in, changed] inputStorage The storage to read from
220 : * @param[out] into Holder of the read value
221 : * @return Whether a byte was given (by data type)
222 : */
223 : bool readTypeCheckingByte(tcpip::Storage& inputStorage, int& into);
224 :
225 :
226 : /** @brief Reads the value type and an unsigned byte, verifying the type
227 : *
228 : * @param[in, changed] inputStorage The storage to read from
229 : * @param[out] into Holder of the read value
230 : * @return Whether an unsigned byte was given (by data type)
231 : */
232 : bool readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into);
233 :
234 :
235 : /** @brief Reads the value type and a polygon, verifying the type
236 : *
237 : * @param[in, changed] inputStorage The storage to read from
238 : * @param[out] into Holder of the read value
239 : * @return Whether an unsigned byte was given (by data type)
240 : */
241 : bool readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into);
242 : /// @}
243 :
244 :
245 : /// @brief updates myTargetTime and resets vehicle state changes after loading a simulation state
246 : /// @note Used in MSStateHandler to update the server's time after loading a state
247 : void stateLoaded(SUMOTime targetTime);
248 :
249 : std::vector<std::string>& getLoadArgs() {
250 13 : return myLoadArgs;
251 : }
252 :
253 : /// @name VariableWrapper interface
254 : /// @{
255 : void initWrapper(const int domainID, const int variable, const std::string& objID);
256 : bool wrapConnectionVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIConnection>& value);
257 : bool wrapDouble(const std::string& objID, const int variable, const double value);
258 : bool wrapInt(const std::string& objID, const int variable, const int value);
259 : bool wrapString(const std::string& objID, const int variable, const std::string& value);
260 : bool wrapStringList(const std::string& objID, const int variable, const std::vector<std::string>& value);
261 : bool wrapDoubleList(const std::string& objID, const int variable, const std::vector<double>& value);
262 : bool wrapPosition(const std::string& objID, const int variable, const libsumo::TraCIPosition& value);
263 : bool wrapPositionVector(const std::string& objID, const int variable, const libsumo::TraCIPositionVector& value);
264 : bool wrapColor(const std::string& objID, const int variable, const libsumo::TraCIColor& value);
265 : bool wrapStringDoublePair(const std::string& objID, const int variable, const std::pair<std::string, double>& value);
266 : bool wrapStringDoublePairList(const std::string& objID, const int variable, const std::vector<std::pair<std::string, double> >& value);
267 : bool wrapStringPair(const std::string& objID, const int variable, const std::pair<std::string, std::string>& value);
268 : bool wrapIntPair(const std::string& objID, const int variable, const std::pair<int, int>& value);
269 : bool wrapStage(const std::string& objID, const int variable, const libsumo::TraCIStage& value);
270 : bool wrapReservationVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIReservation>& value);
271 : bool wrapLogicVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCILogic>& value);
272 : bool wrapLinkVectorVector(const std::string& objID, const int variable, const std::vector<std::vector<libsumo::TraCILink> >& value);
273 : bool wrapSignalConstraintVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCISignalConstraint>& value);
274 : bool wrapJunctionFoeVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIJunctionFoe>& value);
275 : bool wrapNextStopDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCINextStopData>& value);
276 : bool wrapVehicleDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIVehicleData>& value);
277 : bool wrapBestLanesDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIBestLanesData>& value);
278 : bool wrapNextTLSDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCINextTLSData>& value);
279 : tcpip::Storage& getWrapperStorage();
280 : /// @}
281 :
282 :
283 : private:
284 : /** @brief Constructor
285 : * @param[in] port The port to listen to (to open)
286 : */
287 : TraCIServer(const SUMOTime begin, const int port, const int numClients);
288 :
289 :
290 : /// @brief Destructor
291 : virtual ~TraCIServer();
292 :
293 :
294 :
295 : struct SocketInfo {
296 : public:
297 : /// @brief constructor
298 : SocketInfo(tcpip::Socket* socket, SUMOTime t)
299 2713 : : targetTime(t), socket(socket) {}
300 : /// @brief destructor
301 2705 : ~SocketInfo() {
302 2705 : delete socket;
303 2705 : }
304 : /// @brief next point of action for the client
305 : SUMOTime targetTime;
306 : /// @brief whether a "half step" has been done, executing only the move
307 : bool executeMove = false;
308 : /// @brief Socket object for this client
309 : tcpip::Socket* socket;
310 : /// @brief container for vehicle state changes since last step taken by this client
311 : std::map<MSNet::VehicleState, std::vector<std::string> > vehicleStateChanges;
312 : /// @brief container for transportable state changes since last step taken by this client
313 : std::map<MSNet::TransportableState, std::vector<std::string> > transportableStateChanges;
314 : private:
315 : SocketInfo(const SocketInfo&);
316 : };
317 :
318 : /// @name Server-internal command handling
319 : /// @{
320 :
321 : /** @brief Returns the TraCI-version
322 : * @return Always true
323 : */
324 : bool commandGetVersion();
325 :
326 : /** @brief Handles subscriptions to send after a simstep2 command
327 : */
328 : void postProcessSimulationStep();
329 : /// @}
330 :
331 :
332 : /// @brief Reads the next command ID from the input storage
333 : /// @return the command ID
334 : /// @param[out] the version with reference parameters provides information on the command start position and length used in dispatchCommand for checking purposes
335 : int readCommandID(int& commandStart, int& commandLength);
336 :
337 : /// @brief Handles command, writes response to myOutputStorage
338 : int dispatchCommand();
339 :
340 : /// @brief Called once after connection of all clients for executing SET_ORDER (and possibly prior GET_VERSION) commands,
341 : /// that should be executed before simulation starts (in processCommandsUntilNextSimStep()).
342 : void checkClientOrdering();
343 :
344 : /// @brief checks for and processes reordering requests (relevant for multiple clients)
345 : void processReorderingRequests();
346 :
347 : /// @brief get the minimal next target time among all clients
348 : SUMOTime nextTargetTime() const;
349 :
350 : /// @brief send out subscription results (actually just the content of myOutputStorage) to clients which will act in this step (i.e. with client target time <= myTargetTime)
351 : void sendOutputToAll() const;
352 :
353 : /// @brief sends an empty response to a simstep command to the current client. (This applies to a situation where the TraCI step frequency is higher than the SUMO step frequency)
354 : void sendSingleSimStepResponse();
355 :
356 : /// @brief removes myCurrentSocket from mySockets and returns an iterator pointing to the next member according to the ordering
357 : std::map<int, SocketInfo*>::iterator removeCurrentSocket();
358 :
359 :
360 : private:
361 : /// @brief Singleton instance of the server
362 : static TraCIServer* myInstance;
363 :
364 : /// @brief Whether the connection was set to be to close
365 : static bool myDoCloseConnection;
366 :
367 : /// @brief The socket connections to the clients
368 : /// the first component (index) determines the client's order (lowest index's commands are processed first), @see CMD_SETORDER
369 : std::map<int, SocketInfo*> mySockets;
370 :
371 : /// @brief This stores the setOrder(int) requests of the clients.
372 : std::map<int, SocketInfo*> mySocketReorderRequests;
373 :
374 : /// @brief The currently active client socket
375 : std::map<int, SocketInfo*>::iterator myCurrentSocket;
376 :
377 : /// @brief The time step to reach until processing the next commands
378 : SUMOTime myTargetTime;
379 :
380 : /// @brief The storage to read from
381 : tcpip::Storage myInputStorage;
382 :
383 : /// @brief The storage to write to
384 : tcpip::Storage myOutputStorage;
385 :
386 : /// @brief A temporary storage to let the wrapper write to
387 : tcpip::Storage myWrapperStorage;
388 :
389 : /// @brief The last timestep's subscription results
390 : tcpip::Storage mySubscriptionCache;
391 :
392 : /// @brief Map of commandIds -> their executors; applicable if the executor applies to the method footprint
393 : std::map<int, CmdExecutor> myExecutors;
394 :
395 : /// @brief Set of variables which have parameters
396 : std::set<std::pair<int, int>> myParameterized;
397 :
398 : std::vector<std::string> myLoadArgs;
399 :
400 : /// @brief The list of known, still valid subscriptions
401 : std::vector<libsumo::Subscription> mySubscriptions;
402 :
403 : /// @brief The last modified context subscription (the one to add a filter to, see @addSubscriptionFilter(), currently only for vehicle to vehicle context)
404 : libsumo::Subscription* myLastContextSubscription;
405 :
406 : /// @brief Changes in the states of simulated vehicles
407 : /// @note
408 : /// Server cache myVehicleStateChanges is used for managing last steps subscription updates
409 : /// and for client information in case that myAmEmbedded==true, which implies a single client.
410 : /// For the potential multiclient case (myAmEmbedded==false), each socket in mySockets is associated
411 : /// with a proper vehicleStateChanges container mySockets[...].second->vehicleStateChanges
412 : /// Performance could be improved if for a single client, myVehicleStateChanges is used only.
413 : std::map<MSNet::VehicleState, std::vector<std::string> > myVehicleStateChanges;
414 :
415 : /// @brief Changes in the states of simulated transportables
416 : /// @note
417 : /// Server cache myTransportableStateChanges is used for managing last steps subscription updates
418 : /// and for client information in case that myAmEmbedded==true, which implies a single client.
419 : /// For the potential multiclient case (myAmEmbedded==false), each socket in mySockets is associated
420 : /// with a proper TransportableStateChanges container mySockets[...].second->TransportableStateChanges
421 : /// Performance could be improved if for a single client, myTransportableStateChanges is used only.
422 : std::map<MSNet::TransportableState, std::vector<std::string> > myTransportableStateChanges;
423 :
424 : private:
425 : bool addObjectVariableSubscription(const int commandId, const bool hasContext);
426 : void initialiseSubscription(libsumo::Subscription& s);
427 : void removeSubscription(int commandId, const std::string& identity, int domain);
428 : bool processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
429 : std::string& errors);
430 :
431 :
432 : bool addSubscriptionFilter();
433 : void removeFilters();
434 : void addSubscriptionFilterLanes(std::vector<int> lanes);
435 : void addSubscriptionFilterNoOpposite();
436 : void addSubscriptionFilterDownstreamDistance(double dist);
437 : void addSubscriptionFilterUpstreamDistance(double dist);
438 : void addSubscriptionFilterLeadFollow();
439 : // TODO: for libsumo, implement convenience definitions present in python client:
440 : // void addSubscriptionFilterCF();
441 : // void addSubscriptionFilterLC(int direction);
442 : void addSubscriptionFilterTurn(double dist);
443 : void addSubscriptionFilterVClass(SVCPermissions vClasses);
444 : void addSubscriptionFilterVType(std::set<std::string> vTypes);
445 : /** @brief Filter only vehicles within field of vision
446 : *
447 : * @param[in] openingAngle The opening angle of the circle sector
448 : */
449 : void addSubscriptionFilterFieldOfVision(double openingAngle);
450 : /** @brief Filter only vehicles within the given lateral distance
451 : *
452 : * @param[in] dist The lateral distance
453 : */
454 : void addSubscriptionFilterLateralDistance(double dist);
455 :
456 : /// @brief check whether a found objID refers to the central object of a context subscription
457 : bool centralObject(const libsumo::Subscription& s, const std::string& objID);
458 :
459 :
460 : private:
461 : /// @brief Invalidated assignment operator
462 : TraCIServer& operator=(const TraCIServer& s) = delete;
463 :
464 : };
|