LCOV - code coverage report
Current view: top level - src/traci-server - TraCIServer.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.8 % 934 895
Test Date: 2025-12-06 15:35:27 Functions: 97.1 % 68 66

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2007-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.cpp
      15              : /// @author  Axel Wegener
      16              : /// @author  Friedemann Wesner
      17              : /// @author  Christoph Sommer
      18              : /// @author  Jakob Erdmann
      19              : /// @author  Daniel Krajzewicz
      20              : /// @author  Thimor Bohn
      21              : /// @author  Tino Morenz
      22              : /// @author  Laura Bieker
      23              : /// @author  Michael Behrisch
      24              : /// @author  Mario Krumnow
      25              : /// @author  Leonhard Luecken
      26              : /// @date    2007/10/24
      27              : ///
      28              : // TraCI server used to control sumo by a remote TraCI client (e.g., ns2)
      29              : /****************************************************************************/
      30              : #include <config.h>
      31              : 
      32              : #ifdef HAVE_VERSION_H
      33              : #include <version.h>
      34              : #endif
      35              : 
      36              : #include <string>
      37              : #include <cmath>
      38              : #include <map>
      39              : #include <iostream>
      40              : #include <algorithm>
      41              : #include <foreign/tcpip/socket.h>
      42              : #include <foreign/tcpip/storage.h>
      43              : #include <utils/common/SUMOTime.h>
      44              : #include <utils/router/DijkstraRouter.h>
      45              : #include <utils/common/NamedObjectCont.h>
      46              : #include <utils/common/RandHelper.h>
      47              : #include <utils/common/MsgHandler.h>
      48              : #include <utils/vehicle/SUMOVehicleParameter.h>
      49              : #include <utils/shapes/PointOfInterest.h>
      50              : #include <utils/shapes/ShapeContainer.h>
      51              : #include <utils/xml/XMLSubSys.h>
      52              : #include <microsim/MSNet.h>
      53              : #include <microsim/MSVehicle.h>
      54              : #include <microsim/MSEdge.h>
      55              : #include <microsim/MSJunctionControl.h>
      56              : #include <microsim/transportables/MSTransportableControl.h>
      57              : #include <microsim/MSJunction.h>
      58              : #include <microsim/MSEdgeControl.h>
      59              : #include <microsim/MSLane.h>
      60              : #include <microsim/MSGlobals.h>
      61              : #include <microsim/traffic_lights/MSTLLogicControl.h>
      62              : #include <libsumo/Helper.h>
      63              : #include <libsumo/StorageHelper.h>
      64              : #include <libsumo/libsumo.h>
      65              : #include <libsumo/Subscription.h>
      66              : #include <libsumo/TraCIConstants.h>
      67              : #include "TraCIServer.h"
      68              : #include "TraCIServerAPI_InductionLoop.h"
      69              : #include "TraCIServerAPI_Junction.h"
      70              : #include "TraCIServerAPI_Lane.h"
      71              : #include "TraCIServerAPI_MultiEntryExit.h"
      72              : #include "TraCIServerAPI_LaneArea.h"
      73              : #include "TraCIServerAPI_TrafficLight.h"
      74              : #include "TraCIServerAPI_Vehicle.h"
      75              : #include "TraCIServerAPI_VehicleType.h"
      76              : #include "TraCIServerAPI_Route.h"
      77              : #include "TraCIServerAPI_POI.h"
      78              : #include "TraCIServerAPI_Polygon.h"
      79              : #include "TraCIServerAPI_Edge.h"
      80              : #include "TraCIServerAPI_Simulation.h"
      81              : #include "TraCIServerAPI_Person.h"
      82              : #include "TraCIServerAPI_Calibrator.h"
      83              : #include "TraCIServerAPI_BusStop.h"
      84              : #include "TraCIServerAPI_ParkingArea.h"
      85              : #include "TraCIServerAPI_ChargingStation.h"
      86              : #include "TraCIServerAPI_RouteProbe.h"
      87              : #include "TraCIServerAPI_Rerouter.h"
      88              : #include "TraCIServerAPI_VariableSpeedSign.h"
      89              : #include "TraCIServerAPI_MeanData.h"
      90              : #include "TraCIServerAPI_OverheadWire.h"
      91              : 
      92              : 
      93              : // ===========================================================================
      94              : // debug constants
      95              : // ===========================================================================
      96              : //#define DEBUG_MULTI_CLIENTS
      97              : //#define DEBUG_SUBSCRIPTIONS
      98              : //#define DEBUG_SUBSCRIPTION_FILTERS
      99              : //#define DEBUG_RAW_INPUT
     100              : 
     101              : 
     102              : // ===========================================================================
     103              : // static member definitions
     104              : // ===========================================================================
     105              : TraCIServer* TraCIServer::myInstance = nullptr;
     106              : bool TraCIServer::myDoCloseConnection = false;
     107              : 
     108              : 
     109              : // ===========================================================================
     110              : // method definitions
     111              : // ===========================================================================
     112              : void
     113     17554030 : TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
     114     17554030 :     myWrapperStorage.reset();
     115     17554030 :     myWrapperStorage.writeUnsignedByte(domainID);
     116     17554030 :     myWrapperStorage.writeUnsignedByte(variable);
     117     17554030 :     myWrapperStorage.writeString(objID);
     118     17554030 : }
     119              : 
     120              : 
     121              : bool
     122           51 : TraCIServer::wrapConnectionVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIConnection>& value) {
     123           51 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 8);
     124           51 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     125          139 :     for (const libsumo::TraCIConnection& c : value) {
     126           88 :         StoHelp::writeTypedString(myWrapperStorage, c.approachedLane);
     127           88 :         StoHelp::writeTypedString(myWrapperStorage, c.approachedInternal);
     128           88 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasPrio);
     129           88 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.isOpen);
     130           88 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.hasFoe);
     131           88 :         StoHelp::writeTypedString(myWrapperStorage, c.state);
     132           88 :         StoHelp::writeTypedString(myWrapperStorage, c.direction);
     133           88 :         StoHelp::writeTypedDouble(myWrapperStorage, c.length);
     134              :     }
     135           51 :     return true;
     136              : }
     137              : 
     138              : 
     139              : bool
     140      4410601 : TraCIServer::wrapDouble(const std::string& /* objID */, const int /* variable */, const double value) {
     141      4410601 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
     142      4410601 :     myWrapperStorage.writeDouble(value);
     143      4410601 :     return true;
     144              : }
     145              : 
     146              : 
     147              : bool
     148      7710381 : TraCIServer::wrapInt(const std::string& /* objID */, const int /* variable */, const int value) {
     149      7710381 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_INTEGER);
     150      7710381 :     myWrapperStorage.writeInt(value);
     151      7710381 :     return true;
     152              : }
     153              : 
     154              : 
     155              : bool
     156      4167838 : TraCIServer::wrapString(const std::string& /* objID */, const int /* variable */, const std::string& value) {
     157      4167838 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
     158      4167838 :     myWrapperStorage.writeString(value);
     159      4167838 :     return true;
     160              : }
     161              : 
     162              : 
     163              : bool
     164       201251 : TraCIServer::wrapStringList(const std::string& /* objID */, const int /* variable */, const std::vector<std::string>& value) {
     165       201251 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
     166       201251 :     myWrapperStorage.writeStringList(value);
     167       201251 :     return true;
     168              : }
     169              : 
     170              : 
     171              : bool
     172           18 : TraCIServer::wrapDoubleList(const std::string& /* objID */, const int /* variable */, const std::vector<double>& value) {
     173           18 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLELIST);
     174           18 :     myWrapperStorage.writeDoubleList(value);
     175           18 :     return true;
     176              : }
     177              : 
     178              : 
     179              : bool
     180       908479 : TraCIServer::wrapPosition(const std::string& /* objID */, const int variable, const libsumo::TraCIPosition& value) {
     181              :     const bool includeZ = variable == libsumo::VAR_POSITION3D;
     182      1815714 :     myWrapperStorage.writeUnsignedByte(includeZ ? libsumo::POSITION_3D : libsumo::POSITION_2D);
     183       908479 :     myWrapperStorage.writeDouble(value.x);
     184       908479 :     myWrapperStorage.writeDouble(value.y);
     185       908479 :     if (includeZ) {
     186         1244 :         myWrapperStorage.writeDouble(value.z);
     187              :     }
     188       908479 :     return true;
     189              : }
     190              : 
     191              : 
     192              : bool
     193        12129 : TraCIServer::wrapPositionVector(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIPositionVector& shape) {
     194        12129 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
     195        12129 :     if (shape.value.size() < 256) {
     196        12126 :         myWrapperStorage.writeUnsignedByte((int)shape.value.size());
     197              :     } else {
     198            3 :         myWrapperStorage.writeUnsignedByte(0);
     199            3 :         myWrapperStorage.writeInt((int)shape.value.size());
     200              :     }
     201        43437 :     for (const libsumo::TraCIPosition& pos : shape.value) {
     202        31308 :         myWrapperStorage.writeDouble(pos.x);
     203        31308 :         myWrapperStorage.writeDouble(pos.y);
     204              :     }
     205        12129 :     return true;
     206              : }
     207              : 
     208              : 
     209              : bool
     210          740 : TraCIServer::wrapColor(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIColor& value) {
     211          740 :     myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COLOR);
     212          740 :     myWrapperStorage.writeUnsignedByte(value.r);
     213          740 :     myWrapperStorage.writeUnsignedByte(value.g);
     214          740 :     myWrapperStorage.writeUnsignedByte(value.b);
     215          740 :     myWrapperStorage.writeUnsignedByte(value.a);
     216          740 :     return true;
     217              : }
     218              : 
     219              : 
     220              : bool
     221        22405 : TraCIServer::wrapStringDoublePair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, double>& value) {
     222        22405 :     StoHelp::writeCompound(myWrapperStorage, 2);
     223        22405 :     StoHelp::writeTypedString(myWrapperStorage, value.first);
     224        22405 :     StoHelp::writeTypedDouble(myWrapperStorage, value.second);
     225        22405 :     return true;
     226              : }
     227              : 
     228              : 
     229              : bool
     230         2574 : TraCIServer::wrapStringDoublePairList(const std::string& /* objID */, const int /* variable */, const std::vector<std::pair<std::string, double> >& value) {
     231         2574 :     StoHelp::writeCompound(myWrapperStorage, (int)value.size());
     232         3990 :     for (const auto& p : value) {
     233         1416 :         myWrapperStorage.writeString(p.first);
     234         1416 :         myWrapperStorage.writeDouble(p.second);
     235              :     }
     236         2574 :     return true;
     237              : }
     238              : 
     239              : 
     240              : bool
     241          314 : TraCIServer::wrapStringPair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, std::string>& value) {
     242          314 :     StoHelp::writeCompound(myWrapperStorage, 2);
     243          314 :     StoHelp::writeTypedString(myWrapperStorage, value.first);
     244          314 :     StoHelp::writeTypedString(myWrapperStorage, value.second);
     245          314 :     return true;
     246              : }
     247              : 
     248              : 
     249              : bool
     250         9383 : TraCIServer::wrapIntPair(const std::string& /* objID */, const int /* variable */, const std::pair<int, int>& value) {
     251         9383 :     StoHelp::writeCompound(myWrapperStorage, 2);
     252         9383 :     StoHelp::writeTypedInt(myWrapperStorage, value.first);
     253         9383 :     StoHelp::writeTypedInt(myWrapperStorage, value.second);
     254         9383 :     return true;
     255              : }
     256              : 
     257              : 
     258              : bool
     259          418 : TraCIServer::wrapStage(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIStage& value) {
     260          418 :     StoHelp::writeStage(myWrapperStorage, value);
     261          418 :     return true;
     262              : }
     263              : 
     264              : 
     265              : bool
     266         3132 : TraCIServer::wrapReservationVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIReservation>& value) {
     267         3132 :     StoHelp::writeCompound(myWrapperStorage, (int)value.size());
     268         8165 :     for (const libsumo::TraCIReservation& r : value) {
     269              :         StoHelp::writeCompound(myWrapperStorage, 10);
     270         5033 :         StoHelp::writeTypedString(myWrapperStorage, r.id);
     271         5033 :         StoHelp::writeTypedStringList(myWrapperStorage, r.persons);
     272         5033 :         StoHelp::writeTypedString(myWrapperStorage, r.group);
     273         5033 :         StoHelp::writeTypedString(myWrapperStorage, r.fromEdge);
     274         5033 :         StoHelp::writeTypedString(myWrapperStorage, r.toEdge);
     275         5033 :         StoHelp::writeTypedDouble(myWrapperStorage, r.departPos);
     276         5033 :         StoHelp::writeTypedDouble(myWrapperStorage, r.arrivalPos);
     277         5033 :         StoHelp::writeTypedDouble(myWrapperStorage, r.depart);
     278         5033 :         StoHelp::writeTypedDouble(myWrapperStorage, r.reservationTime);
     279         5033 :         StoHelp::writeTypedInt(myWrapperStorage, r.state);
     280              :     }
     281         3132 :     return true;
     282              : }
     283              : 
     284              : 
     285              : bool
     286           62 : TraCIServer::wrapLogicVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCILogic>& value) {
     287           62 :     StoHelp::writeCompound(myWrapperStorage, (int)value.size());
     288          163 :     for (const libsumo::TraCILogic& logic : value) {
     289              :         StoHelp::writeCompound(myWrapperStorage, 5);
     290          101 :         StoHelp::writeTypedString(myWrapperStorage, logic.programID);
     291          101 :         StoHelp::writeTypedInt(myWrapperStorage, logic.type);
     292          101 :         StoHelp::writeTypedInt(myWrapperStorage, logic.currentPhaseIndex);
     293          101 :         StoHelp::writeCompound(myWrapperStorage, (int)logic.phases.size());
     294          788 :         for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
     295              :             StoHelp::writeCompound(myWrapperStorage, 6);
     296          687 :             StoHelp::writeTypedDouble(myWrapperStorage, phase->duration);
     297          687 :             StoHelp::writeTypedString(myWrapperStorage, phase->state);
     298          687 :             StoHelp::writeTypedDouble(myWrapperStorage, phase->minDur);
     299          687 :             StoHelp::writeTypedDouble(myWrapperStorage, phase->maxDur);
     300          687 :             StoHelp::writeCompound(myWrapperStorage, (int)phase->next.size());
     301          803 :             for (int n : phase->next) {
     302              :                 StoHelp::writeTypedInt(myWrapperStorage, n);
     303              :             }
     304          687 :             StoHelp::writeTypedString(myWrapperStorage, phase->name);
     305              :         }
     306          101 :         StoHelp::writeCompound(myWrapperStorage, (int)logic.subParameter.size());
     307          107 :         for (const auto& item : logic.subParameter) {
     308           24 :             StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string> {item.first, item.second});
     309              :         }
     310              :     }
     311           62 :     return true;
     312            0 : }
     313              : 
     314              : 
     315              : bool
     316           32 : TraCIServer::wrapLinkVectorVector(const std::string& /* objID */, const int /* variable */, const std::vector<std::vector<libsumo::TraCILink> >& value) {
     317              :     int cnt = 1;
     318          551 :     for (const std::vector<libsumo::TraCILink>& sublinks : value) {
     319          519 :         cnt += (int)sublinks.size() + 1;
     320              :     }
     321           32 :     StoHelp::writeCompound(myWrapperStorage, cnt);
     322           32 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     323          551 :     for (const std::vector<libsumo::TraCILink>& sublinks : value) {
     324          519 :         StoHelp::writeTypedInt(myWrapperStorage, (int)sublinks.size());
     325         1038 :         for (const libsumo::TraCILink& link : sublinks) {
     326         2595 :             StoHelp::writeTypedStringList(myWrapperStorage, std::vector<std::string>({ link.fromLane, link.toLane, link.viaLane }));
     327              :         }
     328              :     }
     329           32 :     return true;
     330            0 : }
     331              : 
     332              : 
     333              : bool
     334          813 : TraCIServer::wrapSignalConstraintVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCISignalConstraint>& value) {
     335          813 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
     336          813 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     337         1479 :     for (const auto& c : value) {
     338          666 :         StoHelp::writeConstraint(myWrapperStorage, c);
     339              :     }
     340          813 :     return true;
     341              : }
     342              : 
     343              : 
     344              : bool
     345           96 : TraCIServer::wrapJunctionFoeVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIJunctionFoe>& value) {
     346           96 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 9);
     347           96 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     348          186 :     for (const auto& c : value) {
     349           90 :         StoHelp::writeTypedString(myWrapperStorage, c.foeId);
     350           90 :         StoHelp::writeTypedDouble(myWrapperStorage, c.egoDist);
     351           90 :         StoHelp::writeTypedDouble(myWrapperStorage, c.foeDist);
     352           90 :         StoHelp::writeTypedDouble(myWrapperStorage, c.egoExitDist);
     353           90 :         StoHelp::writeTypedDouble(myWrapperStorage, c.foeExitDist);
     354           90 :         StoHelp::writeTypedString(myWrapperStorage, c.egoLane);
     355           90 :         StoHelp::writeTypedString(myWrapperStorage, c.foeLane);
     356           90 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.egoResponse);
     357           90 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, c.foeResponse);
     358              :     }
     359           96 :     return true;
     360              : }
     361              : 
     362              : 
     363              : bool
     364         2380 : TraCIServer::wrapNextStopDataVector(const std::string& /* objID */, const int variable, const std::vector<libsumo::TraCINextStopData>& value) {
     365         2380 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
     366         2380 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     367              :     const bool full = variable == libsumo::VAR_NEXT_STOPS2;
     368         8409 :     for (const auto& s : value) {
     369         6029 :         const int legacyStopFlags = (s.stopFlags << 1) + (s.arrival >= 0 ? 1 : 0);
     370         6029 :         StoHelp::writeTypedString(myWrapperStorage, s.lane);
     371         6029 :         StoHelp::writeTypedDouble(myWrapperStorage, s.endPos);
     372         6029 :         StoHelp::writeTypedString(myWrapperStorage, s.stoppingPlaceID);
     373         6029 :         StoHelp::writeTypedInt(myWrapperStorage, full ? s.stopFlags : legacyStopFlags);
     374         6029 :         StoHelp::writeTypedDouble(myWrapperStorage, s.duration);
     375         6029 :         StoHelp::writeTypedDouble(myWrapperStorage, s.until);
     376         6029 :         if (full) {
     377         6018 :             StoHelp::writeTypedDouble(myWrapperStorage, s.startPos);
     378         6018 :             StoHelp::writeTypedDouble(myWrapperStorage, s.intendedArrival);
     379         6018 :             StoHelp::writeTypedDouble(myWrapperStorage, s.arrival);
     380         6018 :             StoHelp::writeTypedDouble(myWrapperStorage, s.depart);
     381         6018 :             StoHelp::writeTypedString(myWrapperStorage, s.split);
     382         6018 :             StoHelp::writeTypedString(myWrapperStorage, s.join);
     383         6018 :             StoHelp::writeTypedString(myWrapperStorage, s.actType);
     384         6018 :             StoHelp::writeTypedString(myWrapperStorage, s.tripId);
     385         6018 :             StoHelp::writeTypedString(myWrapperStorage, s.line);
     386         6018 :             StoHelp::writeTypedDouble(myWrapperStorage, s.speed);
     387              :         }
     388              :     }
     389         2380 :     return true;
     390              : }
     391              : 
     392              : 
     393              : bool
     394        24858 : TraCIServer::wrapVehicleDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIVehicleData>& value) {
     395        24858 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 5);
     396        24858 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     397        29136 :     for (const libsumo::TraCIVehicleData& vd : value) {
     398         4278 :         StoHelp::writeTypedString(myWrapperStorage, vd.id);
     399         4278 :         StoHelp::writeTypedDouble(myWrapperStorage, vd.length);
     400         4278 :         StoHelp::writeTypedDouble(myWrapperStorage, vd.entryTime);
     401         4278 :         StoHelp::writeTypedDouble(myWrapperStorage, vd.leaveTime);
     402         4278 :         StoHelp::writeTypedString(myWrapperStorage, vd.typeID);
     403              :     }
     404        24858 :     return true;
     405              : }
     406              : 
     407              : 
     408              : bool
     409           56 : TraCIServer::wrapBestLanesDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCIBestLanesData>& value) {
     410           56 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 6);
     411           56 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     412          111 :     for (const libsumo::TraCIBestLanesData& bld : value) {
     413           55 :         StoHelp::writeTypedString(myWrapperStorage, bld.laneID);
     414           55 :         StoHelp::writeTypedDouble(myWrapperStorage, bld.length);
     415           55 :         StoHelp::writeTypedDouble(myWrapperStorage, bld.occupation);
     416           55 :         StoHelp::writeTypedByte(myWrapperStorage, bld.bestLaneOffset);
     417           55 :         StoHelp::writeTypedUnsignedByte(myWrapperStorage, bld.allowsContinuation ? 1 : 0);
     418           55 :         StoHelp::writeTypedStringList(myWrapperStorage, bld.continuationLanes);
     419              :     }
     420           56 :     return true;
     421              : }
     422              : 
     423              : 
     424              : bool
     425          806 : TraCIServer::wrapNextTLSDataVector(const std::string& /* objID */, const int /* variable */, const std::vector<libsumo::TraCINextTLSData>& value) {
     426          806 :     StoHelp::writeCompound(myWrapperStorage, 1 + (int)value.size() * 4);
     427          806 :     StoHelp::writeTypedInt(myWrapperStorage, (int)value.size());
     428         1525 :     for (const libsumo::TraCINextTLSData& tlsd : value) {
     429          719 :         StoHelp::writeTypedString(myWrapperStorage, tlsd.id);
     430          719 :         StoHelp::writeTypedInt(myWrapperStorage, tlsd.tlIndex);
     431          719 :         StoHelp::writeTypedDouble(myWrapperStorage, tlsd.dist);
     432          719 :         StoHelp::writeTypedByte(myWrapperStorage, tlsd.state);
     433              :     }
     434          806 :     return true;
     435              : }
     436              : 
     437              : 
     438              : tcpip::Storage&
     439     17629445 : TraCIServer::getWrapperStorage() {
     440     17629445 :     return myWrapperStorage;
     441              : }
     442              : 
     443              : 
     444              : 
     445         2559 : TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
     446         2559 :     : myTargetTime(begin), myLastContextSubscription(nullptr) {
     447              : #ifdef DEBUG_MULTI_CLIENTS
     448              :     std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
     449              : #endif
     450         2559 :     myVehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
     451         2559 :     myVehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
     452         2559 :     myVehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
     453         2559 :     myVehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
     454         2559 :     myVehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
     455         2559 :     myVehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
     456         2559 :     myVehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
     457         2559 :     myVehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
     458         2559 :     myVehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
     459         2559 :     myVehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
     460         2559 :     myVehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
     461         2559 :     myVehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
     462         2559 :     myVehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
     463              : 
     464         2559 :     myTransportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
     465         2559 :     myTransportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
     466         2559 :     myTransportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
     467         2559 :     myTransportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
     468              : 
     469         2559 :     myExecutors[libsumo::CMD_SET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processSet;
     470         2559 :     myExecutors[libsumo::CMD_SET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processSet;
     471         2559 :     myExecutors[libsumo::CMD_SET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processSet;
     472              : 
     473         2559 :     myExecutors[libsumo::CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processSet;
     474         2559 :     myExecutors[libsumo::CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
     475         2559 :     myExecutors[libsumo::CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
     476         2559 :     myExecutors[libsumo::CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
     477         2559 :     myExecutors[libsumo::CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
     478         2559 :     myExecutors[libsumo::CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
     479         2559 :     myExecutors[libsumo::CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
     480         2559 :     myExecutors[libsumo::CMD_SET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processSet;
     481         2559 :     myExecutors[libsumo::CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
     482         2559 :     myExecutors[libsumo::CMD_SET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processSet;
     483         2559 :     myExecutors[libsumo::CMD_SET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processSet;
     484         2559 :     myExecutors[libsumo::CMD_SET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processSet;
     485         2559 :     myExecutors[libsumo::CMD_SET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processSet;
     486         2559 :     myExecutors[libsumo::CMD_SET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processSet;
     487         2559 :     myExecutors[libsumo::CMD_SET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processSet;
     488         2559 :     myExecutors[libsumo::CMD_SET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processSet;
     489         2559 :     myExecutors[libsumo::CMD_SET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processSet;
     490         2559 :     myExecutors[libsumo::CMD_SET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processSet;
     491              :     //myExecutors[libsumo::CMD_SET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processSet;
     492         2559 :     myExecutors[libsumo::CMD_SET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processSet;
     493              : 
     494         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
     495         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
     496         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE, libsumo::VAR_ANGLE));
     497         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_ANGLE));
     498         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::LANE_CHANGES));
     499         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_LANE_VARIABLE, libsumo::VAR_FOES));
     500         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::DISTANCE_REQUEST));
     501         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_EDGES));
     502         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_STAGE));
     503         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::VAR_TAXI_RESERVATIONS));
     504         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE, libsumo::SPLIT_TAXI_RESERVATIONS));
     505         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_BLOCKING_VEHICLES));
     506         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_RIVAL_VEHICLES));
     507         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_PRIORITY_VEHICLES));
     508         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT));
     509         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::TL_CONSTRAINT_BYFOE));
     510         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_TL_VARIABLE, libsumo::VAR_PERSON_NUMBER));
     511         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::DISTANCE_REQUEST));
     512         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_TRAVELTIME));
     513         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_EDGE_EFFORT));
     514         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOW_SPEED));
     515         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_SECURE_GAP));
     516         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_SPEED));
     517         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOES));
     518         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::CMD_CHANGELANE));
     519         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_LEADER));
     520         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOWER));
     521         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEIGHBORS));
     522         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_STOP_PARAMETER));
     523         5118 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS));  // this is just a dummy to trigger an error
     524         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_NEXT_STOPS2));
     525         2559 :     myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_TAXI_FLEET));
     526         2559 :     myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER));
     527         2559 :     myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER_WITH_KEY));
     528              : 
     529         2559 :     myDoCloseConnection = false;
     530              : 
     531              :     // display warning if internal lanes are not used
     532              :     // TODO this may be redundant to the warning in NLBuilder::build
     533         2559 :     if (!MSGlobals::gUsingInternalLanes && !MSGlobals::gUseMesoSim) {
     534            2 :         WRITE_WARNING(TL("Starting TraCI without using internal lanes!"));
     535            2 :         MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
     536           12 :         MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
     537              :     }
     538              : 
     539              :     try {
     540         5118 :         WRITE_MESSAGEF(TL("***Starting server on port % ***"), toString(port));
     541         2559 :         tcpip::Socket serverSocket(port);
     542         2559 :         if (numClients > 1) {
     543          156 :             WRITE_MESSAGEF(TL("  waiting for % clients..."), toString(numClients));
     544              :         }
     545         5280 :         while ((int)mySockets.size() < numClients) {
     546         2725 :             int index = (int)mySockets.size() + libsumo::MAX_ORDER + 1;
     547         2725 :             mySockets[index] = new SocketInfo(serverSocket.accept(true), begin);
     548         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
     549         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
     550         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
     551         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
     552         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
     553         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
     554         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
     555         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
     556         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
     557         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
     558         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
     559         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
     560         2721 :             mySockets[index]->vehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
     561              : 
     562         2721 :             mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
     563         2721 :             mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
     564         2721 :             mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
     565         2721 :             mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
     566         2721 :             if (numClients > 1) {
     567          488 :                 WRITE_MESSAGE(TL("  client connected"));
     568              :             }
     569              :         }
     570              :         // When got here, all clients have connected
     571         2555 :         if (numClients > 1) {
     572           78 :             checkClientOrdering();
     573              :         }
     574              :         // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommands()
     575         2551 :         myCurrentSocket = mySockets.begin();
     576         2567 :     } catch (tcpip::SocketException& e) {
     577            8 :         throw ProcessError(e.what());
     578            4 :     }
     579         2599 : }
     580              : 
     581              : 
     582         5102 : TraCIServer::~TraCIServer() {
     583         2580 :     for (const auto& socket : mySockets) {
     584           29 :         delete socket.second;
     585              :     }
     586              :     // there is no point in calling cleanup() here, it does not free any pointers and will only modify members which get deleted anyway
     587         7653 : }
     588              : 
     589              : 
     590              : // ---------- Initialisation and Shutdown
     591              : void
     592        39141 : TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
     593       114838 :     if (myInstance == nullptr && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0)) {
     594         7669 :         myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
     595         2559 :                                      OptionsCont::getOptions().getInt("remote-port"),
     596        10244 :                                      OptionsCont::getOptions().getInt("num-clients"));
     597         2743 :         for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
     598          192 :             myInstance->myExecutors[i->first] = i->second;
     599              :         }
     600              :     }
     601        39133 :     if (myInstance != nullptr) {
     602              :         // maybe net was deleted and built again
     603         2564 :         MSNet::getInstance()->addVehicleStateListener(myInstance);
     604         2564 :         MSNet::getInstance()->addTransportableStateListener(myInstance);
     605         2564 :         myInstance->mySubscriptionCache.writeInt(0);
     606              :     }
     607        39133 : }
     608              : 
     609              : 
     610              : void
     611        38770 : TraCIServer::close() {
     612        38770 :     if (myInstance == nullptr) {
     613              :         return;
     614              :     }
     615         2551 :     delete myInstance;
     616         2551 :     myInstance = nullptr;
     617         2551 :     myDoCloseConnection = true;
     618              : }
     619              : 
     620              : 
     621              : bool
     622     79112369 : TraCIServer::wasClosed() {
     623     79112369 :     return myDoCloseConnection;
     624              : }
     625              : 
     626              : 
     627              : // ---------- Initialisation and Shutdown
     628              : 
     629              : 
     630              : void
     631        90763 : TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
     632        90763 :     if (!myDoCloseConnection) {
     633        90763 :         myVehicleStateChanges[to].push_back(vehicle->getID());
     634       190556 :         for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
     635        99793 :             i->second->vehicleStateChanges[to].push_back(vehicle->getID());
     636              :         }
     637              :     }
     638        90763 : }
     639              : 
     640              : 
     641              : void
     642         1735 : TraCIServer::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& /*info*/) {
     643         1735 :     if (!myDoCloseConnection) {
     644         1735 :         myTransportableStateChanges[to].push_back(transportable->getID());
     645         3470 :         for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
     646         1735 :             i->second->transportableStateChanges[to].push_back(transportable->getID());
     647              :         }
     648              :     }
     649         1735 : }
     650              : 
     651              : 
     652              : void
     653           78 : TraCIServer::checkClientOrdering() {
     654              : #ifdef DEBUG_MULTI_CLIENTS
     655              :     std::cout << "Checking client order requests." << std::endl;
     656              : #endif
     657              :     // check for SET_ORDER commands queued by connected clients
     658              :     // In multiclient cas it is mandatory that SET_ORDER  is sent as the first command (or directly after GET_VERSION)
     659           78 :     myCurrentSocket = mySockets.begin();
     660          316 :     while (myCurrentSocket != mySockets.end()) {
     661              : #ifdef DEBUG_MULTI_CLIENTS
     662              :         std::cout << "  Socket " << myCurrentSocket->second->socket << ":" << std::endl;
     663              : #endif
     664              : //        bool clientUnordered = true;
     665              :         while (true) {
     666          482 :             myInputStorage.reset();
     667          482 :             myCurrentSocket->second->socket->receiveExact(myInputStorage);
     668              :             int commandStart, commandLength;
     669          482 :             int commandId = readCommandID(commandStart, commandLength);
     670              : #ifdef DEBUG_MULTI_CLIENTS
     671              :             std::cout << "    received command " << commandId << std::endl;
     672              : #endif
     673              :             // Whether the received command is a permitted command for the initialization phase.
     674              :             // Currently, getVersion and setOrder are permitted.
     675          482 :             bool initCommand = commandId == libsumo::CMD_SETORDER || commandId == libsumo::CMD_GETVERSION;
     676          482 :             if (initCommand) {
     677              : #ifdef DEBUG_MULTI_CLIENTS
     678              :                 std::cout << "    Init command. Sending response." << std::endl;
     679              : #endif
     680              :                 // reset input storage to initial state before reading the commandId
     681              :                 // (ugly, but we can't just reset the store's iter_ from here)
     682              :                 // Giving the commandId to dispatch command didn't work either
     683          478 :                 tcpip::Storage tmp;
     684          478 :                 tmp.writeStorage(myInputStorage);
     685          478 :                 myInputStorage.reset();
     686              :                 // we don't know whether the command was set with extended
     687              :                 // length syntax or not so we hardcode the length here (#5037)
     688          718 :                 myInputStorage.writeUnsignedByte(commandId == libsumo::CMD_SETORDER ? 6 : 2);
     689          478 :                 myInputStorage.writeUnsignedByte(commandId);
     690          478 :                 myInputStorage.writeStorage(tmp);
     691              : 
     692              :                 // Handle initialization command completely
     693          478 :                 dispatchCommand();
     694          478 :                 myCurrentSocket->second->socket->sendExact(myOutputStorage);
     695          478 :                 myOutputStorage.reset();
     696          478 :             } else {
     697              : #ifdef DEBUG_MULTI_CLIENTS
     698              :                 std::cout << "    Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
     699              : #endif
     700            8 :                 throw ProcessError(TL("Execution order (libsumo::CMD_SETORDER) was not set for all TraCI clients in pre-execution phase."));
     701              :             }
     702          478 :             if (commandId == libsumo::CMD_SETORDER) {
     703              :                 // This is what we have waited for.
     704              :                 break;
     705              :             }
     706          240 :         }
     707              :         ++myCurrentSocket;
     708              :     }
     709           74 : }
     710              : 
     711              : 
     712              : void
     713      7912768 : TraCIServer::processReorderingRequests() {
     714              :     // Process reordering requests
     715      7912768 :     if (mySocketReorderRequests.size() > 0) {
     716              :         // process reordering requests
     717              :         std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
     718              :         std::map<int, SocketInfo*>::iterator j;
     719              : #ifdef DEBUG_MULTI_CLIENTS
     720              :         std::cout << SIMTIME << " Current socket ordering:\n";
     721              :         for (j = mySockets.begin(); j != mySockets.end(); ++j) {
     722              :             std::cout << "      " << j->first << ": " << j->second->socket << "\n";
     723              :         }
     724              :         std::cout << "Reordering requests:\n";
     725              :         for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
     726              :             std::cout << "      Socket " << i->second->socket << " -> " << i->first << "\n";
     727              :         }
     728              :         i = mySocketReorderRequests.begin();
     729              : #endif
     730          324 :         while (i != mySocketReorderRequests.end()) {
     731              :             j = mySockets.begin();
     732          579 :             while (j != mySockets.end()) {
     733          579 :                 if (j->second->socket == i->second->socket) {
     734              :                     break;
     735              :                 } else {
     736              :                     j++;
     737              :                 }
     738              :             }
     739              :             assert(j != mySockets.end());
     740              :             mySockets.erase(j);
     741          243 :             mySockets[i->first] = i->second;
     742              :             ++i;
     743              :         }
     744              :         mySocketReorderRequests.clear();
     745              : #ifdef DEBUG_MULTI_CLIENTS
     746              :         std::cout << "New socket ordering:\n";
     747              :         for (j = mySockets.begin(); j != mySockets.end(); ++j) {
     748              :             std::cout << "      " << j->first << ": " << j->second->socket << "\n";
     749              :         }
     750              :         std::cout << std::endl;
     751              : #endif
     752              :     }
     753      7912768 : }
     754              : 
     755              : 
     756              : SUMOTime
     757     15781573 : TraCIServer::nextTargetTime() const {
     758              : #ifdef DEBUG_MULTI_CLIENTS
     759              :     std::cout << "\n    Determining new target time..." << std::endl;
     760              :     if (mySockets.size() == 0) {
     761              :         std::cout << "    All clients have disconnected." << std::endl;
     762              :     }
     763              : #endif
     764              :     std::map<int, SocketInfo*>::const_iterator i;
     765              :     SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
     766     31669784 :     for (i = mySockets.begin(); i != mySockets.end(); ++i) {
     767              : #ifdef DEBUG_MULTI_CLIENTS
     768              :         std::cout << "    target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
     769              : #endif
     770     15888211 :         targetTime = MIN2(targetTime, i->second->targetTime);
     771              :     }
     772              : #ifdef DEBUG_MULTI_CLIENTS
     773              :     std::cout << std::endl;
     774              : #endif
     775     15781573 :     return targetTime;
     776              : }
     777              : 
     778              : 
     779              : // send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
     780              : void
     781      7910204 : TraCIServer::sendOutputToAll() const {
     782              : #ifdef DEBUG_MULTI_CLIENTS
     783              :     std::cout << "\n    Sending subscription results to clients:\n";
     784              : #endif
     785              :     std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
     786     15854548 :     while (i != mySockets.end()) {
     787      7944344 :         if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
     788              :             // this client will become active before the next SUMO step. Provide subscription results.
     789      7870292 :             i->second->socket->sendExact(myOutputStorage);
     790              : #ifdef DEBUG_MULTI_CLIENTS
     791              :             std::cout << i->second->socket << "\n";
     792              : #endif
     793              :         }
     794              :         ++i;
     795              :     }
     796              : #ifdef DEBUG_MULTI_CLIENTS
     797              :     std::cout << std::endl;
     798              : #endif
     799      7910204 : }
     800              : 
     801              : 
     802              : int
     803      7912768 : TraCIServer::processCommands(const SUMOTime step, const bool afterMove) {
     804              : #ifdef DEBUG_MULTI_CLIENTS
     805              :     std::cout << SIMTIME << " processCommands(step = " << step << "):\n" << std::endl;
     806              : #endif
     807              :     try {
     808              :         int finalCmd = 0;
     809              :         const bool firstStep = myCurrentSocket != mySockets.end();
     810              :         // update client order if requested
     811      7912768 :         processReorderingRequests();
     812      7912768 :         if (!firstStep && !afterMove) {
     813              :             // This is the entry point after performing a SUMO step (block is skipped before first SUMO step since then no simulation results have to be sent)
     814              :             // update subscription results
     815      7910204 :             postProcessSimulationStep();
     816              :             // Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
     817      7910204 :             sendOutputToAll();
     818      7910204 :             myOutputStorage.reset();
     819              :         }
     820              : 
     821              :         // determine minimal next target time among clients
     822      7912768 :         myTargetTime = nextTargetTime();
     823              : 
     824      7912768 :         if (step < myTargetTime) {
     825              : #ifdef DEBUG_MULTI_CLIENTS
     826              :             std::cout << "    next target time is larger than next SUMO simstep (" << step << "). Returning from processCommands()." << std::endl;
     827              : #endif
     828              :             return finalCmd;
     829              :         }
     830              : 
     831              :         // Simulation should run until
     832              :         // 1. end time reached or
     833              :         // 2. got libsumo::CMD_CLOSE or
     834              :         // 3. got libsumo::CMD_LOAD or
     835              :         // 4. Client closes socket connection
     836     15721113 :         while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep()) && finalCmd != libsumo::CMD_EXECUTEMOVE) {
     837              : #ifdef DEBUG_MULTI_CLIENTS
     838              :             std::cout << "  Next target time: " << myTargetTime << std::endl;
     839              : #endif
     840              :             // Iterate over clients and process communication for the ones with target time == myTargetTime
     841      7871362 :             myCurrentSocket = mySockets.begin();
     842     15815200 :             while (myCurrentSocket != mySockets.end()) {
     843              : #ifdef DEBUG_MULTI_CLIENTS
     844              :                 std::cout << "  current socket: " << myCurrentSocket->second->socket
     845              :                           << " with target time=" << myCurrentSocket->second->targetTime
     846              :                           << std::endl;
     847              : #endif
     848              : 
     849      7943860 :                 if (myCurrentSocket->second->targetTime > myTargetTime || (afterMove && !myCurrentSocket->second->executeMove)) {
     850              :                     // this client must wait
     851              : #ifdef DEBUG_MULTI_CLIENTS
     852              :                     std::cout <<  "       skipping client " << myCurrentSocket->second->socket
     853              :                               << " with target time=" << myCurrentSocket->second->targetTime << std::endl;
     854              : #endif
     855              :                     myCurrentSocket++;
     856        51960 :                     continue;
     857              :                 }
     858              :                 finalCmd = 0;
     859     25055434 :                 while (finalCmd == 0) {
     860     17163556 :                     if (!myInputStorage.valid_pos()) {
     861              :                         // have read request completely, send response if adequate
     862     17163556 :                         if (myOutputStorage.size() > 0) {
     863              :                             // send response to previous query
     864      9271662 :                             myCurrentSocket->second->socket->sendExact(myOutputStorage);
     865      9271662 :                             myOutputStorage.reset();
     866              :                         }
     867              : #ifdef DEBUG_MULTI_CLIENTS
     868              :                         std::cout << "    resetting input storage and reading next command..." << std::endl;
     869              : #endif
     870              :                         // Read next request
     871     17163556 :                         myInputStorage.reset();
     872     17163556 :                         myCurrentSocket->second->socket->receiveExact(myInputStorage);
     873              :                     }
     874              : 
     875     34327068 :                     while (myInputStorage.valid_pos() && !myDoCloseConnection) {
     876     17163534 :                         const int cmd = dispatchCommand();
     877     17163534 :                         if (cmd == libsumo::CMD_SIMSTEP || cmd == libsumo::CMD_LOAD || cmd == libsumo::CMD_EXECUTEMOVE || cmd == libsumo::CMD_CLOSE) {
     878              :                             finalCmd = cmd;
     879              :                         }
     880              :                     }
     881              :                 }
     882              :             }
     883      7871340 :             if (!myLoadArgs.empty()) {
     884              : #ifdef DEBUG_MULTI_CLIENTS
     885              :                 std::cout << "  Breaking loop to load new simulation." << std::endl;
     886              : #endif
     887              :                 break;
     888      7871327 :             } else if (myDoCloseConnection) {
     889              : #ifdef DEBUG_MULTI_CLIENTS
     890              :                 std::cout << "  Breaking loop because last client closed connection." << std::endl;
     891              : #endif
     892              :                 break;
     893              :             }
     894      7868805 :             SUMOTime nextT = nextTargetTime();
     895              :             // minimal target time among clients should have been increased during the last loop through mySockets
     896              :             // XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
     897              :             //      leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
     898              :             //      the next call is then usually simulationStep(step=1000) leading to no further increase
     899              :             //      and thus a failing assertion here.
     900              :             //assert(myTargetTime < nextT || myDoCloseConnection);
     901      7868805 :             myTargetTime = nextT;
     902              :         }
     903              :         // All clients are done with the current time step
     904              :         // Reset myVehicleStateChanges and myTransportableStateChanges
     905    109932004 :         for (auto& item : myVehicleStateChanges) {
     906              :             item.second.clear();
     907              :         }
     908     39261430 :         for (auto& item : myTransportableStateChanges) {
     909              :             item.second.clear();
     910              :         }
     911              :         return finalCmd;
     912           22 :     } catch (std::invalid_argument& e) {
     913            0 :         throw ProcessError(e.what());
     914            0 :     } catch (libsumo::TraCIException& e) {
     915            0 :         throw ProcessError(e.what());
     916           22 :     } catch (tcpip::SocketException& e) {
     917           44 :         throw ProcessError(e.what());
     918           22 :     }
     919              : }
     920              : 
     921              : 
     922              : bool
     923     17553370 : TraCIServer::processGet(const int commandID, tcpip::Storage& inputStorage, tcpip::Storage& outputStorage) {
     924     17553370 :     const int variable = inputStorage.readUnsignedByte();
     925     17553370 :     const std::string id = inputStorage.readString();
     926     17553370 :     initWrapper(commandID + 0x10, variable, id);
     927              :     try {
     928     17553370 :         switch (commandID) {
     929        31963 :             case libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE:
     930        31963 :                 if (!libsumo::InductionLoop::handleVariable(id, variable, this, &inputStorage)) {
     931            8 :                     throw libsumo::TraCIException("Get Induction Loop Variable: unsupported variable " + toHex(variable, 2) + " specified");
     932              :                 }
     933              :                 break;
     934         1097 :             case libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE:
     935         1097 :                 if (!libsumo::MultiEntryExit::handleVariable(id, variable, this, &inputStorage)) {
     936            8 :                     throw libsumo::TraCIException("Get Multi Entry Exit Detector Variable: unsupported variable " + toHex(variable, 2) + " specified");
     937              :                 }
     938              :                 break;
     939        73442 :             case libsumo::CMD_GET_TL_VARIABLE:
     940        73442 :                 if (!libsumo::TrafficLight::handleVariable(id, variable, this, &inputStorage)) {
     941           74 :                     switch (variable) {
     942              :                         case libsumo::TL_CONSTRAINT_SWAP: {
     943           69 :                             StoHelp::readCompound(inputStorage, 3, "A compound object of size 3 is needed for swapping constraints.");
     944           66 :                             const std::string tripId = StoHelp::readTypedString(inputStorage, "The tripId must be given as a string.");
     945           66 :                             const std::string foeSignal = StoHelp::readTypedString(inputStorage, "The foeSignal id must be given as a string.");
     946           66 :                             const std::string foeId = StoHelp::readTypedString(inputStorage, "The foe tripId must be given as a string.");
     947          132 :                             wrapSignalConstraintVector(id, variable, libsumo::TrafficLight::swapConstraints(id, tripId, foeSignal, foeId));
     948              :                             break;
     949              :                         }
     950            5 :                         default:
     951           10 :                             throw libsumo::TraCIException("Get TLS Variable: unsupported variable " + toHex(variable, 2) + " specified");
     952              :                     }
     953              :                 }
     954              :                 break;
     955        16309 :             case libsumo::CMD_GET_LANE_VARIABLE:
     956        16309 :                 if (!libsumo::Lane::handleVariable(id, variable, this, &inputStorage)) {
     957           10 :                     throw libsumo::TraCIException("Get Lane Variable: unsupported variable " + toHex(variable, 2) + " specified");
     958              :                 }
     959              :                 break;
     960      9389677 :             case libsumo::CMD_GET_VEHICLE_VARIABLE:
     961      9389677 :                 if (!libsumo::Vehicle::handleVariable(id, variable, this, &inputStorage)) {
     962           12 :                     throw libsumo::TraCIException("Get Vehicle Variable: unsupported variable " + toHex(variable, 2) + " specified");
     963              :                 }
     964              :                 break;
     965         2254 :             case libsumo::CMD_GET_VEHICLETYPE_VARIABLE:
     966         2254 :                 if (!libsumo::VehicleType::handleVariable(id, variable, this, &inputStorage)) {
     967           10 :                     throw libsumo::TraCIException("Get Vehicle Type Variable: unsupported variable " + toHex(variable, 2) + " specified");
     968              :                 }
     969              :                 break;
     970          308 :             case libsumo::CMD_GET_ROUTE_VARIABLE:
     971          308 :                 if (!libsumo::Route::handleVariable(id, variable, this, &inputStorage)) {
     972           10 :                     throw libsumo::TraCIException("Get Route Variable: unsupported variable " + toHex(variable, 2) + " specified");
     973              :                 }
     974              :                 break;
     975         4397 :             case libsumo::CMD_GET_POI_VARIABLE:
     976         4397 :                 if (!libsumo::POI::handleVariable(id, variable, this, &inputStorage)) {
     977           10 :                     throw libsumo::TraCIException("Get PoI Variable: unsupported variable " + toHex(variable, 2) + " specified");
     978              :                 }
     979              :                 break;
     980         4760 :             case libsumo::CMD_GET_POLYGON_VARIABLE:
     981         4760 :                 if (!libsumo::Polygon::handleVariable(id, variable, this, &inputStorage)) {
     982           10 :                     throw libsumo::TraCIException("Get Polygon Variable: unsupported variable " + toHex(variable, 2) + " specified");
     983              :                 }
     984              :                 break;
     985         4223 :             case libsumo::CMD_GET_JUNCTION_VARIABLE:
     986         4223 :                 if (!libsumo::Junction::handleVariable(id, variable, this, &inputStorage)) {
     987           10 :                     throw libsumo::TraCIException("Get Junction Variable: unsupported variable " + toHex(variable, 2) + " specified");
     988              :                 }
     989              :                 break;
     990        14945 :             case libsumo::CMD_GET_EDGE_VARIABLE:
     991        14945 :                 if (!libsumo::Edge::handleVariable(id, variable, this, &inputStorage)) {
     992           10 :                     throw libsumo::TraCIException("Get Edge Variable: unsupported variable " + toHex(variable, 2) + " specified");
     993              :                 }
     994              :                 break;
     995      7896530 :             case libsumo::CMD_GET_SIM_VARIABLE:
     996      7896530 :                 if (!TraCIServerAPI_Simulation::processGet(*this, inputStorage, id, variable)) {
     997            0 :                     throw libsumo::TraCIException("Get Simulation Variable: unsupported variable " + toHex(variable, 2) + " specified");
     998              :                 }
     999              :                 break;
    1000         7374 :             case libsumo::CMD_GET_LANEAREA_VARIABLE:
    1001         7374 :                 if (!libsumo::LaneArea::handleVariable(id, variable, this, &inputStorage)) {
    1002            8 :                     throw libsumo::TraCIException("Get Lane Area Detector Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1003              :                 }
    1004              :                 break;
    1005       100726 :             case libsumo::CMD_GET_PERSON_VARIABLE:
    1006       100726 :                 if (!libsumo::Person::handleVariable(id, variable, this, &inputStorage)) {
    1007           10 :                     throw libsumo::TraCIException("Get Person Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1008              :                 }
    1009              :                 break;
    1010          549 :             case libsumo::CMD_GET_BUSSTOP_VARIABLE:
    1011          549 :                 if (!libsumo::BusStop::handleVariable(id, variable, this, &inputStorage)) {
    1012            6 :                     throw libsumo::TraCIException("Get BusStop Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1013              :                 }
    1014              :                 break;
    1015          393 :             case libsumo::CMD_GET_PARKINGAREA_VARIABLE:
    1016          393 :                 if (!libsumo::ParkingArea::handleVariable(id, variable, this, &inputStorage)) {
    1017            6 :                     throw libsumo::TraCIException("Get ParkingArea Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1018              :                 }
    1019              :                 break;
    1020         1432 :             case libsumo::CMD_GET_CHARGINGSTATION_VARIABLE:
    1021         1432 :                 if (!libsumo::ChargingStation::handleVariable(id, variable, this, &inputStorage)) {
    1022            8 :                     throw libsumo::TraCIException("Get ChargingStation Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1023              :                 }
    1024              :                 break;
    1025         1815 :             case libsumo::CMD_GET_ROUTEPROBE_VARIABLE:
    1026         1815 :                 if (!libsumo::RouteProbe::handleVariable(id, variable, this, &inputStorage)) {
    1027            6 :                     throw libsumo::TraCIException("Get RouteProbe Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1028              :                 }
    1029              :                 break;
    1030          330 :             case libsumo::CMD_GET_CALIBRATOR_VARIABLE:
    1031          330 :                 if (!libsumo::Calibrator::handleVariable(id, variable, this, &inputStorage)) {
    1032            6 :                     throw libsumo::TraCIException("Get Calibrator Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1033              :                 }
    1034              :                 break;
    1035          156 :             case libsumo::CMD_GET_REROUTER_VARIABLE:
    1036          156 :                 if (!libsumo::Rerouter::handleVariable(id, variable, this, &inputStorage)) {
    1037            6 :                     throw libsumo::TraCIException("Get Rerouter Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1038              :                 }
    1039              :                 break;
    1040          165 :             case libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE:
    1041          165 :                 if (!libsumo::VariableSpeedSign::handleVariable(id, variable, this, &inputStorage)) {
    1042            6 :                     throw libsumo::TraCIException("Get VariableSpeedSign Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1043              :                 }
    1044              :                 break;
    1045          156 :             case libsumo::CMD_GET_MEANDATA_VARIABLE:
    1046          156 :                 if (!libsumo::MeanData::handleVariable(id, variable, this, &inputStorage)) {
    1047            6 :                     throw libsumo::TraCIException("Get MeanData Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1048              :                 }
    1049              :                 break;
    1050          369 :             case libsumo::CMD_GET_OVERHEADWIRE_VARIABLE:
    1051          369 :                 if (!libsumo::OverheadWire::handleVariable(id, variable, this, &inputStorage)) {
    1052            6 :                     throw libsumo::TraCIException("Get OverheadWire Variable: unsupported variable " + toHex(variable, 2) + " specified");
    1053              :                 }
    1054              :                 break;
    1055              :             default:
    1056              :                 return false;
    1057              :         }
    1058          724 :     } catch (libsumo::TraCIException& e) {
    1059          703 :         return writeErrorStatusCmd(commandID, e.what(), outputStorage);
    1060          703 :     }
    1061     17552667 :     writeStatusCmd(commandID, libsumo::RTYPE_OK, "", outputStorage);
    1062     17552646 :     writeResponseWithLength(outputStorage, getWrapperStorage());
    1063              :     return true;
    1064              : }
    1065              : 
    1066              : 
    1067              : void
    1068         2559 : TraCIServer::cleanup() {
    1069              :     mySubscriptions.clear();
    1070         5118 :     myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
    1071         2596 :     for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
    1072           37 :         myCurrentSocket->second->targetTime = myTargetTime;
    1073           37 :         myCurrentSocket->second->executeMove = false;
    1074              :     }
    1075         2559 :     myOutputStorage.reset();
    1076         2559 :     myInputStorage.reset();
    1077         2559 :     mySubscriptionCache.reset();
    1078        35826 :     for (auto& i : myVehicleStateChanges) {
    1079              :         i.second.clear();
    1080              :     }
    1081        12795 :     for (auto& i : myTransportableStateChanges) {
    1082              :         i.second.clear();
    1083              :     }
    1084         2559 :     myCurrentSocket = mySockets.begin();
    1085         2559 : }
    1086              : 
    1087              : 
    1088              : std::map<int, TraCIServer::SocketInfo*>::iterator
    1089         2684 : TraCIServer::removeCurrentSocket() {
    1090              : #ifdef DEBUG_MULTI_CLIENTS
    1091              :     std::cout << "       Removing socket " << myCurrentSocket->second->socket
    1092              :               << " (order " << myCurrentSocket->first << ")" << std::endl;
    1093              : #endif
    1094         2684 :     delete myCurrentSocket->second;
    1095         2684 :     myCurrentSocket = mySockets.erase(myCurrentSocket);
    1096         2684 :     return myCurrentSocket;
    1097              : }
    1098              : 
    1099              : 
    1100              : int
    1101     17164494 : TraCIServer::readCommandID(int& commandStart, int& commandLength) {
    1102     17164494 :     commandStart = myInputStorage.position();
    1103     17164494 :     commandLength = myInputStorage.readUnsignedByte();
    1104     17164494 :     if (commandLength == 0) {
    1105        49925 :         commandLength = myInputStorage.readInt();
    1106              :     }
    1107              : #ifdef DEBUG_RAW_INPUT
    1108              :     std::cout << " commandStart=" << commandStart << " commandLength=" << commandLength << " pos=" << myInputStorage.position() << " raw=";
    1109              :     for (auto it = myInputStorage.begin(); it != myInputStorage.end(); ++it) {
    1110              :         std::cout << (int)*it << " ";
    1111              :     }
    1112              :     std::cout << "\n";
    1113              : #endif
    1114     17164494 :     return myInputStorage.readUnsignedByte();
    1115              : }
    1116              : 
    1117              : 
    1118              : int
    1119     17164012 : TraCIServer::dispatchCommand() {
    1120              :     int commandStart, commandLength;
    1121     17164012 :     int commandId = readCommandID(commandStart, commandLength);
    1122              : #ifdef DEBUG_MULTI_CLIENTS
    1123              :     std::cout << "       dispatchCommand() called for client " << myCurrentSocket->second->socket
    1124              :               << ", commandId = " << commandId << std::endl;
    1125              : #endif
    1126              :     bool success = false;
    1127              :     // dispatch commands
    1128     17164012 :     if (myExecutors.find(commandId) != myExecutors.end()) {
    1129       107624 :         success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
    1130     17056388 :     } else if ((commandId >= libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE && commandId <= libsumo::CMD_GET_BUSSTOP_VARIABLE)
    1131     17056388 :                || (commandId >= libsumo::CMD_GET_PARKINGAREA_VARIABLE && commandId <= libsumo::CMD_GET_OVERHEADWIRE_VARIABLE)) {
    1132      9152449 :         if (commandId == libsumo::CMD_GET_GUI_VARIABLE) {
    1133          246 :             writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
    1134              :         } else {
    1135      9152326 :             success = processGet(commandId, myInputStorage, myOutputStorage);
    1136              :         }
    1137              :     } else {
    1138      7903939 :         switch (commandId) {
    1139         2099 :             case libsumo::CMD_GETVERSION:
    1140         2099 :                 success = commandGetVersion();
    1141              :                 break;
    1142              :             case libsumo::CMD_LOAD: {
    1143              :                 try {
    1144           13 :                     const std::vector<std::string> args = StoHelp::readTypedStringList(myInputStorage, "A load command needs a list of string arguments.");
    1145              : #ifdef DEBUG_MULTI_CLIENTS
    1146              :                     std::cout << "       commandId == libsumo::CMD_LOAD"
    1147              :                               << ", args = " << toString(args) << std::endl;
    1148              : #endif
    1149           13 :                     myLoadArgs = args;
    1150              :                     success = true;
    1151           26 :                     writeStatusCmd(libsumo::CMD_LOAD, libsumo::RTYPE_OK, "");
    1152              :                     // XXX: This only cares for the client that issued the load command.
    1153              :                     // Multiclient-load functionality is still to be implemented. Refs #3146.
    1154           13 :                     myCurrentSocket->second->socket->sendExact(myOutputStorage);
    1155           13 :                     myCurrentSocket = mySockets.end();
    1156           13 :                     myOutputStorage.reset();
    1157           13 :                 } catch (libsumo::TraCIException& e) {
    1158            0 :                     return writeErrorStatusCmd(libsumo::CMD_LOAD, e.what(), myOutputStorage);
    1159            0 :                 }
    1160              :                 break;
    1161              :             }
    1162            6 :             case libsumo::CMD_EXECUTEMOVE:
    1163            6 :                 myCurrentSocket->second->executeMove = true;
    1164              :                 myCurrentSocket++;
    1165              :                 success = true;
    1166           12 :                 writeStatusCmd(libsumo::CMD_EXECUTEMOVE, libsumo::RTYPE_OK, "");
    1167              :                 break;
    1168      7889175 :             case libsumo::CMD_SIMSTEP: {
    1169      7889175 :                 const double nextT = myInputStorage.readDouble();
    1170      7889175 :                 if (nextT == 0.) {
    1171      7843105 :                     myCurrentSocket->second->targetTime += DELTA_T;
    1172              :                 } else {
    1173        46070 :                     myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
    1174              :                 }
    1175      7889175 :                 myCurrentSocket->second->executeMove = false;
    1176              : #ifdef DEBUG_MULTI_CLIENTS
    1177              :                 std::cout << "       commandId == libsumo::CMD_SIMSTEP"
    1178              :                           << ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
    1179              : #endif
    1180      7889175 :                 if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
    1181              :                     // This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
    1182              :                     // @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommands()
    1183        18882 :                     sendSingleSimStepResponse();
    1184              :                 }
    1185              :                 // Clear vehicleStateChanges and transportableStateChanges for this client
    1186              :                 // -> For subsequent TraCI stepping
    1187              :                 // that is performed within this SUMO step, no updates on vehicle states
    1188              :                 // belonging to the last SUMO simulation step will be received by this client.
    1189    110448450 :                 for (auto& item : myCurrentSocket->second->vehicleStateChanges) {
    1190              :                     item.second.clear();
    1191              :                 }
    1192     39445875 :                 for (auto& item : myCurrentSocket->second->transportableStateChanges) {
    1193              :                     item.second.clear();
    1194              :                 }
    1195              :                 myCurrentSocket++;
    1196      7889175 :                 return commandId;
    1197              :             }
    1198              :             case libsumo::CMD_CLOSE:
    1199         5368 :                 writeStatusCmd(libsumo::CMD_CLOSE, libsumo::RTYPE_OK, "");
    1200         2684 :                 myCurrentSocket->second->socket->sendExact(myOutputStorage);
    1201         2684 :                 myOutputStorage.reset();
    1202         2684 :                 if (mySockets.size() == 1) {
    1203              :                     // Last client has closed connection
    1204         2522 :                     myDoCloseConnection = true;
    1205              :                 }
    1206              :                 // remove current socket and increment to next socket in ordering
    1207         2684 :                 myCurrentSocket = removeCurrentSocket();
    1208              :                 success = true;
    1209              :                 break;
    1210          246 :             case libsumo::CMD_SETORDER: {
    1211          246 :                 const int order = myInputStorage.readInt();
    1212              : #ifdef DEBUG_MULTI_CLIENTS
    1213              :                 std::cout << "       commandId == libsumo::CMD_SETORDER"
    1214              :                           << ", order index is " << order << std::endl;
    1215              : #endif
    1216          246 :                 if (order > libsumo::MAX_ORDER) {
    1217            0 :                     return writeErrorStatusCmd(libsumo::CMD_SETORDER, "A set order command needs an int argument below " + toString(libsumo::MAX_ORDER) + ".", myOutputStorage);
    1218              :                 }
    1219              :                 if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
    1220            0 :                     return writeErrorStatusCmd(libsumo::CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
    1221              :                 }
    1222              :                 // memorize reorder request (will only take effect in the next step)
    1223          246 :                 mySocketReorderRequests[order] = myCurrentSocket->second;
    1224              :                 success = true;
    1225          246 :                 writeStatusCmd(libsumo::CMD_SETORDER, libsumo::RTYPE_OK, "");
    1226          246 :                 break;
    1227              :             }
    1228         5217 :             case libsumo::CMD_SUBSCRIBE_BUSSTOP_VARIABLE:
    1229              :             case libsumo::CMD_SUBSCRIBE_CALIBRATOR_VARIABLE:
    1230              :             case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_VARIABLE:
    1231              :             case libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE:
    1232              :             case libsumo::CMD_SUBSCRIBE_GUI_VARIABLE:
    1233              :             case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE:
    1234              :             case libsumo::CMD_SUBSCRIBE_JUNCTION_VARIABLE:
    1235              :             case libsumo::CMD_SUBSCRIBE_LANE_VARIABLE:
    1236              :             case libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE:
    1237              :             case libsumo::CMD_SUBSCRIBE_MEANDATA_VARIABLE:
    1238              :             case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE:
    1239              :             case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_VARIABLE:
    1240              :             case libsumo::CMD_SUBSCRIBE_PARKINGAREA_VARIABLE:
    1241              :             case libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE:
    1242              :             case libsumo::CMD_SUBSCRIBE_POI_VARIABLE:
    1243              :             case libsumo::CMD_SUBSCRIBE_POLYGON_VARIABLE:
    1244              :             case libsumo::CMD_SUBSCRIBE_REROUTER_VARIABLE:
    1245              :             case libsumo::CMD_SUBSCRIBE_ROUTE_VARIABLE:
    1246              :             case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_VARIABLE:
    1247              :             case libsumo::CMD_SUBSCRIBE_SIM_VARIABLE:
    1248              :             case libsumo::CMD_SUBSCRIBE_TL_VARIABLE:
    1249              :             case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_VARIABLE:
    1250              :             case libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE:
    1251              :             case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE:
    1252         5217 :                 success = addObjectVariableSubscription(commandId, false);
    1253              :                 break;
    1254         4110 :             case libsumo::CMD_SUBSCRIBE_BUSSTOP_CONTEXT:
    1255              :             case libsumo::CMD_SUBSCRIBE_CALIBRATOR_CONTEXT:
    1256              :             case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_CONTEXT:
    1257              :             case libsumo::CMD_SUBSCRIBE_EDGE_CONTEXT:
    1258              :             case libsumo::CMD_SUBSCRIBE_GUI_CONTEXT:
    1259              :             case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT:
    1260              :             case libsumo::CMD_SUBSCRIBE_JUNCTION_CONTEXT:
    1261              :             case libsumo::CMD_SUBSCRIBE_LANE_CONTEXT:
    1262              :             case libsumo::CMD_SUBSCRIBE_LANEAREA_CONTEXT:
    1263              :             case libsumo::CMD_SUBSCRIBE_MEANDATA_CONTEXT:
    1264              :             case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT:
    1265              :             case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_CONTEXT:
    1266              :             case libsumo::CMD_SUBSCRIBE_PARKINGAREA_CONTEXT:
    1267              :             case libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT:
    1268              :             case libsumo::CMD_SUBSCRIBE_POI_CONTEXT:
    1269              :             case libsumo::CMD_SUBSCRIBE_POLYGON_CONTEXT:
    1270              :             case libsumo::CMD_SUBSCRIBE_REROUTER_CONTEXT:
    1271              :             case libsumo::CMD_SUBSCRIBE_ROUTE_CONTEXT:
    1272              :             case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_CONTEXT:
    1273              :             case libsumo::CMD_SUBSCRIBE_SIM_CONTEXT:
    1274              :             case libsumo::CMD_SUBSCRIBE_TL_CONTEXT:
    1275              :             case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_CONTEXT:
    1276              :             case libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT:
    1277              :             case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_CONTEXT:
    1278         4110 :                 success = addObjectVariableSubscription(commandId, true);
    1279              :                 break;
    1280          387 :             case libsumo::CMD_ADD_SUBSCRIPTION_FILTER:
    1281          387 :                 success = addSubscriptionFilter();
    1282              :                 break;
    1283              :             case libsumo::CMD_SET_GUI_VARIABLE:
    1284            1 :                 writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
    1285            1 :                 break;
    1286              :             default:
    1287            2 :                 writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
    1288              :         }
    1289              :     }
    1290      9271888 :     if (!success) {
    1291         2111 :         while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
    1292         1115 :             myInputStorage.readChar();
    1293              :         }
    1294              :     }
    1295      9274837 :     if ((int)myInputStorage.position() != commandStart + commandLength) {
    1296            0 :         std::ostringstream msg;
    1297            0 :         msg << "Wrong position in requestMessage after dispatching command " << commandId << ".";
    1298            0 :         msg << " Expected command length was " << commandLength;
    1299            0 :         msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
    1300            0 :         writeStatusCmd(commandId, libsumo::RTYPE_ERR, msg.str());
    1301            0 :         myDoCloseConnection = true;
    1302            0 :     }
    1303      9274837 :     return commandId;
    1304              : }
    1305              : 
    1306              : 
    1307              : // ---------- Server-internal command handling
    1308              : bool
    1309         2099 : TraCIServer::commandGetVersion() {
    1310              :     // Prepare response
    1311         2099 :     tcpip::Storage answerTmp;
    1312         2099 :     answerTmp.writeInt(libsumo::TRACI_VERSION);
    1313         2099 :     answerTmp.writeString("SUMO " VERSION_STRING);
    1314              :     // When we get here, the response is stored in answerTmp -> put into myOutputStorage
    1315         2099 :     writeStatusCmd(libsumo::CMD_GETVERSION, libsumo::RTYPE_OK, "");
    1316              :     // command length
    1317         2099 :     myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
    1318              :     // command type
    1319         2099 :     myOutputStorage.writeUnsignedByte(libsumo::CMD_GETVERSION);
    1320              :     // and the parameter dependant part
    1321         2099 :     myOutputStorage.writeStorage(answerTmp);
    1322         2099 :     return true;
    1323         2099 : }
    1324              : 
    1325              : 
    1326              : void
    1327      7910204 : TraCIServer::postProcessSimulationStep() {
    1328      7910204 :     SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1329              : #ifdef DEBUG_MULTI_CLIENTS
    1330              :     std::cout << "   postProcessSimulationStep() at time=" << t << std::endl;
    1331              : #endif
    1332     15820408 :     writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
    1333              :     int noActive = 0;
    1334     12075315 :     for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
    1335              :         const libsumo::Subscription& s = *i;
    1336      4165111 :         bool isArrivedVehicle = (s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT)
    1337      4165111 :                                 && (find(myVehicleStateChanges[MSNet::VehicleState::ARRIVED].begin(), myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end());
    1338              : 
    1339      4165111 :         bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT) && MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
    1340      4165111 :         if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
    1341         2063 :             i = mySubscriptions.erase(i);
    1342         2063 :             continue;
    1343              :         }
    1344              :         ++i;
    1345      4163048 :         if (s.beginTime > t) {
    1346           25 :             continue;
    1347              :         }
    1348      4163023 :         ++noActive;
    1349              :     }
    1350      7910204 :     mySubscriptionCache.reset();
    1351              : #ifdef DEBUG_SUBSCRIPTIONS
    1352              :     std::cout << "   Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
    1353              :               << "\n   Nr. of active subscriptions = " << noActive << std::endl;
    1354              : #endif
    1355      7910204 :     mySubscriptionCache.writeInt(noActive);
    1356              : #ifdef DEBUG_SUBSCRIPTIONS
    1357              :     std::cout << "   Size after writing an int is " << mySubscriptionCache.size() << std::endl;
    1358              : #endif
    1359     12073252 :     for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
    1360              :         const libsumo::Subscription& s = *i;
    1361      4163048 :         if (s.beginTime > t) {
    1362              :             ++i;
    1363           25 :             continue;
    1364              :         }
    1365      4163023 :         tcpip::Storage into;
    1366              :         std::string errors;
    1367      4163023 :         bool ok = processSingleSubscription(s, into, errors);
    1368              : #ifdef DEBUG_SUBSCRIPTIONS
    1369              :         std::cout << "   Size of into-store for subscription " << s.id
    1370              :                   << ": " << into.size() << std::endl;
    1371              : #endif
    1372      4163023 :         mySubscriptionCache.writeStorage(into);
    1373      4163023 :         if (ok) {
    1374              :             ++i;
    1375              :         } else {
    1376            0 :             i = mySubscriptions.erase(i);
    1377              :         }
    1378      4163023 :     }
    1379      7910204 :     myOutputStorage.writeStorage(mySubscriptionCache);
    1380              : #ifdef DEBUG_SUBSCRIPTIONS
    1381              :     std::cout << "   Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
    1382              : #endif
    1383      7910204 : }
    1384              : 
    1385              : 
    1386              : void
    1387        18882 : TraCIServer::sendSingleSimStepResponse() {
    1388              : #ifdef DEBUG_MULTI_CLIENTS
    1389              :     std::cout << "       Sending cached simstep response to current client " << myCurrentSocket->second->socket
    1390              :               << " (-> intermediate TraCI step)."
    1391              :               << "\n       Size of mySubscriptionCache is " << mySubscriptionCache.size()
    1392              :               << std::endl;
    1393              : #endif
    1394        18882 :     writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
    1395              : 
    1396              : // NOTE: the commented code would send an empty response
    1397              : //    myOutputStorage.writeInt(0);
    1398              : //    myCurrentSocket->second->socket->sendExact(myOutputStorage);
    1399              : //    myOutputStorage.reset();
    1400        18882 :     myOutputStorage.writeStorage(mySubscriptionCache);
    1401              :     // send results to active client
    1402        18882 :     myCurrentSocket->second->socket->sendExact(myOutputStorage);
    1403        18882 :     myOutputStorage.reset();
    1404        18882 : }
    1405              : 
    1406              : 
    1407              : void
    1408      7943973 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
    1409      7943973 :     writeStatusCmd(commandId, status, description, myOutputStorage);
    1410      7943973 : }
    1411              : 
    1412              : 
    1413              : void
    1414     25605582 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
    1415     25605582 :     if (status == libsumo::RTYPE_ERR) {
    1416         6528 :         WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
    1417     25603406 :     } else if (status == libsumo::RTYPE_NOTIMPLEMENTED) {
    1418          438 :         WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
    1419              :     }
    1420     25605582 :     outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
    1421     25605582 :     outputStorage.writeUnsignedByte(commandId); // command type
    1422     25605582 :     outputStorage.writeUnsignedByte(status); // status
    1423     25605582 :     outputStorage.writeString(description); // description
    1424     25605582 : }
    1425              : 
    1426              : 
    1427              : bool
    1428          944 : TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
    1429          944 :     writeStatusCmd(commandId, libsumo::RTYPE_ERR, description, outputStorage);
    1430          944 :     return false;
    1431              : }
    1432              : 
    1433              : 
    1434              : void
    1435         7866 : TraCIServer::initialiseSubscription(libsumo::Subscription& s) {
    1436         7866 :     tcpip::Storage writeInto;
    1437              :     std::string errors;
    1438         7866 :     libsumo::Subscription* modifiedSubscription = nullptr;
    1439              :     try {
    1440         7866 :         if (processSingleSubscription(s, writeInto, errors)) {
    1441         6642 :             if (s.endTime < MSNet::getInstance()->getCurrentTimeStep()) {
    1442            0 :                 writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Subscription has ended.");
    1443              :             } else {
    1444         6642 :                 if (libsumo::Helper::needNewSubscription(s, mySubscriptions, modifiedSubscription)) {
    1445              :                     // Add new subscription to subscription cache (note: seems a bit inefficient)
    1446         4507 :                     if (s.beginTime < MSNet::getInstance()->getCurrentTimeStep()) {
    1447              :                         // copy new subscription into cache
    1448         4461 :                         int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
    1449         4461 :                         tcpip::Storage tmp;
    1450         4461 :                         tmp.writeInt(noActive);
    1451     28560261 :                         while (mySubscriptionCache.valid_pos()) {
    1452     28555800 :                             tmp.writeByte(mySubscriptionCache.readByte());
    1453              :                         }
    1454         4461 :                         tmp.writeStorage(writeInto);
    1455         4461 :                         mySubscriptionCache.reset();
    1456         4461 :                         mySubscriptionCache.writeStorage(tmp);
    1457         4461 :                     }
    1458              :                 }
    1459        13284 :                 writeStatusCmd(s.commandId, libsumo::RTYPE_OK, "");
    1460              :             }
    1461         6642 :             if (modifiedSubscription != nullptr && (
    1462              :                         modifiedSubscription->isVehicleToVehicleContextSubscription()
    1463              :                         || modifiedSubscription->isVehicleToPersonContextSubscription())) {
    1464              :                 // Set last modified vehicle context subscription active for filter modifications
    1465          150 :                 myLastContextSubscription = modifiedSubscription;
    1466              :             } else {
    1467              :                 // adding other subscriptions deactivates the activation for filter addition
    1468         6492 :                 myLastContextSubscription = nullptr;
    1469              :             }
    1470              :         } else {
    1471          204 :             writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Could not add subscription. " + errors);
    1472              :         }
    1473         1122 :     } catch (libsumo::TraCIException& e) {
    1474         1122 :         writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, e.what());
    1475         1122 :     }
    1476         7866 :     myOutputStorage.writeStorage(writeInto);
    1477         7866 : }
    1478              : 
    1479              : 
    1480              : void
    1481         1455 : TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
    1482              :     bool found = false;
    1483              :     std::vector<libsumo::Subscription>::iterator j;
    1484         2940 :     for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
    1485         1485 :         if (j->id == id && j->commandId == commandId && j->contextDomain == domain) {
    1486         1455 :             j = mySubscriptions.erase(j);
    1487         1455 :             if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
    1488              :                 // Remove also reference for filter additions
    1489            0 :                 myLastContextSubscription = nullptr;
    1490              :             }
    1491              :             found = true;
    1492         1455 :             continue;
    1493              :         }
    1494              :         ++j;
    1495              :     }
    1496              :     // try unsubscribe
    1497         1455 :     if (found) {
    1498         2910 :         writeStatusCmd(commandId, libsumo::RTYPE_OK, "");
    1499              :     } else {
    1500            0 :         writeStatusCmd(commandId, libsumo::RTYPE_ERR, "The subscription to remove was not found.");
    1501              :     }
    1502         1455 : }
    1503              : 
    1504              : 
    1505              : bool
    1506      4170889 : TraCIServer::processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
    1507              :                                        std::string& errors) {
    1508              :     bool ok = true;
    1509      4170889 :     tcpip::Storage outputStorage;
    1510      4170889 :     const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
    1511              :     std::set<std::string> objIDs;
    1512      4170889 :     if (s.contextDomain > 0) {
    1513        62086 :         if ((s.activeFilters & libsumo::SUBS_FILTER_NO_RTREE) == 0) {
    1514        60380 :             PositionVector shape;
    1515        60380 :             libsumo::Helper::findObjectShape(s.commandId, s.id, shape);
    1516        60380 :             libsumo::Helper::collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
    1517        60380 :         }
    1518        60964 :         libsumo::Helper::applySubscriptionFilters(s, objIDs);
    1519              :     } else {
    1520      4108803 :         objIDs.insert(s.id);
    1521              :     }
    1522      4169767 :     const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == libsumo::TRACI_ID_LIST ? 0 : (int)s.variables.size();
    1523              :     int skipped = 0;
    1524      8474550 :     for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
    1525      4304783 :         if (s.contextDomain > 0) {
    1526              :             //if (centralObject(s, *j)) {
    1527              :             //    skipped++;
    1528              :             //    continue;
    1529              :             //}
    1530       195980 :             outputStorage.writeString(*j);
    1531              :         }
    1532      4304783 :         if (numVars > 0) {
    1533              :             std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
    1534     12699251 :             for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
    1535      8401659 :                 tcpip::Storage message;
    1536      8401659 :                 message.writeUnsignedByte(*i);
    1537      8401659 :                 message.writeString(*j);
    1538              :                 // TODO check why writeStorage fails here (probably some kind of invalid iterator)
    1539      8492616 :                 for (const auto& v :** k) {
    1540        90957 :                     message.writeChar(v);
    1541              :                 }
    1542      8401659 :                 tcpip::Storage tmpOutput;
    1543              :                 try {
    1544      8401659 :                     if (myExecutors.find(getCommandId) != myExecutors.end()) {
    1545          615 :                         ok &= myExecutors[getCommandId](*this, message, tmpOutput);
    1546      8401044 :                     } else if (!processGet(getCommandId, message, tmpOutput)) {
    1547           81 :                         if (getCommandId == libsumo::CMD_GET_GUI_VARIABLE) {
    1548            0 :                             writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo", tmpOutput);
    1549              :                         }
    1550              :                         ok = false;
    1551              :                     }
    1552           21 :                 } catch (const std::invalid_argument&) {
    1553           21 :                     writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
    1554              :                     ok = false;
    1555           21 :                 }
    1556              :                 // copy response part
    1557      8401557 :                 if (ok) {
    1558      8401557 :                     int length = tmpOutput.readUnsignedByte();
    1559     58810899 :                     while (--length > 0) {
    1560     50409342 :                         tmpOutput.readUnsignedByte();
    1561              :                     }
    1562              :                     int lengthLength = 1;
    1563      8401557 :                     length = tmpOutput.readUnsignedByte();
    1564      8401557 :                     if (length == 0) {
    1565              :                         lengthLength = 5;
    1566           39 :                         length = tmpOutput.readInt();
    1567              :                     }
    1568              :                     //read responseType
    1569      8401557 :                     tmpOutput.readUnsignedByte();
    1570      8401557 :                     int variable = tmpOutput.readUnsignedByte();
    1571      8401557 :                     std::string id = tmpOutput.readString();
    1572      8401557 :                     outputStorage.writeUnsignedByte(variable);
    1573      8401557 :                     outputStorage.writeUnsignedByte(libsumo::RTYPE_OK);
    1574      8401557 :                     length -= (lengthLength + 1 + 4 + (int)id.length());
    1575    106383340 :                     while (--length > 0) {
    1576     97981783 :                         outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
    1577              :                     }
    1578              :                 } else {
    1579              :                     //read length
    1580          102 :                     tmpOutput.readUnsignedByte();
    1581              :                     //read cmd
    1582          102 :                     tmpOutput.readUnsignedByte();
    1583              :                     //read status
    1584          102 :                     tmpOutput.readUnsignedByte();
    1585          102 :                     std::string msg = tmpOutput.readString();
    1586          102 :                     outputStorage.writeUnsignedByte(*i);
    1587          102 :                     outputStorage.writeUnsignedByte(libsumo::RTYPE_ERR);
    1588          102 :                     outputStorage.writeUnsignedByte(libsumo::TYPE_STRING);
    1589          102 :                     outputStorage.writeString(msg);
    1590          204 :                     errors = errors + msg;
    1591              :                 }
    1592      8401659 :             }
    1593              :         }
    1594              :     }
    1595      4169767 :     int length = (1 + 4) + 1 + (4 + (int)s.id.length()) + 1 + (int)outputStorage.size();
    1596      4169767 :     if (s.contextDomain > 0) {
    1597        60964 :         length += 1 + 4;  // context domain and number of objects
    1598              :     }
    1599              :     // we always write extended command length here for backward compatibility
    1600      4169767 :     writeInto.writeUnsignedByte(0); // command length -> extended
    1601      4169767 :     writeInto.writeInt(length);
    1602      4169767 :     writeInto.writeUnsignedByte(s.commandId + 0x10);
    1603      4169767 :     writeInto.writeString(s.id);
    1604      4169767 :     if (s.contextDomain > 0) {
    1605        60964 :         writeInto.writeUnsignedByte(s.contextDomain);
    1606              :     }
    1607      4169767 :     writeInto.writeUnsignedByte(numVars);
    1608      4169767 :     if (s.contextDomain > 0) {
    1609        60964 :         writeInto.writeInt((int)objIDs.size() - skipped);
    1610              :     }
    1611      4169767 :     if (s.contextDomain == 0 || objIDs.size() != 0) {
    1612      4148210 :         writeInto.writeStorage(outputStorage);
    1613              :     }
    1614      4169767 :     return ok;
    1615      4170889 : }
    1616              : 
    1617              : 
    1618              : bool
    1619         9327 : TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
    1620         9327 :     const double beginTime = myInputStorage.readDouble();
    1621         9327 :     const double endTime = myInputStorage.readDouble();
    1622         9327 :     const SUMOTime begin = beginTime == libsumo::INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
    1623         9327 :     const SUMOTime end = endTime == libsumo::INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
    1624         9327 :     const std::string id = myInputStorage.readString();
    1625         9327 :     const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
    1626         4110 :     double range = hasContext ? myInputStorage.readDouble() : 0.;
    1627         9327 :     if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
    1628              :         range = std::numeric_limits<double>::max();
    1629              :     }
    1630         9327 :     const int num = myInputStorage.readUnsignedByte();
    1631              :     std::vector<int> variables;
    1632              :     std::vector<std::shared_ptr<tcpip::Storage> > parameters;
    1633        20047 :     for (int i = 0; i < num; ++i) {
    1634        10726 :         const int varID = myInputStorage.readUnsignedByte();
    1635        10726 :         variables.push_back(varID);
    1636        10726 :         parameters.push_back(std::make_shared<tcpip::Storage>());
    1637        10726 :         if ((myParameterized.count(std::make_pair(0, varID)) > 0) || (myParameterized.count(std::make_pair(commandId, varID)) > 0)) {
    1638          323 :             if (!myInputStorage.valid_pos()) {
    1639           12 :                 writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Missing parameter for subscription " + toHex(commandId, 2));
    1640            6 :                 return false;
    1641              :             }
    1642              :             int count = 1;
    1643          688 :             while (count-- > 0) {
    1644          383 :                 const int parType = myInputStorage.readUnsignedByte();
    1645          383 :                 parameters.back()->writeUnsignedByte(parType);
    1646              :                 if (parType == libsumo::TYPE_DOUBLE) {
    1647           95 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1648              :                 } else if (parType == libsumo::TYPE_INTEGER) {
    1649           33 :                     parameters.back()->writeInt(myInputStorage.readInt());
    1650              :                 } else if (parType == libsumo::TYPE_STRING) {
    1651          408 :                     parameters.back()->writeString(myInputStorage.readString());
    1652              :                 } else if (parType == libsumo::TYPE_BYTE) {
    1653            6 :                     parameters.back()->writeByte(myInputStorage.readByte());
    1654              :                 } else if (parType == libsumo::TYPE_UBYTE) {
    1655            3 :                     parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
    1656              :                 } else if (parType == libsumo::POSITION_2D) {
    1657            6 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1658            6 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1659            6 :                     if (varID == libsumo::DISTANCE_REQUEST) {
    1660            6 :                         parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
    1661              :                         break;
    1662              :                     }
    1663              :                 } else if (parType == libsumo::POSITION_3D) {
    1664            0 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1665            0 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1666            0 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1667            0 :                     if (varID == libsumo::DISTANCE_REQUEST) {
    1668            0 :                         parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
    1669              :                         break;
    1670              :                     }
    1671              :                 } else if (parType == libsumo::POSITION_ROADMAP) {
    1672           12 :                     parameters.back()->writeString(myInputStorage.readString());
    1673            6 :                     parameters.back()->writeDouble(myInputStorage.readDouble());
    1674            6 :                     parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
    1675            6 :                     if (varID == libsumo::DISTANCE_REQUEST) {
    1676            6 :                         parameters.back()->writeUnsignedByte(myInputStorage.readUnsignedByte());
    1677              :                         break;
    1678              :                     }
    1679              :                 } else if (parType == libsumo::TYPE_COMPOUND) {
    1680           30 :                     count = myInputStorage.readInt();
    1681           30 :                     parameters.back()->writeInt(count);
    1682              :                 } else {
    1683            0 :                     writeStatusCmd(commandId, libsumo::RTYPE_ERR, "Invalid parameter for subscription " + toHex(commandId, 2));
    1684            0 :                     return false;
    1685              :                 }
    1686              :             }
    1687              :         }
    1688              :     }
    1689              :     // check subscribe/unsubscribe
    1690         9321 :     if (variables.empty()) {
    1691         1455 :         removeSubscription(commandId, id, domain);
    1692              :         return true;
    1693              :     }
    1694              :     // process subscription
    1695         7866 :     libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
    1696         7866 :     initialiseSubscription(s);
    1697              :     return true;
    1698        17193 : }
    1699              : 
    1700              : 
    1701              : 
    1702              : bool
    1703          387 : TraCIServer::addSubscriptionFilter() {
    1704              :     bool success  = true;
    1705              :     // Read filter type
    1706          387 :     int filterType = myInputStorage.readUnsignedByte();
    1707              : 
    1708          387 :     if (myLastContextSubscription == nullptr) {
    1709            2 :         writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_ERR,
    1710            2 :                        "No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
    1711            2 :         return false;
    1712              :     }
    1713              : 
    1714              :     // dispatch according to filter type
    1715          385 :     switch (filterType) {
    1716            0 :         case libsumo::FILTER_TYPE_NONE:
    1717              :             // Remove all filters
    1718            0 :             removeFilters();
    1719              :             break;
    1720           90 :         case libsumo::FILTER_TYPE_LANES: {
    1721              :             // Read relative lanes to consider for context filter
    1722           90 :             int nrLanes = (int)myInputStorage.readByte();
    1723              :             std::vector<int> lanes;
    1724          243 :             for (int i = 0; i < nrLanes; ++i) {
    1725          153 :                 lanes.push_back((int) myInputStorage.readByte());
    1726              :             }
    1727           90 :             addSubscriptionFilterLanes(lanes);
    1728           90 :         }
    1729              :         break;
    1730           29 :         case libsumo::FILTER_TYPE_NOOPPOSITE:
    1731              :             // Add no-opposite filter
    1732           29 :             addSubscriptionFilterNoOpposite();
    1733              :             break;
    1734          103 :         case libsumo::FILTER_TYPE_DOWNSTREAM_DIST: {
    1735          103 :             myInputStorage.readByte(); // read type double
    1736          103 :             double dist = myInputStorage.readDouble();
    1737          103 :             addSubscriptionFilterDownstreamDistance(dist);
    1738              :         }
    1739              :         break;
    1740           87 :         case libsumo::FILTER_TYPE_UPSTREAM_DIST: {
    1741           87 :             myInputStorage.readByte(); // read type double
    1742           87 :             double dist = myInputStorage.readDouble();
    1743           87 :             addSubscriptionFilterUpstreamDistance(dist);
    1744              :         }
    1745              :         break;
    1746           13 :         case libsumo::FILTER_TYPE_LEAD_FOLLOW: {
    1747              :             // Read relative lanes to consider for context filter
    1748           13 :             addSubscriptionFilterLeadFollow();
    1749              :         }
    1750              :         break;
    1751           17 :         case libsumo::FILTER_TYPE_TURN: {
    1752           17 :             myInputStorage.readByte(); // read type double
    1753           17 :             double dist = myInputStorage.readDouble();
    1754           17 :             addSubscriptionFilterTurn(dist);
    1755              :         }
    1756              :         break;
    1757            7 :         case libsumo::FILTER_TYPE_VCLASS: {
    1758            7 :             myInputStorage.readByte(); // read type stringlist
    1759            7 :             SVCPermissions vClasses = parseVehicleClasses(myInputStorage.readStringList());
    1760            7 :             addSubscriptionFilterVClass(vClasses);
    1761              :         }
    1762              :         break;
    1763            7 :         case libsumo::FILTER_TYPE_VTYPE: {
    1764            7 :             myInputStorage.readByte(); // read type stringlist
    1765            7 :             std::vector<std::string> vTypesVector = myInputStorage.readStringList();
    1766              :             std::set<std::string> vTypesSet;
    1767              :             vTypesSet.insert(vTypesVector.begin(), vTypesVector.end());
    1768           14 :             addSubscriptionFilterVType(vTypesSet);
    1769            7 :         }
    1770              :         break;
    1771           17 :         case libsumo::FILTER_TYPE_FIELD_OF_VISION: {
    1772           17 :             myInputStorage.readByte();  // read type double
    1773           17 :             double angle = myInputStorage.readDouble();
    1774           17 :             addSubscriptionFilterFieldOfVision(angle);
    1775              :         }
    1776              :         break;
    1777           15 :         case libsumo::FILTER_TYPE_LATERAL_DIST: {
    1778           15 :             myInputStorage.readByte();  // read type double
    1779           15 :             double dist = myInputStorage.readDouble();
    1780           15 :             addSubscriptionFilterLateralDistance(dist);
    1781              :         }
    1782              :         break;
    1783            0 :         default:
    1784            0 :             writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_NOTIMPLEMENTED,
    1785            0 :                            "'" + toString(filterType) + "' is no valid filter type code.");
    1786              :             success  = false;
    1787              :     }
    1788              : 
    1789              :     if (success) {
    1790              :         // acknowledge filter addition
    1791          770 :         writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_OK, "");
    1792              :     }
    1793              : 
    1794              :     return success;
    1795              : }
    1796              : 
    1797              : 
    1798              : void
    1799            0 : TraCIServer::removeFilters() {
    1800              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1801              :     std::cout << "Removing filters" << std::endl;
    1802              : #endif
    1803            0 :     myLastContextSubscription->activeFilters = libsumo::SUBS_FILTER_NONE;
    1804            0 : }
    1805              : 
    1806              : void
    1807           90 : TraCIServer::addSubscriptionFilterLanes(std::vector<int> lanes) {
    1808              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1809              :     std::cout << "Adding lane filter (lanes=" << toString(lanes) << ")" << std::endl;
    1810              : #endif
    1811           90 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LANES;
    1812           90 :     myLastContextSubscription->filterLanes = lanes;
    1813           90 : }
    1814              : 
    1815              : void
    1816           29 : TraCIServer::addSubscriptionFilterNoOpposite() {
    1817              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1818              :     std::cout << "Adding no opposite filter" << std::endl;
    1819              : #endif
    1820           29 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_NOOPPOSITE;
    1821           29 : }
    1822              : 
    1823              : void
    1824          103 : TraCIServer::addSubscriptionFilterDownstreamDistance(double dist) {
    1825              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1826              :     std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
    1827              : #endif
    1828          103 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_DOWNSTREAM_DIST;
    1829          103 :     myLastContextSubscription->filterDownstreamDist = dist;
    1830          103 : }
    1831              : 
    1832              : void
    1833           87 : TraCIServer::addSubscriptionFilterUpstreamDistance(double dist) {
    1834              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1835              :     std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
    1836              : #endif
    1837           87 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_UPSTREAM_DIST;
    1838           87 :     myLastContextSubscription->filterUpstreamDist = dist;
    1839           87 : }
    1840              : 
    1841              : void
    1842           13 : TraCIServer::addSubscriptionFilterLeadFollow() {
    1843              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1844              :     std::cout << "Adding Lead/Follow-maneuver filter" << std::endl;
    1845              : #endif
    1846           13 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LEAD_FOLLOW;
    1847           13 : }
    1848              : 
    1849              : void
    1850           17 : TraCIServer::addSubscriptionFilterTurn(double dist) {
    1851              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1852              :     std::cout << "Adding turn-maneuver filter" << std::endl;
    1853              : #endif
    1854           17 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_TURN;
    1855           17 :     myLastContextSubscription->filterFoeDistToJunction = dist;
    1856           17 : }
    1857              : 
    1858              : void
    1859            7 : TraCIServer::addSubscriptionFilterVClass(SVCPermissions vClasses) {
    1860              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1861              :     std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
    1862              : #endif
    1863            7 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VCLASS;
    1864            7 :     myLastContextSubscription->filterVClasses = vClasses;
    1865            7 : }
    1866              : 
    1867              : void
    1868            7 : TraCIServer::addSubscriptionFilterVType(std::set<std::string> vTypes) {
    1869              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1870              :     std::cout << "Adding vType filter (vTypes=" << toString(vTypes) << ")" << std::endl;
    1871              : #endif
    1872            7 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VTYPE;
    1873              :     myLastContextSubscription->filterVTypes = vTypes;
    1874            7 : }
    1875              : 
    1876              : void
    1877           17 : TraCIServer::addSubscriptionFilterFieldOfVision(double openingAngle) {
    1878              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1879              :     std::cout << "Adding FieldOfVision filter (openingAngle=" << toString(openingAngle) << ")" << std::endl;
    1880              : #endif
    1881           17 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_FIELD_OF_VISION;
    1882           17 :     myLastContextSubscription->filterFieldOfVisionOpeningAngle = openingAngle;
    1883           17 : }
    1884              : 
    1885              : void
    1886           15 : TraCIServer::addSubscriptionFilterLateralDistance(double dist) {
    1887              : #ifdef DEBUG_SUBSCRIPTION_FILTERS
    1888              :     std::cout << "Adding lateral dist filter (dist=" << toString(dist) << ")" << std::endl;
    1889              : #endif
    1890           15 :     myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LATERAL_DIST;
    1891           15 :     myLastContextSubscription->filterLateralDist = dist;
    1892           15 : }
    1893              : 
    1894              : void
    1895     17553306 : TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
    1896     17553306 :     if (tempMsg.size() < 254) {
    1897     17528838 :         outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
    1898              :     } else {
    1899        24468 :         outputStorage.writeUnsignedByte(0); // command length -> extended
    1900        24468 :         outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
    1901              :     }
    1902     17553306 :     outputStorage.writeStorage(tempMsg);
    1903     17553306 : }
    1904              : 
    1905              : 
    1906              : void
    1907          135 : TraCIServer::stateLoaded(SUMOTime targetTime) {
    1908          135 :     myTargetTime = targetTime;
    1909          270 :     for (auto& s : mySockets) {
    1910          135 :         s.second->targetTime = targetTime;
    1911          135 :         s.second->executeMove = false;
    1912         1890 :         for (auto& stateChange : s.second->vehicleStateChanges) {
    1913              :             stateChange.second.clear();
    1914              :         }
    1915          675 :         for (auto& stateChange : s.second->transportableStateChanges) {
    1916              :             stateChange.second.clear();
    1917              :         }
    1918              :     }
    1919              :     mySubscriptions.clear();
    1920          135 :     mySubscriptionCache.reset();
    1921          135 : }
    1922              : 
    1923              : 
    1924              : bool
    1925            0 : TraCIServer::centralObject(const libsumo::Subscription& s, const std::string& objID) {
    1926            0 :     return (s.id == objID && s.commandId + 32 == s.contextDomain);
    1927              : }
    1928              : 
    1929              : 
    1930              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1