Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2007-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file TraCIServer.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 <libsumo/Helper.h>
53 : #include <microsim/MSNet.h>
54 : #include <microsim/MSVehicle.h>
55 : #include <microsim/MSEdge.h>
56 : #include <microsim/MSJunctionControl.h>
57 : #include <microsim/transportables/MSTransportableControl.h>
58 : #include <microsim/MSJunction.h>
59 : #include <microsim/MSEdgeControl.h>
60 : #include <microsim/MSLane.h>
61 : #include <microsim/MSGlobals.h>
62 : #include <microsim/traffic_lights/MSTLLogicControl.h>
63 : #include <libsumo/Simulation.h>
64 : #include <libsumo/Subscription.h>
65 : #include <libsumo/TraCIConstants.h>
66 : #include "TraCIServer.h"
67 : #include "TraCIServerAPI_InductionLoop.h"
68 : #include "TraCIServerAPI_Junction.h"
69 : #include "TraCIServerAPI_Lane.h"
70 : #include "TraCIServerAPI_MultiEntryExit.h"
71 : #include "TraCIServerAPI_LaneArea.h"
72 : #include "TraCIServerAPI_TrafficLight.h"
73 : #include "TraCIServerAPI_Vehicle.h"
74 : #include "TraCIServerAPI_VehicleType.h"
75 : #include "TraCIServerAPI_Route.h"
76 : #include "TraCIServerAPI_POI.h"
77 : #include "TraCIServerAPI_Polygon.h"
78 : #include "TraCIServerAPI_Edge.h"
79 : #include "TraCIServerAPI_Simulation.h"
80 : #include "TraCIServerAPI_Person.h"
81 : #include "TraCIServerAPI_Calibrator.h"
82 : #include "TraCIServerAPI_BusStop.h"
83 : #include "TraCIServerAPI_ParkingArea.h"
84 : #include "TraCIServerAPI_ChargingStation.h"
85 : #include "TraCIServerAPI_RouteProbe.h"
86 : #include "TraCIServerAPI_Rerouter.h"
87 : #include "TraCIServerAPI_VariableSpeedSign.h"
88 : #include "TraCIServerAPI_MeanData.h"
89 : #include "TraCIServerAPI_OverheadWire.h"
90 :
91 :
92 : // ===========================================================================
93 : // debug constants
94 : // ===========================================================================
95 : //#define DEBUG_MULTI_CLIENTS
96 : //#define DEBUG_SUBSCRIPTIONS
97 : //#define DEBUG_SUBSCRIPTION_FILTERS
98 : //#define DEBUG_RAW_INPUT
99 :
100 :
101 : // ===========================================================================
102 : // static member definitions
103 : // ===========================================================================
104 : TraCIServer* TraCIServer::myInstance = nullptr;
105 : bool TraCIServer::myDoCloseConnection = false;
106 :
107 :
108 : // ===========================================================================
109 : // method definitions
110 : // ===========================================================================
111 : void
112 25831249 : TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
113 25831249 : myWrapperStorage.reset();
114 25831249 : myWrapperStorage.writeUnsignedByte(domainID);
115 25831249 : myWrapperStorage.writeUnsignedByte(variable);
116 25831249 : myWrapperStorage.writeString(objID);
117 25831249 : }
118 :
119 :
120 : bool
121 8763096 : TraCIServer::wrapDouble(const std::string& /* objID */, const int /* variable */, const double value) {
122 8763096 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
123 8763096 : myWrapperStorage.writeDouble(value);
124 8763096 : return true;
125 : }
126 :
127 :
128 : bool
129 6744607 : TraCIServer::wrapInt(const std::string& /* objID */, const int /* variable */, const int value) {
130 6744607 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_INTEGER);
131 6744607 : myWrapperStorage.writeInt(value);
132 6744607 : return true;
133 : }
134 :
135 :
136 : bool
137 8393199 : TraCIServer::wrapString(const std::string& /* objID */, const int /* variable */, const std::string& value) {
138 8393199 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
139 8393199 : myWrapperStorage.writeString(value);
140 8393199 : return true;
141 : }
142 :
143 :
144 : bool
145 286710 : TraCIServer::wrapStringList(const std::string& /* objID */, const int /* variable */, const std::vector<std::string>& value) {
146 286710 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
147 286710 : myWrapperStorage.writeStringList(value);
148 286710 : return true;
149 : }
150 :
151 :
152 : bool
153 8 : TraCIServer::wrapDoubleList(const std::string& /* objID */, const int /* variable */, const std::vector<double>& value) {
154 8 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLELIST);
155 8 : myWrapperStorage.writeDoubleList(value);
156 8 : return true;
157 : }
158 :
159 :
160 : bool
161 1361475 : TraCIServer::wrapPosition(const std::string& /* objID */, const int variable, const libsumo::TraCIPosition& value) {
162 : const bool includeZ = variable == libsumo::VAR_POSITION3D;
163 2721351 : myWrapperStorage.writeUnsignedByte(includeZ ? libsumo::POSITION_3D : libsumo::POSITION_2D);
164 1361475 : myWrapperStorage.writeDouble(value.x);
165 1361475 : myWrapperStorage.writeDouble(value.y);
166 1361475 : if (includeZ) {
167 1599 : myWrapperStorage.writeDouble(value.z);
168 : }
169 1361475 : return true;
170 : }
171 :
172 :
173 : bool
174 18142 : TraCIServer::wrapPositionVector(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIPositionVector& shape) {
175 18142 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
176 18142 : if (shape.value.size() < 256) {
177 18138 : myWrapperStorage.writeUnsignedByte((int)shape.value.size());
178 : } else {
179 4 : myWrapperStorage.writeUnsignedByte(0);
180 4 : myWrapperStorage.writeInt((int)shape.value.size());
181 : }
182 64348 : for (const libsumo::TraCIPosition& pos : shape.value) {
183 46206 : myWrapperStorage.writeDouble(pos.x);
184 46206 : myWrapperStorage.writeDouble(pos.y);
185 : }
186 18142 : return true;
187 : }
188 :
189 :
190 : bool
191 1274 : TraCIServer::wrapColor(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIColor& value) {
192 1274 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COLOR);
193 1274 : myWrapperStorage.writeUnsignedByte(value.r);
194 1274 : myWrapperStorage.writeUnsignedByte(value.g);
195 1274 : myWrapperStorage.writeUnsignedByte(value.b);
196 1274 : myWrapperStorage.writeUnsignedByte(value.a);
197 1274 : return true;
198 : }
199 :
200 :
201 : bool
202 33012 : TraCIServer::wrapStringDoublePair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, double>& value) {
203 33012 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
204 33012 : myWrapperStorage.writeInt(2);
205 33012 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
206 33012 : myWrapperStorage.writeString(value.first);
207 33012 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
208 33012 : myWrapperStorage.writeDouble(value.second);
209 33012 : return true;
210 : }
211 :
212 :
213 : bool
214 127 : TraCIServer::wrapStringPair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, std::string>& value) {
215 127 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
216 127 : myWrapperStorage.writeInt(2);
217 127 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
218 127 : myWrapperStorage.writeString(value.first);
219 127 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
220 127 : myWrapperStorage.writeString(value.second);
221 127 : return true;
222 : }
223 :
224 :
225 : tcpip::Storage&
226 26664243 : TraCIServer::getWrapperStorage() {
227 26664243 : return myWrapperStorage;
228 : }
229 :
230 :
231 :
232 3141 : TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
233 3141 : : myTargetTime(begin), myLastContextSubscription(nullptr) {
234 : #ifdef DEBUG_MULTI_CLIENTS
235 : std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
236 : #endif
237 3141 : myVehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
238 3141 : myVehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
239 3141 : myVehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
240 3141 : myVehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
241 3141 : myVehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
242 3141 : myVehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
243 3141 : myVehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
244 3141 : myVehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
245 3141 : myVehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
246 3141 : myVehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
247 3141 : myVehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
248 3141 : myVehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
249 3141 : myVehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
250 :
251 3141 : myTransportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
252 3141 : myTransportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
253 3141 : myTransportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
254 3141 : myTransportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
255 :
256 3141 : myExecutors[libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processGet;
257 3141 : myExecutors[libsumo::CMD_SET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processSet;
258 3141 : myExecutors[libsumo::CMD_GET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processGet;
259 3141 : myExecutors[libsumo::CMD_SET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processSet;
260 3141 : myExecutors[libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processGet;
261 3141 : myExecutors[libsumo::CMD_SET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processSet;
262 :
263 3141 : myExecutors[libsumo::CMD_GET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processGet;
264 3141 : myExecutors[libsumo::CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processSet;
265 3141 : myExecutors[libsumo::CMD_GET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processGet;
266 3141 : myExecutors[libsumo::CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
267 3141 : myExecutors[libsumo::CMD_GET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processGet;
268 3141 : myExecutors[libsumo::CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
269 3141 : myExecutors[libsumo::CMD_GET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processGet;
270 3141 : myExecutors[libsumo::CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
271 3141 : myExecutors[libsumo::CMD_GET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processGet;
272 3141 : myExecutors[libsumo::CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
273 3141 : myExecutors[libsumo::CMD_GET_POI_VARIABLE] = &TraCIServerAPI_POI::processGet;
274 3141 : myExecutors[libsumo::CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
275 3141 : myExecutors[libsumo::CMD_GET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processGet;
276 3141 : myExecutors[libsumo::CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
277 3141 : myExecutors[libsumo::CMD_GET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processGet;
278 3141 : myExecutors[libsumo::CMD_SET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processSet;
279 3141 : myExecutors[libsumo::CMD_GET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processGet;
280 3141 : myExecutors[libsumo::CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
281 3141 : myExecutors[libsumo::CMD_GET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processGet;
282 3141 : myExecutors[libsumo::CMD_SET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processSet;
283 3141 : myExecutors[libsumo::CMD_GET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processGet;
284 3141 : myExecutors[libsumo::CMD_SET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processSet;
285 3141 : myExecutors[libsumo::CMD_GET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processGet;
286 3141 : myExecutors[libsumo::CMD_SET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processSet;
287 3141 : myExecutors[libsumo::CMD_GET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processGet;
288 3141 : myExecutors[libsumo::CMD_SET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processSet;
289 3141 : myExecutors[libsumo::CMD_GET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processGet;
290 3141 : myExecutors[libsumo::CMD_SET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processSet;
291 3141 : myExecutors[libsumo::CMD_GET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processGet;
292 3141 : myExecutors[libsumo::CMD_SET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processSet;
293 3141 : myExecutors[libsumo::CMD_GET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processGet;
294 3141 : myExecutors[libsumo::CMD_SET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processSet;
295 3141 : myExecutors[libsumo::CMD_GET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processGet;
296 3141 : myExecutors[libsumo::CMD_SET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processSet;
297 3141 : myExecutors[libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processGet;
298 3141 : myExecutors[libsumo::CMD_SET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processSet;
299 3141 : myExecutors[libsumo::CMD_GET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processGet;
300 : //myExecutors[libsumo::CMD_SET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processSet;
301 3141 : myExecutors[libsumo::CMD_GET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processGet;
302 3141 : myExecutors[libsumo::CMD_SET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processSet;
303 :
304 3141 : myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_LEADER));
305 3141 : myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOWER));
306 3141 : myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER));
307 3141 : myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER_WITH_KEY));
308 :
309 3141 : myDoCloseConnection = false;
310 :
311 : // display warning if internal lanes are not used
312 : // TODO this may be redundant to the warning in NLBuilder::build
313 3141 : if (!MSGlobals::gUsingInternalLanes && !MSGlobals::gUseMesoSim) {
314 4 : WRITE_WARNING(TL("Starting TraCI without using internal lanes!"));
315 4 : MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
316 20 : MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
317 : }
318 :
319 : try {
320 6282 : WRITE_MESSAGEF(TL("***Starting server on port % ***"), toString(port));
321 3141 : tcpip::Socket serverSocket(port);
322 3141 : if (numClients > 1) {
323 236 : WRITE_MESSAGEF(TL(" waiting for % clients..."), toString(numClients));
324 : }
325 6526 : while ((int)mySockets.size() < numClients) {
326 3391 : int index = (int)mySockets.size() + libsumo::MAX_ORDER + 1;
327 3391 : mySockets[index] = new SocketInfo(serverSocket.accept(true), begin);
328 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
329 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
330 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
331 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
332 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
333 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
334 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
335 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
336 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
337 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
338 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
339 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
340 3385 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
341 :
342 3385 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
343 3385 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
344 3385 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
345 3385 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
346 3385 : if (numClients > 1) {
347 736 : WRITE_MESSAGE(TL(" client connected"));
348 : }
349 : }
350 : // When got here, all clients have connected
351 3135 : if (numClients > 1) {
352 118 : checkClientOrdering();
353 : }
354 : // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommands()
355 3129 : myCurrentSocket = mySockets.begin();
356 3153 : } catch (tcpip::SocketException& e) {
357 12 : throw ProcessError(e.what());
358 6 : }
359 3201 : }
360 :
361 :
362 6258 : TraCIServer::~TraCIServer() {
363 3165 : for (const auto& socket : mySockets) {
364 36 : delete socket.second;
365 : }
366 : // there is no point in calling cleanup() here, it does not free any pointers and will only modify members which get deleted anyway
367 9387 : }
368 :
369 :
370 : // ---------- Initialisation and Shutdown
371 : void
372 35485 : TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
373 103280 : if (myInstance == nullptr && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0)) {
374 9411 : myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
375 6282 : OptionsCont::getOptions().getInt("remote-port"),
376 6282 : OptionsCont::getOptions().getInt("num-clients"));
377 3415 : for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
378 286 : myInstance->myExecutors[i->first] = i->second;
379 : }
380 : }
381 35473 : if (myInstance != nullptr) {
382 : // maybe net was deleted and built again
383 3146 : MSNet::getInstance()->addVehicleStateListener(myInstance);
384 3146 : MSNet::getInstance()->addTransportableStateListener(myInstance);
385 3146 : myInstance->mySubscriptionCache.writeInt(0);
386 : }
387 35473 : }
388 :
389 :
390 : void
391 35331 : TraCIServer::close() {
392 35331 : if (myInstance == nullptr) {
393 : return;
394 : }
395 3129 : delete myInstance;
396 3129 : myInstance = nullptr;
397 3129 : myDoCloseConnection = true;
398 : }
399 :
400 :
401 : bool
402 82572022 : TraCIServer::wasClosed() {
403 82572022 : return myDoCloseConnection;
404 : }
405 :
406 :
407 : // ---------- Initialisation and Shutdown
408 :
409 :
410 : void
411 148820 : TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
412 148820 : if (!myDoCloseConnection) {
413 148820 : myVehicleStateChanges[to].push_back(vehicle->getID());
414 315252 : for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
415 166432 : i->second->vehicleStateChanges[to].push_back(vehicle->getID());
416 : }
417 : }
418 148820 : }
419 :
420 :
421 : void
422 2517 : TraCIServer::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& /*info*/) {
423 2517 : if (!myDoCloseConnection) {
424 2517 : myTransportableStateChanges[to].push_back(transportable->getID());
425 5034 : for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
426 2517 : i->second->transportableStateChanges[to].push_back(transportable->getID());
427 : }
428 : }
429 2517 : }
430 :
431 :
432 : void
433 118 : TraCIServer::checkClientOrdering() {
434 : #ifdef DEBUG_MULTI_CLIENTS
435 : std::cout << "Checking client order requests." << std::endl;
436 : #endif
437 : // check for SET_ORDER commands queued by connected clients
438 : // In multiclient cas it is mandatory that SET_ORDER is sent as the first command (or directly after GET_VERSION)
439 118 : myCurrentSocket = mySockets.begin();
440 477 : while (myCurrentSocket != mySockets.end()) {
441 : #ifdef DEBUG_MULTI_CLIENTS
442 : std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
443 : #endif
444 : // bool clientUnordered = true;
445 : while (true) {
446 726 : myInputStorage.reset();
447 726 : myCurrentSocket->second->socket->receiveExact(myInputStorage);
448 : int commandStart, commandLength;
449 726 : int commandId = readCommandID(commandStart, commandLength);
450 : #ifdef DEBUG_MULTI_CLIENTS
451 : std::cout << " received command " << commandId << std::endl;
452 : #endif
453 : // Whether the received command is a permitted command for the initialization phase.
454 : // Currently, getVersion and setOrder are permitted.
455 726 : bool initCommand = commandId == libsumo::CMD_SETORDER || commandId == libsumo::CMD_GETVERSION;
456 726 : if (initCommand) {
457 : #ifdef DEBUG_MULTI_CLIENTS
458 : std::cout << " Init command. Sending response." << std::endl;
459 : #endif
460 : // reset input storage to initial state before reading the commandId
461 : // (ugly, but we can't just reset the store's iter_ from here)
462 : // Giving the commandId to dispatch command didn't work either
463 720 : tcpip::Storage tmp;
464 720 : tmp.writeStorage(myInputStorage);
465 720 : myInputStorage.reset();
466 : // we don't know whether the command was set with extended
467 : // length syntax or not so we hardcode the length here (#5037)
468 1081 : myInputStorage.writeUnsignedByte(commandId == libsumo::CMD_SETORDER ? 6 : 2);
469 720 : myInputStorage.writeUnsignedByte(commandId);
470 720 : myInputStorage.writeStorage(tmp);
471 :
472 : // Handle initialization command completely
473 720 : dispatchCommand();
474 720 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
475 720 : myOutputStorage.reset();
476 720 : } else {
477 : #ifdef DEBUG_MULTI_CLIENTS
478 : std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
479 : #endif
480 12 : throw ProcessError(TL("Execution order (libsumo::CMD_SETORDER) was not set for all TraCI clients in pre-execution phase."));
481 : }
482 720 : if (commandId == libsumo::CMD_SETORDER) {
483 : // This is what we have waited for.
484 : break;
485 : }
486 361 : }
487 : ++myCurrentSocket;
488 : }
489 112 : }
490 :
491 :
492 : void
493 7071164 : TraCIServer::processReorderingRequests() {
494 : // Process reordering requests
495 7071164 : if (mySocketReorderRequests.size() > 0) {
496 : // process reordering requests
497 : std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
498 : std::map<int, SocketInfo*>::iterator j;
499 : #ifdef DEBUG_MULTI_CLIENTS
500 : std::cout << SIMTIME << " Current socket ordering:\n";
501 : for (j = mySockets.begin(); j != mySockets.end(); ++j) {
502 : std::cout << " " << j->first << ": " << j->second->socket << "\n";
503 : }
504 : std::cout << "Reordering requests:\n";
505 : for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
506 : std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
507 : }
508 : i = mySocketReorderRequests.begin();
509 : #endif
510 484 : while (i != mySocketReorderRequests.end()) {
511 : j = mySockets.begin();
512 849 : while (j != mySockets.end()) {
513 849 : if (j->second->socket == i->second->socket) {
514 : break;
515 : } else {
516 : j++;
517 : }
518 : }
519 : assert(j != mySockets.end());
520 : mySockets.erase(j);
521 364 : mySockets[i->first] = i->second;
522 : ++i;
523 : }
524 : mySocketReorderRequests.clear();
525 : #ifdef DEBUG_MULTI_CLIENTS
526 : std::cout << "New socket ordering:\n";
527 : for (j = mySockets.begin(); j != mySockets.end(); ++j) {
528 : std::cout << " " << j->first << ": " << j->second->socket << "\n";
529 : }
530 : std::cout << std::endl;
531 : #endif
532 : }
533 7071164 : }
534 :
535 :
536 : SUMOTime
537 14079768 : TraCIServer::nextTargetTime() const {
538 : #ifdef DEBUG_MULTI_CLIENTS
539 : std::cout << "\n Determining new target time..." << std::endl;
540 : if (mySockets.size() == 0) {
541 : std::cout << " All clients have disconnected." << std::endl;
542 : }
543 : #endif
544 : std::map<int, SocketInfo*>::const_iterator i;
545 : SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
546 28326694 : for (i = mySockets.begin(); i != mySockets.end(); ++i) {
547 : #ifdef DEBUG_MULTI_CLIENTS
548 : std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
549 : #endif
550 14246926 : targetTime = MIN2(targetTime, i->second->targetTime);
551 : }
552 : #ifdef DEBUG_MULTI_CLIENTS
553 : std::cout << std::endl;
554 : #endif
555 14079768 : return targetTime;
556 : }
557 :
558 :
559 : // send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
560 : void
561 7068019 : TraCIServer::sendOutputToAll() const {
562 : #ifdef DEBUG_MULTI_CLIENTS
563 : std::cout << "\n Sending subscription results to clients:\n";
564 : #endif
565 : std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
566 14190848 : while (i != mySockets.end()) {
567 7122829 : if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
568 : // this client will become active before the next SUMO step. Provide subscription results.
569 7014439 : i->second->socket->sendExact(myOutputStorage);
570 : #ifdef DEBUG_MULTI_CLIENTS
571 : std::cout << i->second->socket << "\n";
572 : #endif
573 : }
574 : ++i;
575 : }
576 : #ifdef DEBUG_MULTI_CLIENTS
577 : std::cout << std::endl;
578 : #endif
579 7068019 : }
580 :
581 :
582 : int
583 7071164 : TraCIServer::processCommands(const SUMOTime step, const bool afterMove) {
584 : #ifdef DEBUG_MULTI_CLIENTS
585 : std::cout << SIMTIME << " processCommands(step = " << step << "):\n" << std::endl;
586 : #endif
587 : try {
588 : int finalCmd = 0;
589 : const bool firstStep = myCurrentSocket != mySockets.end();
590 : // update client order if requested
591 7071164 : processReorderingRequests();
592 7071164 : if (!firstStep && !afterMove) {
593 : // 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)
594 : // update subscription results
595 7068019 : postProcessSimulationStep();
596 : // Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
597 7068019 : sendOutputToAll();
598 7068019 : myOutputStorage.reset();
599 : }
600 :
601 : // determine minimal next target time among clients
602 7071164 : myTargetTime = nextTargetTime();
603 :
604 7071164 : if (step < myTargetTime) {
605 : #ifdef DEBUG_MULTI_CLIENTS
606 : std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommands()." << std::endl;
607 : #endif
608 : return finalCmd;
609 : }
610 :
611 : // Simulation should run until
612 : // 1. end time reached or
613 : // 2. got libsumo::CMD_CLOSE or
614 : // 3. got libsumo::CMD_LOAD or
615 : // 4. Client closes socket connection
616 13991766 : while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep()) && finalCmd != libsumo::CMD_EXECUTEMOVE) {
617 : #ifdef DEBUG_MULTI_CLIENTS
618 : std::cout << " Next target time: " << myTargetTime << std::endl;
619 : #endif
620 : // Iterate over clients and process communication for the ones with target time == myTargetTime
621 7011740 : myCurrentSocket = mySockets.begin();
622 14135802 : while (myCurrentSocket != mySockets.end()) {
623 : #ifdef DEBUG_MULTI_CLIENTS
624 : std::cout << " current socket: " << myCurrentSocket->second->socket
625 : << " with target time=" << myCurrentSocket->second->targetTime
626 : << std::endl;
627 : #endif
628 :
629 7124088 : if (myCurrentSocket->second->targetTime > myTargetTime || (afterMove && !myCurrentSocket->second->executeMove)) {
630 : // this client must wait
631 : #ifdef DEBUG_MULTI_CLIENTS
632 : std::cout << " skipping client " << myCurrentSocket->second->socket
633 : << " with target time=" << myCurrentSocket->second->targetTime << std::endl;
634 : #endif
635 : myCurrentSocket++;
636 77940 : continue;
637 : }
638 : finalCmd = 0;
639 23307701 : while (finalCmd == 0) {
640 16261579 : if (!myInputStorage.valid_pos()) {
641 : // have read request completely, send response if adequate
642 16261579 : if (myOutputStorage.size() > 0) {
643 : // send response to previous query
644 9215439 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
645 9215439 : myOutputStorage.reset();
646 : }
647 : #ifdef DEBUG_MULTI_CLIENTS
648 : std::cout << " resetting input storage and reading next command..." << std::endl;
649 : #endif
650 : // Read next request
651 16261579 : myInputStorage.reset();
652 16261579 : myCurrentSocket->second->socket->receiveExact(myInputStorage);
653 : }
654 :
655 32523106 : while (myInputStorage.valid_pos() && !myDoCloseConnection) {
656 16261553 : const int cmd = dispatchCommand();
657 16261553 : if (cmd == libsumo::CMD_SIMSTEP || cmd == libsumo::CMD_LOAD || cmd == libsumo::CMD_EXECUTEMOVE || cmd == libsumo::CMD_CLOSE) {
658 : finalCmd = cmd;
659 : }
660 : }
661 : }
662 : }
663 7011714 : if (!myLoadArgs.empty()) {
664 : #ifdef DEBUG_MULTI_CLIENTS
665 : std::cout << " Breaking loop to load new simulation." << std::endl;
666 : #endif
667 : break;
668 7011697 : } else if (myDoCloseConnection) {
669 : #ifdef DEBUG_MULTI_CLIENTS
670 : std::cout << " Breaking loop because last client closed connection." << std::endl;
671 : #endif
672 : break;
673 : }
674 7008604 : SUMOTime nextT = nextTargetTime();
675 : // minimal target time among clients should have been increased during the last loop through mySockets
676 : // XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
677 : // leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
678 : // the next call is then usually simulationStep(step=1000) leading to no further increase
679 : // and thus a failing assertion here.
680 : //assert(myTargetTime < nextT || myDoCloseConnection);
681 7008604 : myTargetTime = nextT;
682 : }
683 : // All clients are done with the current time step
684 : // Reset myVehicleStateChanges and myTransportableStateChanges
685 97763904 : for (auto& item : myVehicleStateChanges) {
686 : item.second.clear();
687 : }
688 34915680 : for (auto& item : myTransportableStateChanges) {
689 : item.second.clear();
690 : }
691 : return finalCmd;
692 26 : } catch (std::invalid_argument& e) {
693 0 : throw ProcessError(e.what());
694 0 : } catch (libsumo::TraCIException& e) {
695 0 : throw ProcessError(e.what());
696 26 : } catch (tcpip::SocketException& e) {
697 52 : throw ProcessError(e.what());
698 26 : }
699 : }
700 :
701 :
702 : void
703 3138 : TraCIServer::cleanup() {
704 : mySubscriptions.clear();
705 3138 : myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
706 3183 : for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
707 45 : myCurrentSocket->second->targetTime = myTargetTime;
708 45 : myCurrentSocket->second->executeMove = false;
709 : }
710 3138 : myOutputStorage.reset();
711 3138 : myInputStorage.reset();
712 3138 : mySubscriptionCache.reset();
713 43932 : for (auto& i : myVehicleStateChanges) {
714 : i.second.clear();
715 : }
716 15690 : for (auto& i : myTransportableStateChanges) {
717 : i.second.clear();
718 : }
719 3138 : myCurrentSocket = mySockets.begin();
720 3138 : }
721 :
722 :
723 : std::map<int, TraCIServer::SocketInfo*>::iterator
724 3337 : TraCIServer::removeCurrentSocket() {
725 : #ifdef DEBUG_MULTI_CLIENTS
726 : std::cout << " Removing socket " << myCurrentSocket->second->socket
727 : << " (order " << myCurrentSocket->first << ")" << std::endl;
728 : #endif
729 3337 : delete myCurrentSocket->second;
730 3337 : myCurrentSocket = mySockets.erase(myCurrentSocket);
731 3337 : return myCurrentSocket;
732 : }
733 :
734 :
735 : int
736 16262999 : TraCIServer::readCommandID(int& commandStart, int& commandLength) {
737 16262999 : commandStart = myInputStorage.position();
738 16262999 : commandLength = myInputStorage.readUnsignedByte();
739 16262999 : if (commandLength == 0) {
740 95871 : commandLength = myInputStorage.readInt();
741 : }
742 : #ifdef DEBUG_RAW_INPUT
743 : std::cout << " commandStart=" << commandStart << " commandLength=" << commandLength << " pos=" << myInputStorage.position() << " raw=";
744 : for (auto it = myInputStorage.begin(); it != myInputStorage.end(); ++it) {
745 : std::cout << (int)*it << " ";
746 : }
747 : std::cout << "\n";
748 : #endif
749 16262999 : return myInputStorage.readUnsignedByte();
750 : }
751 :
752 :
753 : int
754 16262273 : TraCIServer::dispatchCommand() {
755 : int commandStart, commandLength;
756 16262273 : int commandId = readCommandID(commandStart, commandLength);
757 : #ifdef DEBUG_MULTI_CLIENTS
758 : std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
759 : << ", commandId = " << commandId << std::endl;
760 : #endif
761 : bool success = false;
762 : // dispatch commands
763 16262273 : if (myExecutors.find(commandId) != myExecutors.end()) {
764 9202823 : success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
765 : } else {
766 7059450 : switch (commandId) {
767 2769 : case libsumo::CMD_GETVERSION:
768 2769 : success = commandGetVersion();
769 : break;
770 : case libsumo::CMD_LOAD: {
771 : std::vector<std::string> args;
772 17 : if (!readTypeCheckingStringList(myInputStorage, args)) {
773 0 : return writeErrorStatusCmd(libsumo::CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
774 : }
775 : #ifdef DEBUG_MULTI_CLIENTS
776 : std::cout << " commandId == libsumo::CMD_LOAD"
777 : << ", args = " << toString(args) << std::endl;
778 : #endif
779 : try {
780 17 : myLoadArgs = args;
781 : success = true;
782 34 : writeStatusCmd(libsumo::CMD_LOAD, libsumo::RTYPE_OK, "");
783 : // XXX: This only cares for the client that issued the load command.
784 : // Multiclient-load functionality is still to be implemented. Refs #3146.
785 17 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
786 17 : myCurrentSocket = mySockets.end();
787 17 : myOutputStorage.reset();
788 0 : } catch (libsumo::TraCIException& e) {
789 0 : return writeErrorStatusCmd(libsumo::CMD_LOAD, e.what(), myOutputStorage);
790 0 : }
791 : break;
792 17 : }
793 8 : case libsumo::CMD_EXECUTEMOVE:
794 8 : myCurrentSocket->second->executeMove = true;
795 : myCurrentSocket++;
796 : success = true;
797 16 : writeStatusCmd(libsumo::CMD_EXECUTEMOVE, libsumo::RTYPE_OK, "");
798 : break;
799 7042760 : case libsumo::CMD_SIMSTEP: {
800 7042760 : const double nextT = myInputStorage.readDouble();
801 7042760 : if (nextT == 0.) {
802 6973941 : myCurrentSocket->second->targetTime += DELTA_T;
803 : } else {
804 68819 : myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
805 : }
806 7042760 : myCurrentSocket->second->executeMove = false;
807 : #ifdef DEBUG_MULTI_CLIENTS
808 : std::cout << " commandId == libsumo::CMD_SIMSTEP"
809 : << ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
810 : #endif
811 7042760 : if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
812 : // This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
813 : // @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommands()
814 28320 : sendSingleSimStepResponse();
815 : }
816 : // Clear vehicleStateChanges and transportableStateChanges for this client
817 : // -> For subsequent TraCI stepping
818 : // that is performed within this SUMO step, no updates on vehicle states
819 : // belonging to the last SUMO simulation step will be received by this client.
820 98598640 : for (auto& item : myCurrentSocket->second->vehicleStateChanges) {
821 : item.second.clear();
822 : }
823 35213800 : for (auto& item : myCurrentSocket->second->transportableStateChanges) {
824 : item.second.clear();
825 : }
826 : myCurrentSocket++;
827 7042760 : return commandId;
828 : }
829 : case libsumo::CMD_CLOSE:
830 6674 : writeStatusCmd(libsumo::CMD_CLOSE, libsumo::RTYPE_OK, "");
831 3337 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
832 3337 : myOutputStorage.reset();
833 3337 : if (mySockets.size() == 1) {
834 : // Last client has closed connection
835 3093 : myDoCloseConnection = true;
836 : }
837 : // remove current socket and increment to next socket in ordering
838 3337 : myCurrentSocket = removeCurrentSocket();
839 : success = true;
840 : break;
841 369 : case libsumo::CMD_SETORDER: {
842 369 : const int order = myInputStorage.readInt();
843 : #ifdef DEBUG_MULTI_CLIENTS
844 : std::cout << " commandId == libsumo::CMD_SETORDER"
845 : << ", order index is " << order << std::endl;
846 : #endif
847 369 : if (order > libsumo::MAX_ORDER) {
848 0 : return writeErrorStatusCmd(libsumo::CMD_SETORDER, "A set order command needs an int argument below " + toString(libsumo::MAX_ORDER) + ".", myOutputStorage);
849 : }
850 : if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
851 0 : return writeErrorStatusCmd(libsumo::CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
852 : }
853 : // memorize reorder request (will only take effect in the next step)
854 369 : mySocketReorderRequests[order] = myCurrentSocket->second;
855 : success = true;
856 369 : writeStatusCmd(libsumo::CMD_SETORDER, libsumo::RTYPE_OK, "");
857 369 : break;
858 : }
859 6721 : case libsumo::CMD_SUBSCRIBE_BUSSTOP_VARIABLE:
860 : case libsumo::CMD_SUBSCRIBE_CALIBRATOR_VARIABLE:
861 : case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_VARIABLE:
862 : case libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE:
863 : case libsumo::CMD_SUBSCRIBE_GUI_VARIABLE:
864 : case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE:
865 : case libsumo::CMD_SUBSCRIBE_JUNCTION_VARIABLE:
866 : case libsumo::CMD_SUBSCRIBE_LANE_VARIABLE:
867 : case libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE:
868 : case libsumo::CMD_SUBSCRIBE_MEANDATA_VARIABLE:
869 : case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE:
870 : case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_VARIABLE:
871 : case libsumo::CMD_SUBSCRIBE_PARKINGAREA_VARIABLE:
872 : case libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE:
873 : case libsumo::CMD_SUBSCRIBE_POI_VARIABLE:
874 : case libsumo::CMD_SUBSCRIBE_POLYGON_VARIABLE:
875 : case libsumo::CMD_SUBSCRIBE_REROUTER_VARIABLE:
876 : case libsumo::CMD_SUBSCRIBE_ROUTE_VARIABLE:
877 : case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_VARIABLE:
878 : case libsumo::CMD_SUBSCRIBE_SIM_VARIABLE:
879 : case libsumo::CMD_SUBSCRIBE_TL_VARIABLE:
880 : case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_VARIABLE:
881 : case libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE:
882 : case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE:
883 6721 : success = addObjectVariableSubscription(commandId, false);
884 : break;
885 2818 : case libsumo::CMD_SUBSCRIBE_BUSSTOP_CONTEXT:
886 : case libsumo::CMD_SUBSCRIBE_CALIBRATOR_CONTEXT:
887 : case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_CONTEXT:
888 : case libsumo::CMD_SUBSCRIBE_EDGE_CONTEXT:
889 : case libsumo::CMD_SUBSCRIBE_GUI_CONTEXT:
890 : case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT:
891 : case libsumo::CMD_SUBSCRIBE_JUNCTION_CONTEXT:
892 : case libsumo::CMD_SUBSCRIBE_LANE_CONTEXT:
893 : case libsumo::CMD_SUBSCRIBE_LANEAREA_CONTEXT:
894 : case libsumo::CMD_SUBSCRIBE_MEANDATA_CONTEXT:
895 : case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT:
896 : case libsumo::CMD_SUBSCRIBE_OVERHEADWIRE_CONTEXT:
897 : case libsumo::CMD_SUBSCRIBE_PARKINGAREA_CONTEXT:
898 : case libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT:
899 : case libsumo::CMD_SUBSCRIBE_POI_CONTEXT:
900 : case libsumo::CMD_SUBSCRIBE_POLYGON_CONTEXT:
901 : case libsumo::CMD_SUBSCRIBE_REROUTER_CONTEXT:
902 : case libsumo::CMD_SUBSCRIBE_ROUTE_CONTEXT:
903 : case libsumo::CMD_SUBSCRIBE_ROUTEPROBE_CONTEXT:
904 : case libsumo::CMD_SUBSCRIBE_SIM_CONTEXT:
905 : case libsumo::CMD_SUBSCRIBE_TL_CONTEXT:
906 : case libsumo::CMD_SUBSCRIBE_VARIABLESPEEDSIGN_CONTEXT:
907 : case libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT:
908 : case libsumo::CMD_SUBSCRIBE_VEHICLETYPE_CONTEXT:
909 2818 : success = addObjectVariableSubscription(commandId, true);
910 : break;
911 573 : case libsumo::CMD_ADD_SUBSCRIPTION_FILTER:
912 573 : success = addSubscriptionFilter();
913 : break;
914 78 : default:
915 78 : if (commandId == libsumo::CMD_GET_GUI_VARIABLE || commandId == libsumo::CMD_SET_GUI_VARIABLE) {
916 154 : writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
917 : } else {
918 2 : writeStatusCmd(commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
919 : }
920 : }
921 : }
922 9215704 : if (!success) {
923 2185 : while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
924 1085 : myInputStorage.readChar();
925 : }
926 : }
927 9219513 : if ((int)myInputStorage.position() != commandStart + commandLength) {
928 0 : std::ostringstream msg;
929 0 : msg << "Wrong position in requestMessage after dispatching command " << commandId << ".";
930 0 : msg << " Expected command length was " << commandLength;
931 0 : msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
932 0 : writeStatusCmd(commandId, libsumo::RTYPE_ERR, msg.str());
933 0 : myDoCloseConnection = true;
934 0 : }
935 9219513 : return commandId;
936 : }
937 :
938 :
939 : // ---------- Server-internal command handling
940 : bool
941 2769 : TraCIServer::commandGetVersion() {
942 : // Prepare response
943 2769 : tcpip::Storage answerTmp;
944 2769 : answerTmp.writeInt(libsumo::TRACI_VERSION);
945 2769 : answerTmp.writeString("SUMO " VERSION_STRING);
946 : // When we get here, the response is stored in answerTmp -> put into myOutputStorage
947 2769 : writeStatusCmd(libsumo::CMD_GETVERSION, libsumo::RTYPE_OK, "");
948 : // command length
949 2769 : myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
950 : // command type
951 2769 : myOutputStorage.writeUnsignedByte(libsumo::CMD_GETVERSION);
952 : // and the parameter dependant part
953 2769 : myOutputStorage.writeStorage(answerTmp);
954 2769 : return true;
955 2769 : }
956 :
957 :
958 : void
959 7068019 : TraCIServer::postProcessSimulationStep() {
960 7068019 : SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
961 : #ifdef DEBUG_MULTI_CLIENTS
962 : std::cout << " postProcessSimulationStep() at time=" << t << std::endl;
963 : #endif
964 14136038 : writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
965 : int noActive = 0;
966 15439882 : for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
967 : const libsumo::Subscription& s = *i;
968 8371863 : bool isArrivedVehicle = (s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT)
969 8371863 : && (find(myVehicleStateChanges[MSNet::VehicleState::ARRIVED].begin(), myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end());
970 :
971 8371863 : bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT) && MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
972 8371863 : if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
973 4020 : i = mySubscriptions.erase(i);
974 4020 : continue;
975 : }
976 : ++i;
977 8367843 : if (s.beginTime > t) {
978 4 : continue;
979 : }
980 8367839 : ++noActive;
981 : }
982 7068019 : mySubscriptionCache.reset();
983 : #ifdef DEBUG_SUBSCRIPTIONS
984 : std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
985 : << "\n Nr. of active subscriptions = " << noActive << std::endl;
986 : #endif
987 7068019 : mySubscriptionCache.writeInt(noActive);
988 : #ifdef DEBUG_SUBSCRIPTIONS
989 : std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
990 : #endif
991 15435862 : for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
992 : const libsumo::Subscription& s = *i;
993 8367843 : if (s.beginTime > t) {
994 : ++i;
995 4 : continue;
996 : }
997 8367839 : tcpip::Storage into;
998 : std::string errors;
999 8367839 : bool ok = processSingleSubscription(s, into, errors);
1000 : #ifdef DEBUG_SUBSCRIPTIONS
1001 : std::cout << " Size of into-store for subscription " << s.id
1002 : << ": " << into.size() << std::endl;
1003 : #endif
1004 8367839 : mySubscriptionCache.writeStorage(into);
1005 8367839 : if (ok) {
1006 : ++i;
1007 : } else {
1008 0 : i = mySubscriptions.erase(i);
1009 : }
1010 8367839 : }
1011 7068019 : myOutputStorage.writeStorage(mySubscriptionCache);
1012 : #ifdef DEBUG_SUBSCRIPTIONS
1013 : std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
1014 : #endif
1015 7068019 : }
1016 :
1017 :
1018 : void
1019 28320 : TraCIServer::sendSingleSimStepResponse() {
1020 : #ifdef DEBUG_MULTI_CLIENTS
1021 : std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
1022 : << " (-> intermediate TraCI step)."
1023 : << "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
1024 : << std::endl;
1025 : #endif
1026 28320 : writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
1027 :
1028 : // NOTE: the commented code would send an empty response
1029 : // myOutputStorage.writeInt(0);
1030 : // myCurrentSocket->second->socket->sendExact(myOutputStorage);
1031 : // myOutputStorage.reset();
1032 28320 : myOutputStorage.writeStorage(mySubscriptionCache);
1033 : // send results to active client
1034 28320 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
1035 28320 : myOutputStorage.reset();
1036 28320 : }
1037 :
1038 :
1039 : void
1040 7113034 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
1041 7113034 : writeStatusCmd(commandId, status, description, myOutputStorage);
1042 7113034 : }
1043 :
1044 :
1045 : void
1046 33148940 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
1047 33148940 : if (status == libsumo::RTYPE_ERR) {
1048 3442 : WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
1049 33147219 : } else if (status == libsumo::RTYPE_NOTIMPLEMENTED) {
1050 156 : WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
1051 : }
1052 33148940 : outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
1053 33148940 : outputStorage.writeUnsignedByte(commandId); // command type
1054 33148940 : outputStorage.writeUnsignedByte(status); // status
1055 33148940 : outputStorage.writeString(description); // description
1056 33148940 : }
1057 :
1058 :
1059 : bool
1060 1017 : TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
1061 1017 : writeStatusCmd(commandId, libsumo::RTYPE_ERR, description, outputStorage);
1062 1017 : return false;
1063 : }
1064 :
1065 :
1066 : void
1067 8527 : TraCIServer::initialiseSubscription(libsumo::Subscription& s) {
1068 8527 : tcpip::Storage writeInto;
1069 : std::string errors;
1070 8527 : libsumo::Subscription* modifiedSubscription = nullptr;
1071 : try {
1072 8527 : if (processSingleSubscription(s, writeInto, errors)) {
1073 7831 : if (s.endTime < MSNet::getInstance()->getCurrentTimeStep()) {
1074 0 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Subscription has ended.");
1075 : } else {
1076 7831 : if (libsumo::Helper::needNewSubscription(s, mySubscriptions, modifiedSubscription)) {
1077 : // Add new subscription to subscription cache (note: seems a bit inefficient)
1078 6711 : if (s.beginTime < MSNet::getInstance()->getCurrentTimeStep()) {
1079 : // copy new subscription into cache
1080 6678 : int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1081 6678 : tcpip::Storage tmp;
1082 6678 : tmp.writeInt(noActive);
1083 56910608 : while (mySubscriptionCache.valid_pos()) {
1084 56903930 : tmp.writeByte(mySubscriptionCache.readByte());
1085 : }
1086 6678 : tmp.writeStorage(writeInto);
1087 6678 : mySubscriptionCache.reset();
1088 6678 : mySubscriptionCache.writeStorage(tmp);
1089 6678 : }
1090 : }
1091 15662 : writeStatusCmd(s.commandId, libsumo::RTYPE_OK, "");
1092 : }
1093 7831 : if (modifiedSubscription != nullptr && (
1094 : modifiedSubscription->isVehicleToVehicleContextSubscription()
1095 : || modifiedSubscription->isVehicleToPersonContextSubscription())) {
1096 : // Set last modified vehicle context subscription active for filter modifications
1097 213 : myLastContextSubscription = modifiedSubscription;
1098 : } else {
1099 : // adding other subscriptions deactivates the activation for filter addition
1100 7618 : myLastContextSubscription = nullptr;
1101 : }
1102 : } else {
1103 6 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Could not add subscription. " + errors);
1104 : }
1105 693 : } catch (libsumo::TraCIException& e) {
1106 693 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, e.what());
1107 693 : }
1108 8527 : myOutputStorage.writeStorage(writeInto);
1109 8527 : }
1110 :
1111 :
1112 : void
1113 1012 : TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1114 : bool found = false;
1115 : std::vector<libsumo::Subscription>::iterator j;
1116 2069 : for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1117 1057 : if (j->id == id && j->commandId == commandId && j->contextDomain == domain) {
1118 1012 : j = mySubscriptions.erase(j);
1119 1012 : if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
1120 : // Remove also reference for filter additions
1121 0 : myLastContextSubscription = nullptr;
1122 : }
1123 : found = true;
1124 1012 : continue;
1125 : }
1126 : ++j;
1127 : }
1128 : // try unsubscribe
1129 1012 : if (found) {
1130 2024 : writeStatusCmd(commandId, libsumo::RTYPE_OK, "");
1131 : } else {
1132 0 : writeStatusCmd(commandId, libsumo::RTYPE_ERR, "The subscription to remove was not found.");
1133 : }
1134 1012 : }
1135 :
1136 :
1137 : bool
1138 8376366 : TraCIServer::processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
1139 : std::string& errors) {
1140 : bool ok = true;
1141 8376366 : tcpip::Storage outputStorage;
1142 8376366 : const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
1143 : std::set<std::string> objIDs;
1144 8376366 : if (s.contextDomain > 0) {
1145 89641 : if ((s.activeFilters & libsumo::SUBS_FILTER_NO_RTREE) == 0) {
1146 87087 : PositionVector shape;
1147 87087 : libsumo::Helper::findObjectShape(s.commandId, s.id, shape);
1148 87087 : libsumo::Helper::collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
1149 87087 : }
1150 88948 : libsumo::Helper::applySubscriptionFilters(s, objIDs);
1151 : } else {
1152 8286725 : objIDs.insert(s.id);
1153 : }
1154 8375673 : const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == libsumo::TRACI_ID_LIST ? 0 : (int)s.variables.size();
1155 : int skipped = 0;
1156 16947423 : for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1157 8571750 : if (s.contextDomain > 0) {
1158 : //if (centralObject(s, *j)) {
1159 : // skipped++;
1160 : // continue;
1161 : //}
1162 285025 : outputStorage.writeString(*j);
1163 : }
1164 8571750 : if (numVars > 0) {
1165 : std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
1166 25398496 : for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1167 16833088 : tcpip::Storage message;
1168 16833088 : message.writeUnsignedByte(*i);
1169 16833088 : message.writeString(*j);
1170 : // TODO check why writeStorage fails here (probably some kind of invalid iterator)
1171 16957666 : for (const auto& v :** k) {
1172 124578 : message.writeChar(v);
1173 : }
1174 16833088 : tcpip::Storage tmpOutput;
1175 16833088 : if (myExecutors.find(getCommandId) != myExecutors.end()) {
1176 16833088 : ok &= myExecutors[getCommandId](*this, message, tmpOutput);
1177 : } else {
1178 0 : writeStatusCmd(s.commandId, libsumo::RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1179 : ok = false;
1180 : }
1181 : // copy response part
1182 16833088 : if (ok) {
1183 16833085 : int length = tmpOutput.readUnsignedByte();
1184 117831595 : while (--length > 0) {
1185 100998510 : tmpOutput.readUnsignedByte();
1186 : }
1187 : int lengthLength = 1;
1188 16833085 : length = tmpOutput.readUnsignedByte();
1189 16833085 : if (length == 0) {
1190 : lengthLength = 5;
1191 24 : length = tmpOutput.readInt();
1192 : }
1193 : //read responseType
1194 16833085 : tmpOutput.readUnsignedByte();
1195 16833085 : int variable = tmpOutput.readUnsignedByte();
1196 16833085 : std::string id = tmpOutput.readString();
1197 16833085 : outputStorage.writeUnsignedByte(variable);
1198 16833085 : outputStorage.writeUnsignedByte(libsumo::RTYPE_OK);
1199 16833085 : length -= (lengthLength + 1 + 4 + (int)id.length());
1200 212664044 : while (--length > 0) {
1201 195830959 : outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
1202 : }
1203 : } else {
1204 : //read length
1205 3 : tmpOutput.readUnsignedByte();
1206 : //read cmd
1207 3 : tmpOutput.readUnsignedByte();
1208 : //read status
1209 3 : tmpOutput.readUnsignedByte();
1210 3 : std::string msg = tmpOutput.readString();
1211 3 : outputStorage.writeUnsignedByte(*i);
1212 3 : outputStorage.writeUnsignedByte(libsumo::RTYPE_ERR);
1213 3 : outputStorage.writeUnsignedByte(libsumo::TYPE_STRING);
1214 3 : outputStorage.writeString(msg);
1215 6 : errors = errors + msg;
1216 : }
1217 16833088 : }
1218 : }
1219 : }
1220 8375673 : int length = (1 + 4) + 1 + (4 + (int)s.id.length()) + 1 + (int)outputStorage.size();
1221 8375673 : if (s.contextDomain > 0) {
1222 88948 : length += 1 + 4; // context domain and number of objects
1223 : }
1224 : // we always write extended command length here for backward compatibility
1225 8375673 : writeInto.writeUnsignedByte(0); // command length -> extended
1226 8375673 : writeInto.writeInt(length);
1227 8375673 : writeInto.writeUnsignedByte(s.commandId + 0x10);
1228 8375673 : writeInto.writeString(s.id);
1229 8375673 : if (s.contextDomain > 0) {
1230 88948 : writeInto.writeUnsignedByte(s.contextDomain);
1231 : }
1232 8375673 : writeInto.writeUnsignedByte(numVars);
1233 8375673 : if (s.contextDomain > 0) {
1234 88948 : writeInto.writeInt((int)objIDs.size() - skipped);
1235 : }
1236 8375673 : if (s.contextDomain == 0 || objIDs.size() != 0) {
1237 8343828 : writeInto.writeStorage(outputStorage);
1238 : }
1239 8375673 : return ok;
1240 8376366 : }
1241 :
1242 :
1243 : bool
1244 9539 : TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1245 9539 : const double beginTime = myInputStorage.readDouble();
1246 9539 : const double endTime = myInputStorage.readDouble();
1247 9539 : const SUMOTime begin = beginTime == libsumo::INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
1248 9539 : const SUMOTime end = endTime == libsumo::INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
1249 9539 : const std::string id = myInputStorage.readString();
1250 9539 : const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1251 9539 : double range = hasContext ? myInputStorage.readDouble() : 0.;
1252 9539 : if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
1253 : range = std::numeric_limits<double>::max();
1254 : }
1255 9539 : const int num = myInputStorage.readUnsignedByte();
1256 : std::vector<int> variables;
1257 : std::vector<std::shared_ptr<tcpip::Storage> > parameters;
1258 23563 : for (int i = 0; i < num; ++i) {
1259 14024 : const int varID = myInputStorage.readUnsignedByte();
1260 14024 : variables.push_back(varID);
1261 14024 : parameters.push_back(std::make_shared<tcpip::Storage>());
1262 14024 : if ((myParameterized.count(std::make_pair(0, varID)) > 0) || (myParameterized.count(std::make_pair(commandId, varID)) > 0)) {
1263 80 : const int parType = myInputStorage.readUnsignedByte();
1264 80 : parameters.back()->writeUnsignedByte(parType);
1265 80 : if (parType == libsumo::TYPE_DOUBLE) {
1266 52 : parameters.back()->writeDouble(myInputStorage.readDouble());
1267 28 : } else if (parType == libsumo::TYPE_STRING) {
1268 56 : parameters.back()->writeString(myInputStorage.readString());
1269 : } else {
1270 : // Error!
1271 : }
1272 : }
1273 : }
1274 : // check subscribe/unsubscribe
1275 9539 : if (variables.empty()) {
1276 1012 : removeSubscription(commandId, id, domain);
1277 : return true;
1278 : }
1279 : // process subscription
1280 8527 : libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
1281 8527 : initialiseSubscription(s);
1282 : return true;
1283 9539 : }
1284 :
1285 :
1286 :
1287 : bool
1288 573 : TraCIServer::addSubscriptionFilter() {
1289 : bool success = true;
1290 : // Read filter type
1291 573 : int filterType = myInputStorage.readUnsignedByte();
1292 :
1293 573 : if (myLastContextSubscription == nullptr) {
1294 3 : writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_ERR,
1295 6 : "No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
1296 3 : return false;
1297 : }
1298 :
1299 : // dispatch according to filter type
1300 570 : switch (filterType) {
1301 0 : case libsumo::FILTER_TYPE_NONE:
1302 : // Remove all filters
1303 0 : removeFilters();
1304 : break;
1305 133 : case libsumo::FILTER_TYPE_LANES: {
1306 : // Read relative lanes to consider for context filter
1307 133 : int nrLanes = (int)myInputStorage.readByte();
1308 : std::vector<int> lanes;
1309 358 : for (int i = 0; i < nrLanes; ++i) {
1310 225 : lanes.push_back((int) myInputStorage.readByte());
1311 : }
1312 266 : addSubscriptionFilterLanes(lanes);
1313 : }
1314 : break;
1315 43 : case libsumo::FILTER_TYPE_NOOPPOSITE:
1316 : // Add no-opposite filter
1317 43 : addSubscriptionFilterNoOpposite();
1318 : break;
1319 154 : case libsumo::FILTER_TYPE_DOWNSTREAM_DIST: {
1320 154 : myInputStorage.readByte(); // read type double
1321 154 : double dist = myInputStorage.readDouble();
1322 154 : addSubscriptionFilterDownstreamDistance(dist);
1323 : }
1324 : break;
1325 130 : case libsumo::FILTER_TYPE_UPSTREAM_DIST: {
1326 130 : myInputStorage.readByte(); // read type double
1327 130 : double dist = myInputStorage.readDouble();
1328 130 : addSubscriptionFilterUpstreamDistance(dist);
1329 : }
1330 : break;
1331 18 : case libsumo::FILTER_TYPE_LEAD_FOLLOW: {
1332 : // Read relative lanes to consider for context filter
1333 18 : addSubscriptionFilterLeadFollow();
1334 : }
1335 : break;
1336 25 : case libsumo::FILTER_TYPE_TURN: {
1337 25 : myInputStorage.readByte(); // read type double
1338 25 : double dist = myInputStorage.readDouble();
1339 25 : addSubscriptionFilterTurn(dist);
1340 : }
1341 : break;
1342 10 : case libsumo::FILTER_TYPE_VCLASS: {
1343 10 : myInputStorage.readByte(); // read type stringlist
1344 10 : SVCPermissions vClasses = parseVehicleClasses(myInputStorage.readStringList());
1345 10 : addSubscriptionFilterVClass(vClasses);
1346 : }
1347 : break;
1348 10 : case libsumo::FILTER_TYPE_VTYPE: {
1349 10 : myInputStorage.readByte(); // read type stringlist
1350 10 : std::vector<std::string> vTypesVector = myInputStorage.readStringList();
1351 : std::set<std::string> vTypesSet;
1352 : vTypesSet.insert(vTypesVector.begin(), vTypesVector.end());
1353 20 : addSubscriptionFilterVType(vTypesSet);
1354 10 : }
1355 : break;
1356 25 : case libsumo::FILTER_TYPE_FIELD_OF_VISION: {
1357 25 : myInputStorage.readByte(); // read type double
1358 25 : double angle = myInputStorage.readDouble();
1359 25 : addSubscriptionFilterFieldOfVision(angle);
1360 : }
1361 : break;
1362 22 : case libsumo::FILTER_TYPE_LATERAL_DIST: {
1363 22 : myInputStorage.readByte(); // read type double
1364 22 : double dist = myInputStorage.readDouble();
1365 22 : addSubscriptionFilterLateralDistance(dist);
1366 : }
1367 : break;
1368 0 : default:
1369 0 : writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_NOTIMPLEMENTED,
1370 0 : "'" + toString(filterType) + "' is no valid filter type code.");
1371 : success = false;
1372 : }
1373 :
1374 : if (success) {
1375 : // acknowledge filter addition
1376 1140 : writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_OK, "");
1377 : }
1378 :
1379 : return success;
1380 : }
1381 :
1382 :
1383 : void
1384 0 : TraCIServer::removeFilters() {
1385 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1386 : std::cout << "Removing filters" << std::endl;
1387 : #endif
1388 0 : myLastContextSubscription->activeFilters = libsumo::SUBS_FILTER_NONE;
1389 0 : }
1390 :
1391 : void
1392 133 : TraCIServer::addSubscriptionFilterLanes(std::vector<int> lanes) {
1393 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1394 : std::cout << "Adding lane filter (lanes=" << toString(lanes) << ")" << std::endl;
1395 : #endif
1396 133 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LANES;
1397 133 : myLastContextSubscription->filterLanes = lanes;
1398 133 : }
1399 :
1400 : void
1401 43 : TraCIServer::addSubscriptionFilterNoOpposite() {
1402 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1403 : std::cout << "Adding no opposite filter" << std::endl;
1404 : #endif
1405 43 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_NOOPPOSITE;
1406 43 : }
1407 :
1408 : void
1409 154 : TraCIServer::addSubscriptionFilterDownstreamDistance(double dist) {
1410 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1411 : std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1412 : #endif
1413 154 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_DOWNSTREAM_DIST;
1414 154 : myLastContextSubscription->filterDownstreamDist = dist;
1415 154 : }
1416 :
1417 : void
1418 130 : TraCIServer::addSubscriptionFilterUpstreamDistance(double dist) {
1419 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1420 : std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1421 : #endif
1422 130 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_UPSTREAM_DIST;
1423 130 : myLastContextSubscription->filterUpstreamDist = dist;
1424 130 : }
1425 :
1426 : void
1427 18 : TraCIServer::addSubscriptionFilterLeadFollow() {
1428 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1429 : std::cout << "Adding Lead/Follow-maneuver filter" << std::endl;
1430 : #endif
1431 18 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LEAD_FOLLOW;
1432 18 : }
1433 :
1434 : void
1435 25 : TraCIServer::addSubscriptionFilterTurn(double dist) {
1436 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1437 : std::cout << "Adding turn-maneuver filter" << std::endl;
1438 : #endif
1439 25 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_TURN;
1440 25 : myLastContextSubscription->filterFoeDistToJunction = dist;
1441 25 : }
1442 :
1443 : void
1444 10 : TraCIServer::addSubscriptionFilterVClass(SVCPermissions vClasses) {
1445 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1446 : std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
1447 : #endif
1448 10 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VCLASS;
1449 10 : myLastContextSubscription->filterVClasses = vClasses;
1450 10 : }
1451 :
1452 : void
1453 10 : TraCIServer::addSubscriptionFilterVType(std::set<std::string> vTypes) {
1454 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1455 : std::cout << "Adding vType filter (vTypes=" << toString(vTypes) << ")" << std::endl;
1456 : #endif
1457 10 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VTYPE;
1458 : myLastContextSubscription->filterVTypes = vTypes;
1459 10 : }
1460 :
1461 : void
1462 25 : TraCIServer::addSubscriptionFilterFieldOfVision(double openingAngle) {
1463 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1464 : std::cout << "Adding FieldOfVision filter (openingAngle=" << toString(openingAngle) << ")" << std::endl;
1465 : #endif
1466 25 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_FIELD_OF_VISION;
1467 25 : myLastContextSubscription->filterFieldOfVisionOpeningAngle = openingAngle;
1468 25 : }
1469 :
1470 : void
1471 22 : TraCIServer::addSubscriptionFilterLateralDistance(double dist) {
1472 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1473 : std::cout << "Adding lateral dist filter (dist=" << toString(dist) << ")" << std::endl;
1474 : #endif
1475 22 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LATERAL_DIST;
1476 22 : myLastContextSubscription->filterLateralDist = dist;
1477 22 : }
1478 :
1479 : void
1480 25830492 : TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
1481 25830492 : if (tempMsg.size() < 254) {
1482 25794812 : outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1483 : } else {
1484 35680 : outputStorage.writeUnsignedByte(0); // command length -> extended
1485 35680 : outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1486 : }
1487 25830492 : outputStorage.writeStorage(tempMsg);
1488 25830492 : }
1489 :
1490 :
1491 : void
1492 0 : TraCIServer::writePositionVector(tcpip::Storage& outputStorage, const libsumo::TraCIPositionVector& shape) {
1493 0 : outputStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
1494 0 : if (shape.value.size() < 256) {
1495 0 : outputStorage.writeUnsignedByte((int)shape.value.size());
1496 : } else {
1497 0 : outputStorage.writeUnsignedByte(0);
1498 0 : outputStorage.writeInt((int)shape.value.size());
1499 : }
1500 0 : for (const libsumo::TraCIPosition& pos : shape.value) {
1501 0 : outputStorage.writeDouble(pos.x);
1502 0 : outputStorage.writeDouble(pos.y);
1503 : }
1504 0 : }
1505 :
1506 :
1507 : bool
1508 133320 : TraCIServer::readTypeCheckingInt(tcpip::Storage& inputStorage, int& into) {
1509 133320 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_INTEGER) {
1510 : return false;
1511 : }
1512 133316 : into = inputStorage.readInt();
1513 133316 : return true;
1514 : }
1515 :
1516 :
1517 : bool
1518 433531 : TraCIServer::readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into) {
1519 433531 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLE) {
1520 : return false;
1521 : }
1522 433530 : into = inputStorage.readDouble();
1523 433530 : return true;
1524 : }
1525 :
1526 :
1527 : bool
1528 548892 : TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1529 548892 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRING) {
1530 : return false;
1531 : }
1532 548889 : into = inputStorage.readString();
1533 548889 : return true;
1534 : }
1535 :
1536 :
1537 : bool
1538 622 : TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1539 622 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRINGLIST) {
1540 : return false;
1541 : }
1542 622 : into = inputStorage.readStringList();
1543 622 : return true;
1544 : }
1545 :
1546 :
1547 : bool
1548 280 : TraCIServer::readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into) {
1549 280 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLELIST) {
1550 : return false;
1551 : }
1552 280 : into = inputStorage.readDoubleList();
1553 280 : return true;
1554 : }
1555 :
1556 :
1557 : bool
1558 459 : TraCIServer::readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into) {
1559 459 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_COLOR) {
1560 : return false;
1561 : }
1562 457 : into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1563 457 : into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1564 457 : into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1565 457 : into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1566 457 : return true;
1567 : }
1568 :
1569 :
1570 : bool
1571 216 : TraCIServer::readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into) {
1572 216 : if (inputStorage.readUnsignedByte() != libsumo::POSITION_2D) {
1573 : return false;
1574 : }
1575 215 : into.x = inputStorage.readDouble();
1576 215 : into.y = inputStorage.readDouble();
1577 215 : into.z = 0;
1578 215 : return true;
1579 : }
1580 :
1581 :
1582 : bool
1583 200087 : TraCIServer::readTypeCheckingByte(tcpip::Storage& inputStorage, int& into) {
1584 200087 : if (inputStorage.readByte() != libsumo::TYPE_BYTE) {
1585 : return false;
1586 : }
1587 200087 : into = inputStorage.readByte();
1588 200087 : return true;
1589 : }
1590 :
1591 :
1592 : bool
1593 4263 : TraCIServer::readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into) {
1594 4263 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_UBYTE) {
1595 : return false;
1596 : }
1597 4263 : into = inputStorage.readUnsignedByte();
1598 4263 : return true;
1599 : }
1600 :
1601 :
1602 : bool
1603 147 : TraCIServer::readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into) {
1604 147 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_POLYGON) {
1605 : return false;
1606 : }
1607 146 : into.clear();
1608 146 : int size = inputStorage.readUnsignedByte();
1609 146 : if (size == 0) {
1610 4 : size = inputStorage.readInt();
1611 : }
1612 146 : PositionVector shape;
1613 1821 : for (int i = 0; i < size; ++i) {
1614 1679 : double x = inputStorage.readDouble();
1615 1679 : double y = inputStorage.readDouble();
1616 1679 : if (std::isnan(x) || std::isnan(y)) {
1617 8 : throw libsumo::TraCIException("NaN-Value in shape.");
1618 : }
1619 1675 : into.push_back(Position(x, y));
1620 : }
1621 : return true;
1622 146 : }
1623 :
1624 :
1625 : void
1626 179 : TraCIServer::stateLoaded(SUMOTime targetTime) {
1627 179 : myTargetTime = targetTime;
1628 358 : for (auto& s : mySockets) {
1629 179 : s.second->targetTime = targetTime;
1630 179 : s.second->executeMove = false;
1631 2506 : for (auto& stateChange : s.second->vehicleStateChanges) {
1632 : stateChange.second.clear();
1633 : }
1634 895 : for (auto& stateChange : s.second->transportableStateChanges) {
1635 : stateChange.second.clear();
1636 : }
1637 : }
1638 : mySubscriptions.clear();
1639 179 : mySubscriptionCache.reset();
1640 179 : }
1641 :
1642 :
1643 : bool
1644 0 : TraCIServer::centralObject(const libsumo::Subscription& s, const std::string& objID) {
1645 0 : return (s.id == objID && s.commandId + 32 == s.contextDomain);
1646 : }
1647 :
1648 :
1649 : /****************************************************************************/
|