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