LCOV - code coverage report
Current view: top level - src/traci-server - TraCIServer.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 11 12 91.7 %
Date: 2024-05-07 15:28:01 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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   148541123 :         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      108750 :         if (myCurrentSocket == mySockets.end()) {
     137             :             // Requested in context of a subscription update
     138       32930 :             return myVehicleStateChanges;
     139             :         } else {
     140             :             // Requested in the context of a custom query by active client
     141       75820 :             return myCurrentSocket->second->vehicleStateChanges;
     142             :         }
     143             :     }
     144             : 
     145             :     const std::map<MSNet::TransportableState, std::vector<std::string> >& getTransportableStateChanges() const {
     146          48 :         if (myCurrentSocket == mySockets.end()) {
     147             :             // Requested in context of a subscription update
     148           0 :             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 an int, 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 an integer value was given (by data type)
     168             :      */
     169             :     bool readTypeCheckingInt(tcpip::Storage& inputStorage, int& into);
     170             : 
     171             : 
     172             :     /** @brief Reads the value type and a double, 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 double value was given (by data type)
     177             :      */
     178             :     bool readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into);
     179             : 
     180             : 
     181             :     /** @brief Reads the value type and a string, 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 string value was given (by data type)
     186             :      */
     187             :     bool readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into);
     188             : 
     189             : 
     190             :     /** @brief Reads the value type and a string 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 readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into);
     197             : 
     198             : 
     199             :     /** @brief Reads the value type and a double list, 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 double value was given (by data type)
     204             :      */
     205             :     bool readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into);
     206             : 
     207             : 
     208             :     /** @brief Reads the value type and a color, 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 color was given (by data type)
     213             :      */
     214             :     bool readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into);
     215             : 
     216             : 
     217             :     /** @brief Reads the value type and a 2D position, 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 2D position was given (by data type)
     222             :      */
     223             :     bool readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into);
     224             : 
     225             : 
     226             :     /** @brief Reads the value type and a 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 a byte was given (by data type)
     231             :      */
     232             :     bool readTypeCheckingByte(tcpip::Storage& inputStorage, int& into);
     233             : 
     234             : 
     235             :     /** @brief Reads the value type and an unsigned byte, 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 readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into);
     242             : 
     243             : 
     244             :     /** @brief Reads the value type and a polygon, verifying the type
     245             :      *
     246             :      * @param[in, changed] inputStorage The storage to read from
     247             :      * @param[out] into Holder of the read value
     248             :      * @return Whether an unsigned byte was given (by data type)
     249             :      */
     250             :     bool readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into);
     251             :     /// @}
     252             : 
     253             : 
     254             :     /// @brief updates myTargetTime and resets vehicle state changes after loading a simulation state
     255             :     /// @note  Used in MSStateHandler to update the server's time after loading a state
     256             :     void stateLoaded(SUMOTime targetTime);
     257             : 
     258             :     std::vector<std::string>& getLoadArgs() {
     259          17 :         return myLoadArgs;
     260             :     }
     261             : 
     262             :     /// @name VariableWrapper interface
     263             :     /// @{
     264             :     void initWrapper(const int domainID, const int variable, const std::string& objID);
     265             :     bool wrapDouble(const std::string& objID, const int variable, const double value);
     266             :     bool wrapInt(const std::string& objID, const int variable, const int value);
     267             :     bool wrapString(const std::string& objID, const int variable, const std::string& value);
     268             :     bool wrapStringList(const std::string& objID, const int variable, const std::vector<std::string>& value);
     269             :     bool wrapDoubleList(const std::string& objID, const int variable, const std::vector<double>& value);
     270             :     bool wrapPosition(const std::string& objID, const int variable, const libsumo::TraCIPosition& value);
     271             :     bool wrapPositionVector(const std::string& objID, const int variable, const libsumo::TraCIPositionVector& value);
     272             :     bool wrapColor(const std::string& objID, const int variable, const libsumo::TraCIColor& value);
     273             :     bool wrapStringDoublePair(const std::string& objID, const int variable, const std::pair<std::string, double>& value);
     274             :     bool wrapStringPair(const std::string& objID, const int variable, const std::pair<std::string, std::string>& value);
     275             :     tcpip::Storage& getWrapperStorage();
     276             :     /// @}
     277             : 
     278             : 
     279             : private:
     280             :     /** @brief Constructor
     281             :      * @param[in] port The port to listen to (to open)
     282             :      */
     283             :     TraCIServer(const SUMOTime begin, const int port, const int numClients);
     284             : 
     285             : 
     286             :     /// @brief Destructor
     287             :     virtual ~TraCIServer();
     288             : 
     289             : 
     290             : 
     291             :     struct SocketInfo {
     292             :     public:
     293             :         /// @brief constructor
     294             :         SocketInfo(tcpip::Socket* socket, SUMOTime t)
     295        3385 :             : targetTime(t), socket(socket) {}
     296             :         /// @brief destructor
     297        3373 :         ~SocketInfo() {
     298        3373 :             delete socket;
     299        3373 :         }
     300             :         /// @brief next point of action for the client
     301             :         SUMOTime targetTime;
     302             :         /// @brief whether a "half step" has been done, executing only the move
     303             :         bool executeMove = false;
     304             :         /// @brief Socket object for this client
     305             :         tcpip::Socket* socket;
     306             :         /// @brief container for vehicle state changes since last step taken by this client
     307             :         std::map<MSNet::VehicleState, std::vector<std::string> > vehicleStateChanges;
     308             :         /// @brief container for transportable state changes since last step taken by this client
     309             :         std::map<MSNet::TransportableState, std::vector<std::string> > transportableStateChanges;
     310             :     private:
     311             :         SocketInfo(const SocketInfo&);
     312             :     };
     313             : 
     314             :     /// @name Server-internal command handling
     315             :     /// @{
     316             : 
     317             :     /** @brief Returns the TraCI-version
     318             :      * @return Always true
     319             :      */
     320             :     bool commandGetVersion();
     321             : 
     322             :     /** @brief Handles subscriptions to send after a simstep2 command
     323             :      */
     324             :     void postProcessSimulationStep();
     325             :     /// @}
     326             : 
     327             : 
     328             :     /// @brief Reads the next command ID from the input storage
     329             :     /// @return the command ID
     330             :     /// @param[out] the version with reference parameters provides information on the command start position and length used in dispatchCommand for checking purposes
     331             :     int readCommandID(int& commandStart, int& commandLength);
     332             : 
     333             :     /// @brief Handles command, writes response to myOutputStorage
     334             :     int dispatchCommand();
     335             : 
     336             :     /// @brief Called once after connection of all clients for executing SET_ORDER (and possibly prior GET_VERSION) commands,
     337             :     ///        that should be executed before simulation starts (in processCommandsUntilNextSimStep()).
     338             :     void checkClientOrdering();
     339             : 
     340             :     /// @brief checks for and processes reordering requests (relevant for multiple clients)
     341             :     void processReorderingRequests();
     342             : 
     343             :     /// @brief get the minimal next target time among all clients
     344             :     SUMOTime nextTargetTime() const;
     345             : 
     346             :     /// @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)
     347             :     void sendOutputToAll() const;
     348             : 
     349             :     /// @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)
     350             :     void sendSingleSimStepResponse();
     351             : 
     352             :     /// @brief removes myCurrentSocket from mySockets and returns an iterator pointing to the next member according to the ordering
     353             :     std::map<int, SocketInfo*>::iterator removeCurrentSocket();
     354             : 
     355             : 
     356             : private:
     357             :     /// @brief Singleton instance of the server
     358             :     static TraCIServer* myInstance;
     359             : 
     360             :     /// @brief Whether the connection was set to be to close
     361             :     static bool myDoCloseConnection;
     362             : 
     363             :     /// @brief The socket connections to the clients
     364             :     /// the first component (index) determines the client's order (lowest index's commands are processed first), @see CMD_SETORDER
     365             :     std::map<int, SocketInfo*> mySockets;
     366             : 
     367             :     /// @brief This stores the setOrder(int) requests of the clients.
     368             :     std::map<int, SocketInfo*> mySocketReorderRequests;
     369             : 
     370             :     /// @brief The currently active client socket
     371             :     std::map<int, SocketInfo*>::iterator myCurrentSocket;
     372             : 
     373             :     /// @brief The time step to reach until processing the next commands
     374             :     SUMOTime myTargetTime;
     375             : 
     376             :     /// @brief The storage to read from
     377             :     tcpip::Storage myInputStorage;
     378             : 
     379             :     /// @brief The storage to write to
     380             :     tcpip::Storage myOutputStorage;
     381             : 
     382             :     /// @brief A temporary storage to let the wrapper write to
     383             :     tcpip::Storage myWrapperStorage;
     384             : 
     385             :     /// @brief The last timestep's subscription results
     386             :     tcpip::Storage mySubscriptionCache;
     387             : 
     388             :     /// @brief Map of commandIds -> their executors; applicable if the executor applies to the method footprint
     389             :     std::map<int, CmdExecutor> myExecutors;
     390             : 
     391             :     /// @brief Set of variables which have parameters
     392             :     std::set<std::pair<int, int>> myParameterized;
     393             : 
     394             :     std::vector<std::string> myLoadArgs;
     395             : 
     396             :     /// @brief The list of known, still valid subscriptions
     397             :     std::vector<libsumo::Subscription> mySubscriptions;
     398             : 
     399             :     /// @brief The last modified context subscription (the one to add a filter to, see @addSubscriptionFilter(), currently only for vehicle to vehicle context)
     400             :     libsumo::Subscription* myLastContextSubscription;
     401             : 
     402             :     /// @brief Changes in the states of simulated vehicles
     403             :     /// @note
     404             :     /// Server cache myVehicleStateChanges is used for managing last steps subscription updates
     405             :     /// and for client information in case that myAmEmbedded==true, which implies a single client.
     406             :     /// For the potential multiclient case (myAmEmbedded==false), each socket in mySockets is associated
     407             :     /// with a proper vehicleStateChanges container mySockets[...].second->vehicleStateChanges
     408             :     /// Performance could be improved if for a single client, myVehicleStateChanges is used only.
     409             :     std::map<MSNet::VehicleState, std::vector<std::string> > myVehicleStateChanges;
     410             : 
     411             :     /// @brief Changes in the states of simulated transportables
     412             :     /// @note
     413             :     /// Server cache myTransportableStateChanges is used for managing last steps subscription updates
     414             :     /// and for client information in case that myAmEmbedded==true, which implies a single client.
     415             :     /// For the potential multiclient case (myAmEmbedded==false), each socket in mySockets is associated
     416             :     /// with a proper TransportableStateChanges container mySockets[...].second->TransportableStateChanges
     417             :     /// Performance could be improved if for a single client, myTransportableStateChanges is used only.
     418             :     std::map<MSNet::TransportableState, std::vector<std::string> > myTransportableStateChanges;
     419             : 
     420             : private:
     421             :     bool addObjectVariableSubscription(const int commandId, const bool hasContext);
     422             :     void initialiseSubscription(libsumo::Subscription& s);
     423             :     void removeSubscription(int commandId, const std::string& identity, int domain);
     424             :     bool processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
     425             :                                    std::string& errors);
     426             : 
     427             : 
     428             :     bool addSubscriptionFilter();
     429             :     void removeFilters();
     430             :     void addSubscriptionFilterLanes(std::vector<int> lanes);
     431             :     void addSubscriptionFilterNoOpposite();
     432             :     void addSubscriptionFilterDownstreamDistance(double dist);
     433             :     void addSubscriptionFilterUpstreamDistance(double dist);
     434             :     void addSubscriptionFilterLeadFollow();
     435             :     // TODO: for libsumo, implement convenience definitions present in python client:
     436             :     //    void addSubscriptionFilterCF();
     437             :     //    void addSubscriptionFilterLC(int direction);
     438             :     void addSubscriptionFilterTurn(double dist);
     439             :     void addSubscriptionFilterVClass(SVCPermissions vClasses);
     440             :     void addSubscriptionFilterVType(std::set<std::string> vTypes);
     441             :     /** @brief Filter only vehicles within field of vision
     442             :      *
     443             :      * @param[in] openingAngle The opening angle of the circle sector
     444             :      */
     445             :     void addSubscriptionFilterFieldOfVision(double openingAngle);
     446             :     /** @brief Filter only vehicles within the given lateral distance
     447             :      *
     448             :      * @param[in] dist The lateral distance
     449             :      */
     450             :     void addSubscriptionFilterLateralDistance(double dist);
     451             : 
     452             :     /// @brief check whether a found objID refers to the central object of a context subscription
     453             :     bool centralObject(const libsumo::Subscription& s, const std::string& objID);
     454             : 
     455             : 
     456             : private:
     457             :     /// @brief Invalidated assignment operator
     458             :     TraCIServer& operator=(const TraCIServer& s) = delete;
     459             : 
     460             : };

Generated by: LCOV version 1.14