LCOV - code coverage report
Current view: top level - src/traci-server - TraCIServer.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 12 12
Test Date: 2025-11-13 15:38:19 Functions: 100.0 % 1 1

            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              : };
        

Generated by: LCOV version 2.0-1