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 18084621 : TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
113 18084621 : myWrapperStorage.reset();
114 18084621 : myWrapperStorage.writeUnsignedByte(domainID);
115 18084621 : myWrapperStorage.writeUnsignedByte(variable);
116 18084621 : myWrapperStorage.writeString(objID);
117 18084621 : }
118 :
119 :
120 : bool
121 4427876 : TraCIServer::wrapDouble(const std::string& /* objID */, const int /* variable */, const double value) {
122 4427876 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
123 4427876 : myWrapperStorage.writeDouble(value);
124 4427876 : return true;
125 : }
126 :
127 :
128 : bool
129 8200008 : TraCIServer::wrapInt(const std::string& /* objID */, const int /* variable */, const int value) {
130 8200008 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_INTEGER);
131 8200008 : myWrapperStorage.writeInt(value);
132 8200008 : return true;
133 : }
134 :
135 :
136 : bool
137 4191656 : TraCIServer::wrapString(const std::string& /* objID */, const int /* variable */, const std::string& value) {
138 4191656 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
139 4191656 : myWrapperStorage.writeString(value);
140 4191656 : return true;
141 : }
142 :
143 :
144 : bool
145 178837 : TraCIServer::wrapStringList(const std::string& /* objID */, const int /* variable */, const std::vector<std::string>& value) {
146 178837 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRINGLIST);
147 178837 : myWrapperStorage.writeStringList(value);
148 178837 : return true;
149 : }
150 :
151 :
152 : bool
153 6 : TraCIServer::wrapDoubleList(const std::string& /* objID */, const int /* variable */, const std::vector<double>& value) {
154 6 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLELIST);
155 6 : myWrapperStorage.writeDoubleList(value);
156 6 : return true;
157 : }
158 :
159 :
160 : bool
161 908437 : TraCIServer::wrapPosition(const std::string& /* objID */, const int variable, const libsumo::TraCIPosition& value) {
162 : const bool includeZ = variable == libsumo::VAR_POSITION3D;
163 1815642 : myWrapperStorage.writeUnsignedByte(includeZ ? libsumo::POSITION_3D : libsumo::POSITION_2D);
164 908437 : myWrapperStorage.writeDouble(value.x);
165 908437 : myWrapperStorage.writeDouble(value.y);
166 908437 : if (includeZ) {
167 1232 : myWrapperStorage.writeDouble(value.z);
168 : }
169 908437 : return true;
170 : }
171 :
172 :
173 : bool
174 12105 : TraCIServer::wrapPositionVector(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIPositionVector& shape) {
175 12105 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_POLYGON);
176 12105 : if (shape.value.size() < 256) {
177 12102 : myWrapperStorage.writeUnsignedByte((int)shape.value.size());
178 : } else {
179 3 : myWrapperStorage.writeUnsignedByte(0);
180 3 : myWrapperStorage.writeInt((int)shape.value.size());
181 : }
182 43290 : for (const libsumo::TraCIPosition& pos : shape.value) {
183 31185 : myWrapperStorage.writeDouble(pos.x);
184 31185 : myWrapperStorage.writeDouble(pos.y);
185 : }
186 12105 : return true;
187 : }
188 :
189 :
190 : bool
191 710 : TraCIServer::wrapColor(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIColor& value) {
192 710 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COLOR);
193 710 : myWrapperStorage.writeUnsignedByte(value.r);
194 710 : myWrapperStorage.writeUnsignedByte(value.g);
195 710 : myWrapperStorage.writeUnsignedByte(value.b);
196 710 : myWrapperStorage.writeUnsignedByte(value.a);
197 710 : return true;
198 : }
199 :
200 :
201 : bool
202 22393 : TraCIServer::wrapStringDoublePair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, double>& value) {
203 22393 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
204 22393 : myWrapperStorage.writeInt(2);
205 22393 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
206 22393 : myWrapperStorage.writeString(value.first);
207 22393 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_DOUBLE);
208 22393 : myWrapperStorage.writeDouble(value.second);
209 22393 : return true;
210 : }
211 :
212 :
213 : bool
214 92 : TraCIServer::wrapStringPair(const std::string& /* objID */, const int /* variable */, const std::pair<std::string, std::string>& value) {
215 92 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_COMPOUND);
216 92 : myWrapperStorage.writeInt(2);
217 92 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
218 92 : myWrapperStorage.writeString(value.first);
219 92 : myWrapperStorage.writeUnsignedByte(libsumo::TYPE_STRING);
220 92 : myWrapperStorage.writeString(value.second);
221 92 : return true;
222 : }
223 :
224 :
225 : tcpip::Storage&
226 18607701 : TraCIServer::getWrapperStorage() {
227 18607701 : return myWrapperStorage;
228 : }
229 :
230 :
231 :
232 2479 : TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
233 2479 : : 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 2479 : myVehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
238 2479 : myVehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
239 2479 : myVehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
240 2479 : myVehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
241 2479 : myVehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
242 2479 : myVehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
243 2479 : myVehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
244 2479 : myVehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
245 2479 : myVehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
246 2479 : myVehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
247 2479 : myVehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
248 2479 : myVehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
249 2479 : myVehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
250 :
251 2479 : myTransportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
252 2479 : myTransportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
253 2479 : myTransportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
254 2479 : myTransportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
255 :
256 2479 : myExecutors[libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processGet;
257 2479 : myExecutors[libsumo::CMD_SET_INDUCTIONLOOP_VARIABLE] = &TraCIServerAPI_InductionLoop::processSet;
258 2479 : myExecutors[libsumo::CMD_GET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processGet;
259 2479 : myExecutors[libsumo::CMD_SET_LANEAREA_VARIABLE] = &TraCIServerAPI_LaneArea::processSet;
260 2479 : myExecutors[libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processGet;
261 2479 : myExecutors[libsumo::CMD_SET_MULTIENTRYEXIT_VARIABLE] = &TraCIServerAPI_MultiEntryExit::processSet;
262 :
263 2479 : myExecutors[libsumo::CMD_GET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processGet;
264 2479 : myExecutors[libsumo::CMD_SET_TL_VARIABLE] = &TraCIServerAPI_TrafficLight::processSet;
265 2479 : myExecutors[libsumo::CMD_GET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processGet;
266 2479 : myExecutors[libsumo::CMD_SET_LANE_VARIABLE] = &TraCIServerAPI_Lane::processSet;
267 2479 : myExecutors[libsumo::CMD_GET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processGet;
268 2479 : myExecutors[libsumo::CMD_SET_VEHICLE_VARIABLE] = &TraCIServerAPI_Vehicle::processSet;
269 2479 : myExecutors[libsumo::CMD_GET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processGet;
270 2479 : myExecutors[libsumo::CMD_SET_VEHICLETYPE_VARIABLE] = &TraCIServerAPI_VehicleType::processSet;
271 2479 : myExecutors[libsumo::CMD_GET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processGet;
272 2479 : myExecutors[libsumo::CMD_SET_ROUTE_VARIABLE] = &TraCIServerAPI_Route::processSet;
273 2479 : myExecutors[libsumo::CMD_GET_POI_VARIABLE] = &TraCIServerAPI_POI::processGet;
274 2479 : myExecutors[libsumo::CMD_SET_POI_VARIABLE] = &TraCIServerAPI_POI::processSet;
275 2479 : myExecutors[libsumo::CMD_GET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processGet;
276 2479 : myExecutors[libsumo::CMD_SET_POLYGON_VARIABLE] = &TraCIServerAPI_Polygon::processSet;
277 2479 : myExecutors[libsumo::CMD_GET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processGet;
278 2479 : myExecutors[libsumo::CMD_SET_JUNCTION_VARIABLE] = &TraCIServerAPI_Junction::processSet;
279 2479 : myExecutors[libsumo::CMD_GET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processGet;
280 2479 : myExecutors[libsumo::CMD_SET_EDGE_VARIABLE] = &TraCIServerAPI_Edge::processSet;
281 2479 : myExecutors[libsumo::CMD_GET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processGet;
282 2479 : myExecutors[libsumo::CMD_SET_SIM_VARIABLE] = &TraCIServerAPI_Simulation::processSet;
283 2479 : myExecutors[libsumo::CMD_GET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processGet;
284 2479 : myExecutors[libsumo::CMD_SET_PERSON_VARIABLE] = &TraCIServerAPI_Person::processSet;
285 2479 : myExecutors[libsumo::CMD_GET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processGet;
286 2479 : myExecutors[libsumo::CMD_SET_CALIBRATOR_VARIABLE] = &TraCIServerAPI_Calibrator::processSet;
287 2479 : myExecutors[libsumo::CMD_GET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processGet;
288 2479 : myExecutors[libsumo::CMD_SET_BUSSTOP_VARIABLE] = &TraCIServerAPI_BusStop::processSet;
289 2479 : myExecutors[libsumo::CMD_GET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processGet;
290 2479 : myExecutors[libsumo::CMD_SET_PARKINGAREA_VARIABLE] = &TraCIServerAPI_ParkingArea::processSet;
291 2479 : myExecutors[libsumo::CMD_GET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processGet;
292 2479 : myExecutors[libsumo::CMD_SET_CHARGINGSTATION_VARIABLE] = &TraCIServerAPI_ChargingStation::processSet;
293 2479 : myExecutors[libsumo::CMD_GET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processGet;
294 2479 : myExecutors[libsumo::CMD_SET_ROUTEPROBE_VARIABLE] = &TraCIServerAPI_RouteProbe::processSet;
295 2479 : myExecutors[libsumo::CMD_GET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processGet;
296 2479 : myExecutors[libsumo::CMD_SET_REROUTER_VARIABLE] = &TraCIServerAPI_Rerouter::processSet;
297 2479 : myExecutors[libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processGet;
298 2479 : myExecutors[libsumo::CMD_SET_VARIABLESPEEDSIGN_VARIABLE] = &TraCIServerAPI_VariableSpeedSign::processSet;
299 2479 : myExecutors[libsumo::CMD_GET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processGet;
300 : //myExecutors[libsumo::CMD_SET_MEANDATA_VARIABLE] = &TraCIServerAPI_MeanData::processSet;
301 2479 : myExecutors[libsumo::CMD_GET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processGet;
302 2479 : myExecutors[libsumo::CMD_SET_OVERHEADWIRE_VARIABLE] = &TraCIServerAPI_OverheadWire::processSet;
303 :
304 2479 : myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_LEADER));
305 2479 : myParameterized.insert(std::make_pair(libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE, libsumo::VAR_FOLLOWER));
306 2479 : myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER));
307 2479 : myParameterized.insert(std::make_pair(0, libsumo::VAR_PARAMETER_WITH_KEY));
308 :
309 2479 : 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 2479 : if (!MSGlobals::gUsingInternalLanes && !MSGlobals::gUseMesoSim) {
314 2 : WRITE_WARNING(TL("Starting TraCI without using internal lanes!"));
315 2 : MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
316 12 : MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
317 : }
318 :
319 : try {
320 4958 : WRITE_MESSAGEF(TL("***Starting server on port % ***"), toString(port));
321 2479 : tcpip::Socket serverSocket(port);
322 2479 : if (numClients > 1) {
323 156 : WRITE_MESSAGEF(TL(" waiting for % clients..."), toString(numClients));
324 : }
325 5120 : while ((int)mySockets.size() < numClients) {
326 2645 : int index = (int)mySockets.size() + libsumo::MAX_ORDER + 1;
327 2645 : mySockets[index] = new SocketInfo(serverSocket.accept(true), begin);
328 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::BUILT] = std::vector<std::string>();
329 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::DEPARTED] = std::vector<std::string>();
330 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_TELEPORT] = std::vector<std::string>();
331 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_TELEPORT] = std::vector<std::string>();
332 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ARRIVED] = std::vector<std::string>();
333 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::NEWROUTE] = std::vector<std::string>();
334 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_PARKING] = std::vector<std::string>();
335 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::MANEUVERING] = std::vector<std::string>();
336 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_PARKING] = std::vector<std::string>();
337 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::STARTING_STOP] = std::vector<std::string>();
338 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::ENDING_STOP] = std::vector<std::string>();
339 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::COLLISION] = std::vector<std::string>();
340 2641 : mySockets[index]->vehicleStateChanges[MSNet::VehicleState::EMERGENCYSTOP] = std::vector<std::string>();
341 :
342 2641 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_DEPARTED] = std::vector<std::string>();
343 2641 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::PERSON_ARRIVED] = std::vector<std::string>();
344 2641 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_DEPARTED] = std::vector<std::string>();
345 2641 : mySockets[index]->transportableStateChanges[MSNet::TransportableState::CONTAINER_ARRIVED] = std::vector<std::string>();
346 2641 : if (numClients > 1) {
347 488 : WRITE_MESSAGE(TL(" client connected"));
348 : }
349 : }
350 : // When got here, all clients have connected
351 2475 : if (numClients > 1) {
352 78 : checkClientOrdering();
353 : }
354 : // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommands()
355 2471 : myCurrentSocket = mySockets.begin();
356 2487 : } catch (tcpip::SocketException& e) {
357 8 : throw ProcessError(e.what());
358 4 : }
359 2519 : }
360 :
361 :
362 4942 : TraCIServer::~TraCIServer() {
363 2502 : for (const auto& socket : mySockets) {
364 31 : 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 7413 : }
368 :
369 :
370 : // ---------- Initialisation and Shutdown
371 : void
372 43013 : TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
373 126534 : if (myInstance == nullptr && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0)) {
374 7429 : myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
375 2479 : OptionsCont::getOptions().getInt("remote-port"),
376 9924 : OptionsCont::getOptions().getInt("num-clients"));
377 2657 : for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
378 186 : myInstance->myExecutors[i->first] = i->second;
379 : }
380 : }
381 43005 : if (myInstance != nullptr) {
382 : // maybe net was deleted and built again
383 2484 : MSNet::getInstance()->addVehicleStateListener(myInstance);
384 2484 : MSNet::getInstance()->addTransportableStateListener(myInstance);
385 2484 : myInstance->mySubscriptionCache.writeInt(0);
386 : }
387 43005 : }
388 :
389 :
390 : void
391 42589 : TraCIServer::close() {
392 42589 : if (myInstance == nullptr) {
393 : return;
394 : }
395 2471 : delete myInstance;
396 2471 : myInstance = nullptr;
397 2471 : myDoCloseConnection = true;
398 : }
399 :
400 :
401 : bool
402 101087013 : TraCIServer::wasClosed() {
403 101087013 : return myDoCloseConnection;
404 : }
405 :
406 :
407 : // ---------- Initialisation and Shutdown
408 :
409 :
410 : void
411 88203 : TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
412 88203 : if (!myDoCloseConnection) {
413 88203 : myVehicleStateChanges[to].push_back(vehicle->getID());
414 185436 : for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
415 97233 : i->second->vehicleStateChanges[to].push_back(vehicle->getID());
416 : }
417 : }
418 88203 : }
419 :
420 :
421 : void
422 1686 : TraCIServer::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& /*info*/) {
423 1686 : if (!myDoCloseConnection) {
424 1686 : myTransportableStateChanges[to].push_back(transportable->getID());
425 3372 : for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
426 1686 : i->second->transportableStateChanges[to].push_back(transportable->getID());
427 : }
428 : }
429 1686 : }
430 :
431 :
432 : void
433 78 : 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 78 : myCurrentSocket = mySockets.begin();
440 316 : 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 482 : myInputStorage.reset();
447 482 : myCurrentSocket->second->socket->receiveExact(myInputStorage);
448 : int commandStart, commandLength;
449 482 : 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 482 : bool initCommand = commandId == libsumo::CMD_SETORDER || commandId == libsumo::CMD_GETVERSION;
456 482 : 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 478 : tcpip::Storage tmp;
464 478 : tmp.writeStorage(myInputStorage);
465 478 : 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 718 : myInputStorage.writeUnsignedByte(commandId == libsumo::CMD_SETORDER ? 6 : 2);
469 478 : myInputStorage.writeUnsignedByte(commandId);
470 478 : myInputStorage.writeStorage(tmp);
471 :
472 : // Handle initialization command completely
473 478 : dispatchCommand();
474 478 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
475 478 : myOutputStorage.reset();
476 478 : } else {
477 : #ifdef DEBUG_MULTI_CLIENTS
478 : std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
479 : #endif
480 8 : throw ProcessError(TL("Execution order (libsumo::CMD_SETORDER) was not set for all TraCI clients in pre-execution phase."));
481 : }
482 478 : if (commandId == libsumo::CMD_SETORDER) {
483 : // This is what we have waited for.
484 : break;
485 : }
486 240 : }
487 : ++myCurrentSocket;
488 : }
489 74 : }
490 :
491 :
492 : void
493 8402797 : TraCIServer::processReorderingRequests() {
494 : // Process reordering requests
495 8402797 : 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 320 : while (i != mySocketReorderRequests.end()) {
511 : j = mySockets.begin();
512 573 : while (j != mySockets.end()) {
513 573 : 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 241 : 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 8402797 : }
534 :
535 :
536 : SUMOTime
537 16761791 : 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 33630220 : 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 16868429 : targetTime = MIN2(targetTime, i->second->targetTime);
551 : }
552 : #ifdef DEBUG_MULTI_CLIENTS
553 : std::cout << std::endl;
554 : #endif
555 16761791 : 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 8400312 : 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 16834764 : while (i != mySockets.end()) {
567 8434452 : if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
568 : // this client will become active before the next SUMO step. Provide subscription results.
569 8360481 : 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 8400312 : }
580 :
581 :
582 : int
583 8402797 : 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 8402797 : processReorderingRequests();
592 8402797 : 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 8400312 : 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 8400312 : sendOutputToAll();
598 8400312 : myOutputStorage.reset();
599 : }
600 :
601 : // determine minimal next target time among clients
602 8402797 : myTargetTime = nextTargetTime();
603 :
604 8402797 : 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 16701412 : 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 8361472 : myCurrentSocket = mySockets.begin();
622 16795417 : 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 8433970 : 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 51960 : continue;
637 : }
638 : finalCmd = 0;
639 26517926 : while (finalCmd == 0) {
640 18135941 : if (!myInputStorage.valid_pos()) {
641 : // have read request completely, send response if adequate
642 18135941 : if (myOutputStorage.size() > 0) {
643 : // send response to previous query
644 9753937 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
645 9753937 : 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 18135941 : myInputStorage.reset();
652 18135941 : myCurrentSocket->second->socket->receiveExact(myInputStorage);
653 : }
654 :
655 36271832 : while (myInputStorage.valid_pos() && !myDoCloseConnection) {
656 18135916 : const int cmd = dispatchCommand();
657 18135916 : 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 8361447 : if (!myLoadArgs.empty()) {
664 : #ifdef DEBUG_MULTI_CLIENTS
665 : std::cout << " Breaking loop to load new simulation." << std::endl;
666 : #endif
667 : break;
668 8361434 : } 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 8358994 : 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 8358994 : myTargetTime = nextT;
682 : }
683 : // All clients are done with the current time step
684 : // Reset myVehicleStateChanges and myTransportableStateChanges
685 116793502 : for (auto& item : myVehicleStateChanges) {
686 : item.second.clear();
687 : }
688 41711965 : for (auto& item : myTransportableStateChanges) {
689 : item.second.clear();
690 : }
691 : return finalCmd;
692 25 : } catch (std::invalid_argument& e) {
693 0 : throw ProcessError(e.what());
694 0 : } catch (libsumo::TraCIException& e) {
695 0 : throw ProcessError(e.what());
696 25 : } catch (tcpip::SocketException& e) {
697 50 : throw ProcessError(e.what());
698 25 : }
699 : }
700 :
701 :
702 : void
703 2480 : TraCIServer::cleanup() {
704 : mySubscriptions.clear();
705 4960 : myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
706 2520 : for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
707 40 : myCurrentSocket->second->targetTime = myTargetTime;
708 40 : myCurrentSocket->second->executeMove = false;
709 : }
710 2480 : myOutputStorage.reset();
711 2480 : myInputStorage.reset();
712 2480 : mySubscriptionCache.reset();
713 34720 : for (auto& i : myVehicleStateChanges) {
714 : i.second.clear();
715 : }
716 12400 : for (auto& i : myTransportableStateChanges) {
717 : i.second.clear();
718 : }
719 2480 : myCurrentSocket = mySockets.begin();
720 2480 : }
721 :
722 :
723 : std::map<int, TraCIServer::SocketInfo*>::iterator
724 2602 : TraCIServer::removeCurrentSocket() {
725 : #ifdef DEBUG_MULTI_CLIENTS
726 : std::cout << " Removing socket " << myCurrentSocket->second->socket
727 : << " (order " << myCurrentSocket->first << ")" << std::endl;
728 : #endif
729 2602 : delete myCurrentSocket->second;
730 2602 : myCurrentSocket = mySockets.erase(myCurrentSocket);
731 2602 : return myCurrentSocket;
732 : }
733 :
734 :
735 : int
736 18136876 : TraCIServer::readCommandID(int& commandStart, int& commandLength) {
737 18136876 : commandStart = myInputStorage.position();
738 18136876 : commandLength = myInputStorage.readUnsignedByte();
739 18136876 : if (commandLength == 0) {
740 48661 : 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 18136876 : return myInputStorage.readUnsignedByte();
750 : }
751 :
752 :
753 : int
754 18136394 : TraCIServer::dispatchCommand() {
755 : int commandStart, commandLength;
756 18136394 : 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 18136394 : if (myExecutors.find(commandId) != myExecutors.end()) {
764 9744641 : success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
765 : } else {
766 8391753 : switch (commandId) {
767 2020 : case libsumo::CMD_GETVERSION:
768 2020 : success = commandGetVersion();
769 : break;
770 : case libsumo::CMD_LOAD: {
771 : std::vector<std::string> args;
772 13 : 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 13 : myLoadArgs = args;
781 : success = true;
782 26 : 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 13 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
786 13 : myCurrentSocket = mySockets.end();
787 13 : myOutputStorage.reset();
788 0 : } catch (libsumo::TraCIException& e) {
789 0 : return writeErrorStatusCmd(libsumo::CMD_LOAD, e.what(), myOutputStorage);
790 0 : }
791 : break;
792 13 : }
793 6 : case libsumo::CMD_EXECUTEMOVE:
794 6 : myCurrentSocket->second->executeMove = true;
795 : myCurrentSocket++;
796 : success = true;
797 12 : writeStatusCmd(libsumo::CMD_EXECUTEMOVE, libsumo::RTYPE_OK, "");
798 : break;
799 8379364 : case libsumo::CMD_SIMSTEP: {
800 8379364 : const double nextT = myInputStorage.readDouble();
801 8379364 : if (nextT == 0.) {
802 8333498 : myCurrentSocket->second->targetTime += DELTA_T;
803 : } else {
804 45866 : myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
805 : }
806 8379364 : 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 8379364 : 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 18882 : 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 117311096 : for (auto& item : myCurrentSocket->second->vehicleStateChanges) {
821 : item.second.clear();
822 : }
823 41896820 : for (auto& item : myCurrentSocket->second->transportableStateChanges) {
824 : item.second.clear();
825 : }
826 : myCurrentSocket++;
827 8379364 : return commandId;
828 : }
829 : case libsumo::CMD_CLOSE:
830 5204 : writeStatusCmd(libsumo::CMD_CLOSE, libsumo::RTYPE_OK, "");
831 2602 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
832 2602 : myOutputStorage.reset();
833 2602 : if (mySockets.size() == 1) {
834 : // Last client has closed connection
835 2440 : myDoCloseConnection = true;
836 : }
837 : // remove current socket and increment to next socket in ordering
838 2602 : myCurrentSocket = removeCurrentSocket();
839 : success = true;
840 : break;
841 244 : case libsumo::CMD_SETORDER: {
842 244 : 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 244 : 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 244 : mySocketReorderRequests[order] = myCurrentSocket->second;
855 : success = true;
856 244 : writeStatusCmd(libsumo::CMD_SETORDER, libsumo::RTYPE_OK, "");
857 244 : break;
858 : }
859 3652 : 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 3652 : success = addObjectVariableSubscription(commandId, false);
884 : break;
885 3364 : 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 3364 : success = addObjectVariableSubscription(commandId, true);
910 : break;
911 387 : case libsumo::CMD_ADD_SUBSCRIPTION_FILTER:
912 387 : success = addSubscriptionFilter();
913 : break;
914 101 : default:
915 101 : if (commandId == libsumo::CMD_GET_GUI_VARIABLE || commandId == libsumo::CMD_SET_GUI_VARIABLE) {
916 200 : 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 9754165 : if (!success) {
923 2100 : while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
924 1148 : myInputStorage.readChar();
925 : }
926 : }
927 9757030 : 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 9757030 : return commandId;
936 : }
937 :
938 :
939 : // ---------- Server-internal command handling
940 : bool
941 2020 : TraCIServer::commandGetVersion() {
942 : // Prepare response
943 2020 : tcpip::Storage answerTmp;
944 2020 : answerTmp.writeInt(libsumo::TRACI_VERSION);
945 2020 : answerTmp.writeString("SUMO " VERSION_STRING);
946 : // When we get here, the response is stored in answerTmp -> put into myOutputStorage
947 2020 : writeStatusCmd(libsumo::CMD_GETVERSION, libsumo::RTYPE_OK, "");
948 : // command length
949 2020 : myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
950 : // command type
951 2020 : myOutputStorage.writeUnsignedByte(libsumo::CMD_GETVERSION);
952 : // and the parameter dependant part
953 2020 : myOutputStorage.writeStorage(answerTmp);
954 2020 : return true;
955 2020 : }
956 :
957 :
958 : void
959 8400312 : TraCIServer::postProcessSimulationStep() {
960 8400312 : SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
961 : #ifdef DEBUG_MULTI_CLIENTS
962 : std::cout << " postProcessSimulationStep() at time=" << t << std::endl;
963 : #endif
964 16800624 : writeStatusCmd(libsumo::CMD_SIMSTEP, libsumo::RTYPE_OK, "");
965 : int noActive = 0;
966 12589732 : for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
967 : const libsumo::Subscription& s = *i;
968 4189420 : bool isArrivedVehicle = (s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT)
969 4189420 : && (find(myVehicleStateChanges[MSNet::VehicleState::ARRIVED].begin(), myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end(), s.id) != myVehicleStateChanges[MSNet::VehicleState::ARRIVED].end());
970 :
971 4189420 : bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT) && MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
972 4189420 : if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
973 2042 : i = mySubscriptions.erase(i);
974 2042 : continue;
975 : }
976 : ++i;
977 4187378 : if (s.beginTime > t) {
978 4 : continue;
979 : }
980 4187374 : ++noActive;
981 : }
982 8400312 : 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 8400312 : mySubscriptionCache.writeInt(noActive);
988 : #ifdef DEBUG_SUBSCRIPTIONS
989 : std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
990 : #endif
991 12587690 : for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
992 : const libsumo::Subscription& s = *i;
993 4187378 : if (s.beginTime > t) {
994 : ++i;
995 4 : continue;
996 : }
997 4187374 : tcpip::Storage into;
998 : std::string errors;
999 4187374 : 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 4187374 : mySubscriptionCache.writeStorage(into);
1005 4187374 : if (ok) {
1006 : ++i;
1007 : } else {
1008 0 : i = mySubscriptions.erase(i);
1009 : }
1010 4187374 : }
1011 8400312 : myOutputStorage.writeStorage(mySubscriptionCache);
1012 : #ifdef DEBUG_SUBSCRIPTIONS
1013 : std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
1014 : #endif
1015 8400312 : }
1016 :
1017 :
1018 : void
1019 18882 : 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 18882 : 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 18882 : myOutputStorage.writeStorage(mySubscriptionCache);
1033 : // send results to active client
1034 18882 : myCurrentSocket->second->socket->sendExact(myOutputStorage);
1035 18882 : myOutputStorage.reset();
1036 18882 : }
1037 :
1038 :
1039 : void
1040 8431588 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
1041 8431588 : writeStatusCmd(commandId, status, description, myOutputStorage);
1042 8431588 : }
1043 :
1044 :
1045 : void
1046 26624816 : TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
1047 26624816 : if (status == libsumo::RTYPE_ERR) {
1048 5277 : WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
1049 26623057 : } else if (status == libsumo::RTYPE_NOTIMPLEMENTED) {
1050 303 : WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
1051 : }
1052 26624816 : outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
1053 26624816 : outputStorage.writeUnsignedByte(commandId); // command type
1054 26624816 : outputStorage.writeUnsignedByte(status); // status
1055 26624816 : outputStorage.writeString(description); // description
1056 26624816 : }
1057 :
1058 :
1059 : bool
1060 847 : TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
1061 847 : writeStatusCmd(commandId, libsumo::RTYPE_ERR, description, outputStorage);
1062 847 : return false;
1063 : }
1064 :
1065 :
1066 : void
1067 5821 : TraCIServer::initialiseSubscription(libsumo::Subscription& s) {
1068 5821 : tcpip::Storage writeInto;
1069 : std::string errors;
1070 5821 : libsumo::Subscription* modifiedSubscription = nullptr;
1071 : try {
1072 5821 : if (processSingleSubscription(s, writeInto, errors)) {
1073 4916 : if (s.endTime < MSNet::getInstance()->getCurrentTimeStep()) {
1074 0 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Subscription has ended.");
1075 : } else {
1076 4916 : if (libsumo::Helper::needNewSubscription(s, mySubscriptions, modifiedSubscription)) {
1077 : // Add new subscription to subscription cache (note: seems a bit inefficient)
1078 4145 : if (s.beginTime < MSNet::getInstance()->getCurrentTimeStep()) {
1079 : // copy new subscription into cache
1080 4123 : int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1081 4123 : tcpip::Storage tmp;
1082 4123 : tmp.writeInt(noActive);
1083 28518371 : while (mySubscriptionCache.valid_pos()) {
1084 28514248 : tmp.writeByte(mySubscriptionCache.readByte());
1085 : }
1086 4123 : tmp.writeStorage(writeInto);
1087 4123 : mySubscriptionCache.reset();
1088 4123 : mySubscriptionCache.writeStorage(tmp);
1089 4123 : }
1090 : }
1091 9832 : writeStatusCmd(s.commandId, libsumo::RTYPE_OK, "");
1092 : }
1093 4916 : if (modifiedSubscription != nullptr && (
1094 : modifiedSubscription->isVehicleToVehicleContextSubscription()
1095 : || modifiedSubscription->isVehicleToPersonContextSubscription())) {
1096 : // Set last modified vehicle context subscription active for filter modifications
1097 148 : myLastContextSubscription = modifiedSubscription;
1098 : } else {
1099 : // adding other subscriptions deactivates the activation for filter addition
1100 4768 : myLastContextSubscription = nullptr;
1101 : }
1102 : } else {
1103 6 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, "Could not add subscription. " + errors);
1104 : }
1105 902 : } catch (libsumo::TraCIException& e) {
1106 902 : writeStatusCmd(s.commandId, libsumo::RTYPE_ERR, e.what());
1107 902 : }
1108 5821 : myOutputStorage.writeStorage(writeInto);
1109 5821 : }
1110 :
1111 :
1112 : void
1113 1195 : TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1114 : bool found = false;
1115 : std::vector<libsumo::Subscription>::iterator j;
1116 2420 : for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1117 1225 : if (j->id == id && j->commandId == commandId && j->contextDomain == domain) {
1118 1195 : j = mySubscriptions.erase(j);
1119 1195 : if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
1120 : // Remove also reference for filter additions
1121 0 : myLastContextSubscription = nullptr;
1122 : }
1123 : found = true;
1124 1195 : continue;
1125 : }
1126 : ++j;
1127 : }
1128 : // try unsubscribe
1129 1195 : if (found) {
1130 2390 : writeStatusCmd(commandId, libsumo::RTYPE_OK, "");
1131 : } else {
1132 0 : writeStatusCmd(commandId, libsumo::RTYPE_ERR, "The subscription to remove was not found.");
1133 : }
1134 1195 : }
1135 :
1136 :
1137 : bool
1138 4193195 : TraCIServer::processSingleSubscription(const libsumo::Subscription& s, tcpip::Storage& writeInto,
1139 : std::string& errors) {
1140 : bool ok = true;
1141 4193195 : tcpip::Storage outputStorage;
1142 4193195 : const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
1143 : std::set<std::string> objIDs;
1144 4193195 : if (s.contextDomain > 0) {
1145 61313 : if ((s.activeFilters & libsumo::SUBS_FILTER_NO_RTREE) == 0) {
1146 59607 : PositionVector shape;
1147 59607 : libsumo::Helper::findObjectShape(s.commandId, s.id, shape);
1148 59607 : libsumo::Helper::collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
1149 59607 : }
1150 60411 : libsumo::Helper::applySubscriptionFilters(s, objIDs);
1151 : } else {
1152 4131882 : objIDs.insert(s.id);
1153 : }
1154 4192293 : 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 8518206 : for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1157 4325913 : if (s.contextDomain > 0) {
1158 : //if (centralObject(s, *j)) {
1159 : // skipped++;
1160 : // continue;
1161 : //}
1162 194031 : outputStorage.writeString(*j);
1163 : }
1164 4325913 : if (numVars > 0) {
1165 : std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
1166 12769244 : for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1167 8448592 : tcpip::Storage message;
1168 8448592 : message.writeUnsignedByte(*i);
1169 8448592 : message.writeString(*j);
1170 : // TODO check why writeStorage fails here (probably some kind of invalid iterator)
1171 8533399 : for (const auto& v :** k) {
1172 84807 : message.writeChar(v);
1173 : }
1174 8448592 : tcpip::Storage tmpOutput;
1175 8448592 : if (myExecutors.find(getCommandId) != myExecutors.end()) {
1176 8448592 : 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 8448592 : if (ok) {
1183 8448589 : int length = tmpOutput.readUnsignedByte();
1184 59140123 : while (--length > 0) {
1185 50691534 : tmpOutput.readUnsignedByte();
1186 : }
1187 : int lengthLength = 1;
1188 8448589 : length = tmpOutput.readUnsignedByte();
1189 8448589 : if (length == 0) {
1190 : lengthLength = 5;
1191 12 : length = tmpOutput.readInt();
1192 : }
1193 : //read responseType
1194 8448589 : tmpOutput.readUnsignedByte();
1195 8448589 : int variable = tmpOutput.readUnsignedByte();
1196 8448589 : std::string id = tmpOutput.readString();
1197 8448589 : outputStorage.writeUnsignedByte(variable);
1198 8448589 : outputStorage.writeUnsignedByte(libsumo::RTYPE_OK);
1199 8448589 : length -= (lengthLength + 1 + 4 + (int)id.length());
1200 106931849 : while (--length > 0) {
1201 98483260 : 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 8448592 : }
1218 : }
1219 : }
1220 4192293 : int length = (1 + 4) + 1 + (4 + (int)s.id.length()) + 1 + (int)outputStorage.size();
1221 4192293 : if (s.contextDomain > 0) {
1222 60411 : length += 1 + 4; // context domain and number of objects
1223 : }
1224 : // we always write extended command length here for backward compatibility
1225 4192293 : writeInto.writeUnsignedByte(0); // command length -> extended
1226 4192293 : writeInto.writeInt(length);
1227 4192293 : writeInto.writeUnsignedByte(s.commandId + 0x10);
1228 4192293 : writeInto.writeString(s.id);
1229 4192293 : if (s.contextDomain > 0) {
1230 60411 : writeInto.writeUnsignedByte(s.contextDomain);
1231 : }
1232 4192293 : writeInto.writeUnsignedByte(numVars);
1233 4192293 : if (s.contextDomain > 0) {
1234 60411 : writeInto.writeInt((int)objIDs.size() - skipped);
1235 : }
1236 4192293 : if (s.contextDomain == 0 || objIDs.size() != 0) {
1237 4170854 : writeInto.writeStorage(outputStorage);
1238 : }
1239 4192293 : return ok;
1240 4193195 : }
1241 :
1242 :
1243 : bool
1244 7016 : TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1245 7016 : const double beginTime = myInputStorage.readDouble();
1246 7016 : const double endTime = myInputStorage.readDouble();
1247 7016 : const SUMOTime begin = beginTime == libsumo::INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
1248 7016 : const SUMOTime end = endTime == libsumo::INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
1249 7016 : const std::string id = myInputStorage.readString();
1250 7016 : const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1251 3364 : double range = hasContext ? myInputStorage.readDouble() : 0.;
1252 7016 : if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
1253 : range = std::numeric_limits<double>::max();
1254 : }
1255 7016 : const int num = myInputStorage.readUnsignedByte();
1256 : std::vector<int> variables;
1257 : std::vector<std::shared_ptr<tcpip::Storage> > parameters;
1258 15689 : for (int i = 0; i < num; ++i) {
1259 8673 : const int varID = myInputStorage.readUnsignedByte();
1260 8673 : variables.push_back(varID);
1261 8673 : parameters.push_back(std::make_shared<tcpip::Storage>());
1262 8673 : if ((myParameterized.count(std::make_pair(0, varID)) > 0) || (myParameterized.count(std::make_pair(commandId, varID)) > 0)) {
1263 57 : const int parType = myInputStorage.readUnsignedByte();
1264 57 : parameters.back()->writeUnsignedByte(parType);
1265 57 : if (parType == libsumo::TYPE_DOUBLE) {
1266 36 : parameters.back()->writeDouble(myInputStorage.readDouble());
1267 21 : } else if (parType == libsumo::TYPE_STRING) {
1268 42 : parameters.back()->writeString(myInputStorage.readString());
1269 : } else {
1270 : // Error!
1271 : }
1272 : }
1273 : }
1274 : // check subscribe/unsubscribe
1275 7016 : if (variables.empty()) {
1276 1195 : removeSubscription(commandId, id, domain);
1277 : return true;
1278 : }
1279 : // process subscription
1280 5821 : libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
1281 5821 : initialiseSubscription(s);
1282 : return true;
1283 7016 : }
1284 :
1285 :
1286 :
1287 : bool
1288 387 : TraCIServer::addSubscriptionFilter() {
1289 : bool success = true;
1290 : // Read filter type
1291 387 : int filterType = myInputStorage.readUnsignedByte();
1292 :
1293 387 : if (myLastContextSubscription == nullptr) {
1294 2 : writeStatusCmd(libsumo::CMD_ADD_SUBSCRIPTION_FILTER, libsumo::RTYPE_ERR,
1295 2 : "No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
1296 2 : return false;
1297 : }
1298 :
1299 : // dispatch according to filter type
1300 385 : switch (filterType) {
1301 0 : case libsumo::FILTER_TYPE_NONE:
1302 : // Remove all filters
1303 0 : removeFilters();
1304 : break;
1305 90 : case libsumo::FILTER_TYPE_LANES: {
1306 : // Read relative lanes to consider for context filter
1307 90 : int nrLanes = (int)myInputStorage.readByte();
1308 : std::vector<int> lanes;
1309 243 : for (int i = 0; i < nrLanes; ++i) {
1310 153 : lanes.push_back((int) myInputStorage.readByte());
1311 : }
1312 90 : addSubscriptionFilterLanes(lanes);
1313 90 : }
1314 : break;
1315 29 : case libsumo::FILTER_TYPE_NOOPPOSITE:
1316 : // Add no-opposite filter
1317 29 : addSubscriptionFilterNoOpposite();
1318 : break;
1319 103 : case libsumo::FILTER_TYPE_DOWNSTREAM_DIST: {
1320 103 : myInputStorage.readByte(); // read type double
1321 103 : double dist = myInputStorage.readDouble();
1322 103 : addSubscriptionFilterDownstreamDistance(dist);
1323 : }
1324 : break;
1325 87 : case libsumo::FILTER_TYPE_UPSTREAM_DIST: {
1326 87 : myInputStorage.readByte(); // read type double
1327 87 : double dist = myInputStorage.readDouble();
1328 87 : addSubscriptionFilterUpstreamDistance(dist);
1329 : }
1330 : break;
1331 13 : case libsumo::FILTER_TYPE_LEAD_FOLLOW: {
1332 : // Read relative lanes to consider for context filter
1333 13 : addSubscriptionFilterLeadFollow();
1334 : }
1335 : break;
1336 17 : case libsumo::FILTER_TYPE_TURN: {
1337 17 : myInputStorage.readByte(); // read type double
1338 17 : double dist = myInputStorage.readDouble();
1339 17 : addSubscriptionFilterTurn(dist);
1340 : }
1341 : break;
1342 7 : case libsumo::FILTER_TYPE_VCLASS: {
1343 7 : myInputStorage.readByte(); // read type stringlist
1344 7 : SVCPermissions vClasses = parseVehicleClasses(myInputStorage.readStringList());
1345 7 : addSubscriptionFilterVClass(vClasses);
1346 : }
1347 : break;
1348 7 : case libsumo::FILTER_TYPE_VTYPE: {
1349 7 : myInputStorage.readByte(); // read type stringlist
1350 7 : std::vector<std::string> vTypesVector = myInputStorage.readStringList();
1351 : std::set<std::string> vTypesSet;
1352 : vTypesSet.insert(vTypesVector.begin(), vTypesVector.end());
1353 14 : addSubscriptionFilterVType(vTypesSet);
1354 7 : }
1355 : break;
1356 17 : case libsumo::FILTER_TYPE_FIELD_OF_VISION: {
1357 17 : myInputStorage.readByte(); // read type double
1358 17 : double angle = myInputStorage.readDouble();
1359 17 : addSubscriptionFilterFieldOfVision(angle);
1360 : }
1361 : break;
1362 15 : case libsumo::FILTER_TYPE_LATERAL_DIST: {
1363 15 : myInputStorage.readByte(); // read type double
1364 15 : double dist = myInputStorage.readDouble();
1365 15 : 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 770 : 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 90 : 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 90 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LANES;
1397 90 : myLastContextSubscription->filterLanes = lanes;
1398 90 : }
1399 :
1400 : void
1401 29 : TraCIServer::addSubscriptionFilterNoOpposite() {
1402 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1403 : std::cout << "Adding no opposite filter" << std::endl;
1404 : #endif
1405 29 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_NOOPPOSITE;
1406 29 : }
1407 :
1408 : void
1409 103 : TraCIServer::addSubscriptionFilterDownstreamDistance(double dist) {
1410 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1411 : std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1412 : #endif
1413 103 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_DOWNSTREAM_DIST;
1414 103 : myLastContextSubscription->filterDownstreamDist = dist;
1415 103 : }
1416 :
1417 : void
1418 87 : TraCIServer::addSubscriptionFilterUpstreamDistance(double dist) {
1419 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1420 : std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1421 : #endif
1422 87 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_UPSTREAM_DIST;
1423 87 : myLastContextSubscription->filterUpstreamDist = dist;
1424 87 : }
1425 :
1426 : void
1427 13 : TraCIServer::addSubscriptionFilterLeadFollow() {
1428 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1429 : std::cout << "Adding Lead/Follow-maneuver filter" << std::endl;
1430 : #endif
1431 13 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LEAD_FOLLOW;
1432 13 : }
1433 :
1434 : void
1435 17 : TraCIServer::addSubscriptionFilterTurn(double dist) {
1436 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1437 : std::cout << "Adding turn-maneuver filter" << std::endl;
1438 : #endif
1439 17 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_TURN;
1440 17 : myLastContextSubscription->filterFoeDistToJunction = dist;
1441 17 : }
1442 :
1443 : void
1444 7 : TraCIServer::addSubscriptionFilterVClass(SVCPermissions vClasses) {
1445 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1446 : std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
1447 : #endif
1448 7 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VCLASS;
1449 7 : myLastContextSubscription->filterVClasses = vClasses;
1450 7 : }
1451 :
1452 : void
1453 7 : 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 7 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_VTYPE;
1458 : myLastContextSubscription->filterVTypes = vTypes;
1459 7 : }
1460 :
1461 : void
1462 17 : TraCIServer::addSubscriptionFilterFieldOfVision(double openingAngle) {
1463 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1464 : std::cout << "Adding FieldOfVision filter (openingAngle=" << toString(openingAngle) << ")" << std::endl;
1465 : #endif
1466 17 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_FIELD_OF_VISION;
1467 17 : myLastContextSubscription->filterFieldOfVisionOpeningAngle = openingAngle;
1468 17 : }
1469 :
1470 : void
1471 15 : TraCIServer::addSubscriptionFilterLateralDistance(double dist) {
1472 : #ifdef DEBUG_SUBSCRIPTION_FILTERS
1473 : std::cout << "Adding lateral dist filter (dist=" << toString(dist) << ")" << std::endl;
1474 : #endif
1475 15 : myLastContextSubscription->activeFilters = myLastContextSubscription->activeFilters | libsumo::SUBS_FILTER_LATERAL_DIST;
1476 15 : myLastContextSubscription->filterLateralDist = dist;
1477 15 : }
1478 :
1479 : void
1480 18083999 : TraCIServer::writeResponseWithLength(tcpip::Storage& outputStorage, tcpip::Storage& tempMsg) {
1481 18083999 : if (tempMsg.size() < 254) {
1482 18060236 : outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1483 : } else {
1484 23763 : outputStorage.writeUnsignedByte(0); // command length -> extended
1485 23763 : outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1486 : }
1487 18083999 : outputStorage.writeStorage(tempMsg);
1488 18083999 : }
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 80617 : TraCIServer::readTypeCheckingInt(tcpip::Storage& inputStorage, int& into) {
1509 80617 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_INTEGER) {
1510 : return false;
1511 : }
1512 80613 : into = inputStorage.readInt();
1513 80613 : return true;
1514 : }
1515 :
1516 :
1517 : bool
1518 225094 : TraCIServer::readTypeCheckingDouble(tcpip::Storage& inputStorage, double& into) {
1519 225094 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLE) {
1520 : return false;
1521 : }
1522 225091 : into = inputStorage.readDouble();
1523 225091 : return true;
1524 : }
1525 :
1526 :
1527 : bool
1528 278399 : TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1529 278399 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRING) {
1530 : return false;
1531 : }
1532 278396 : into = inputStorage.readString();
1533 278396 : return true;
1534 : }
1535 :
1536 :
1537 : bool
1538 409 : TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1539 409 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_STRINGLIST) {
1540 : return false;
1541 : }
1542 409 : into = inputStorage.readStringList();
1543 409 : return true;
1544 : }
1545 :
1546 :
1547 : bool
1548 210 : TraCIServer::readTypeCheckingDoubleList(tcpip::Storage& inputStorage, std::vector<double>& into) {
1549 210 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_DOUBLELIST) {
1550 : return false;
1551 : }
1552 210 : into = inputStorage.readDoubleList();
1553 210 : return true;
1554 : }
1555 :
1556 :
1557 : bool
1558 324 : TraCIServer::readTypeCheckingColor(tcpip::Storage& inputStorage, libsumo::TraCIColor& into) {
1559 324 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_COLOR) {
1560 : return false;
1561 : }
1562 322 : into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1563 322 : into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1564 322 : into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1565 322 : into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1566 322 : return true;
1567 : }
1568 :
1569 :
1570 : bool
1571 125 : TraCIServer::readTypeCheckingPosition2D(tcpip::Storage& inputStorage, libsumo::TraCIPosition& into) {
1572 125 : if (inputStorage.readUnsignedByte() != libsumo::POSITION_2D) {
1573 : return false;
1574 : }
1575 124 : into.x = inputStorage.readDouble();
1576 124 : into.y = inputStorage.readDouble();
1577 124 : into.z = 0;
1578 124 : return true;
1579 : }
1580 :
1581 :
1582 : bool
1583 101613 : TraCIServer::readTypeCheckingByte(tcpip::Storage& inputStorage, int& into) {
1584 101613 : if (inputStorage.readByte() != libsumo::TYPE_BYTE) {
1585 : return false;
1586 : }
1587 101613 : into = inputStorage.readByte();
1588 101613 : return true;
1589 : }
1590 :
1591 :
1592 : bool
1593 3196 : TraCIServer::readTypeCheckingUnsignedByte(tcpip::Storage& inputStorage, int& into) {
1594 3196 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_UBYTE) {
1595 : return false;
1596 : }
1597 3196 : into = inputStorage.readUnsignedByte();
1598 3196 : return true;
1599 : }
1600 :
1601 :
1602 : bool
1603 105 : TraCIServer::readTypeCheckingPolygon(tcpip::Storage& inputStorage, PositionVector& into) {
1604 105 : if (inputStorage.readUnsignedByte() != libsumo::TYPE_POLYGON) {
1605 : return false;
1606 : }
1607 : into.clear();
1608 104 : int size = inputStorage.readUnsignedByte();
1609 104 : if (size == 0) {
1610 3 : size = inputStorage.readInt();
1611 : }
1612 104 : PositionVector shape;
1613 1347 : for (int i = 0; i < size; ++i) {
1614 1246 : double x = inputStorage.readDouble();
1615 1246 : double y = inputStorage.readDouble();
1616 1246 : if (std::isnan(x) || std::isnan(y)) {
1617 6 : throw libsumo::TraCIException("NaN-Value in shape.");
1618 : }
1619 1243 : into.push_back(Position(x, y));
1620 : }
1621 : return true;
1622 104 : }
1623 :
1624 :
1625 : void
1626 135 : TraCIServer::stateLoaded(SUMOTime targetTime) {
1627 135 : myTargetTime = targetTime;
1628 270 : for (auto& s : mySockets) {
1629 135 : s.second->targetTime = targetTime;
1630 135 : s.second->executeMove = false;
1631 1890 : for (auto& stateChange : s.second->vehicleStateChanges) {
1632 : stateChange.second.clear();
1633 : }
1634 675 : for (auto& stateChange : s.second->transportableStateChanges) {
1635 : stateChange.second.clear();
1636 : }
1637 : }
1638 : mySubscriptions.clear();
1639 135 : mySubscriptionCache.reset();
1640 135 : }
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 : /****************************************************************************/
|