SUMO - Simulation of Urban MObility
TraCIServer.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2007-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
25 // TraCI server used to control sumo by a remote TraCI client (e.g., ns2)
26 /****************************************************************************/
27 
28 // ===========================================================================
29 // included modules
30 // ===========================================================================
31 #include <config.h>
32 
33 #ifdef HAVE_VERSION_H
34 #include <version.h>
35 #endif
36 
37 #ifdef HAVE_PYTHON
38 #include <Python.h>
39 #endif
40 
41 #include <string>
42 #include <map>
43 #include <iostream>
44 #include <algorithm>
45 #include <foreign/tcpip/socket.h>
46 #include <foreign/tcpip/storage.h>
47 #include <utils/common/SUMOTime.h>
55 #include <utils/xml/XMLSubSys.h>
56 #include <microsim/MSNet.h>
57 #include <microsim/MSVehicle.h>
58 #include <microsim/MSEdge.h>
61 #include <microsim/MSJunction.h>
62 #include <microsim/MSEdgeControl.h>
63 #include <microsim/MSLane.h>
64 #include <microsim/MSGlobals.h>
66 #include <libsumo/Simulation.h>
67 #include "TraCIConstants.h"
68 #include "TraCIServer.h"
71 #include "TraCIServerAPI_Lane.h"
75 #include "TraCIServerAPI_Vehicle.h"
77 #include "TraCIServerAPI_Route.h"
78 #include "TraCIServerAPI_POI.h"
79 #include "TraCIServerAPI_Polygon.h"
80 #include "TraCIServerAPI_Edge.h"
82 #include "TraCIServerAPI_Person.h"
83 
84 
85 // ===========================================================================
86 // debug constants
87 // ===========================================================================
88 //#define DEBUG_MULTI_CLIENTS
89 //#define DEBUG_SUBSCRIPTIONS
90 
91 
92 // ===========================================================================
93 // static member definitions
94 // ===========================================================================
97 
98 
99 // ===========================================================================
100 // method definitions
101 // ===========================================================================
102 void
103 TraCIServer::initWrapper(const int domainID, const int variable, const std::string& objID) {
108 }
109 
110 
111 bool
112 TraCIServer::wrapDouble(const std::string& /* objID */, const int /* variable */, const double value) {
115  return true;
116 }
117 
118 
119 bool
120 TraCIServer::wrapInt(const std::string& /* objID */, const int /* variable */, const int value) {
122  myWrapperStorage.writeInt(value);
123  return true;
124 }
125 
126 
127 bool
128 TraCIServer::wrapString(const std::string& /* objID */, const int /* variable */, const std::string& value) {
131  return true;
132 }
133 
134 
135 bool
136 TraCIServer::wrapStringList(const std::string& /* objID */, const int /* variable */, const std::vector<std::string>& value) {
139  return true;
140 }
141 
142 
143 bool
144 TraCIServer::wrapPosition(const std::string& /* objID */, const int variable, const libsumo::TraCIPosition& value) {
145  const bool includeZ = variable == VAR_POSITION3D;
149  if (includeZ) {
151  }
152  return true;
153 }
154 
155 
156 bool
157 TraCIServer::wrapColor(const std::string& /* objID */, const int /* variable */, const libsumo::TraCIColor& value) {
163  return true;
164 }
165 
166 
169  return myWrapperStorage;
170 }
171 
172 
173 
174 TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
175  : myServerSocket(nullptr), myTargetTime(begin), myAmEmbedded(port == 0), myLastContextSubscription(nullptr) {
176 #ifdef DEBUG_MULTI_CLIENTS
177  std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
178 #endif
179  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
180  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
181  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
182  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
183  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
184  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
185  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
186  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
187  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
188  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
189  myVehicleStateChanges[MSNet::VEHICLE_STATE_COLLISION] = std::vector<std::string>();
190  myVehicleStateChanges[MSNet::VEHICLE_STATE_EMERGENCYSTOP] = std::vector<std::string>();
191 
195 
217 
219 
220  myDoCloseConnection = false;
221 
222  // display warning if internal lanes are not used
224  WRITE_WARNING("Starting TraCI without using internal lanes!");
225  MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
226  MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
227  }
228 
229  if (!myAmEmbedded) {
230  try {
231  WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
232  myServerSocket = new tcpip::Socket(port);
233  while ((int)mySockets.size() < numClients) {
234  int index = (int)mySockets.size() + MAX_ORDER + 1;
235  mySockets[index] = new SocketInfo(myServerSocket->accept(true), begin);
236  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
237  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
238  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
239  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
240  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
241  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
242  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
243  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
244  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
245  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
246  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_COLLISION] = std::vector<std::string>();
247  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_EMERGENCYSTOP] = std::vector<std::string>();
248  }
249  // When got here, all clients have connected
250  if (numClients > 1) {
252  }
253  // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommandsUntilSimStep()
254  myCurrentSocket = mySockets.begin();
255  } catch (tcpip::SocketException& e) {
256  throw ProcessError(e.what());
257  }
258  }
259 }
260 
261 
263  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
264  delete myCurrentSocket->second;
265  }
266  delete myServerSocket;
267  cleanup();
268 }
269 
270 
271 // ---------- Initialisation and Shutdown
272 void
273 TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
274  if (myInstance == 0 && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0
275 #ifdef HAVE_PYTHON
276  || OptionsCont::getOptions().isSet("python-script")
277 #endif
278  )) {
279  myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
280  OptionsCont::getOptions().getInt("remote-port"),
281  OptionsCont::getOptions().getInt("num-clients"));
282  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
283  myInstance->myExecutors[i->first] = i->second;
284  }
285  }
286  if (myInstance != 0) {
287  // maybe net was deleted and built again
290  }
291 }
292 
293 
294 void
296  if (myInstance == 0) {
297  return;
298  }
299  delete myInstance;
300  myInstance = 0;
301  myDoCloseConnection = true;
302 }
303 
304 
305 bool
307  return myDoCloseConnection;
308 }
309 
310 
311 // ---------- Initialisation and Shutdown
312 
313 
314 void
315 TraCIServer::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
316  if (!myDoCloseConnection) {
317  myVehicleStateChanges[to].push_back(vehicle->getID());
318  if (!myAmEmbedded) {
319  for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
320  i->second->vehicleStateChanges[to].push_back(vehicle->getID());
321  }
322  }
323  }
324 }
325 
326 
327 void
329 #ifdef DEBUG_MULTI_CLIENTS
330  std::cout << "Checking client order requests." << std::endl;
331 #endif
332  // check for SET_ORDER commands queued by connected clients
333  // In multiclient cas it is mandatory that SET_ORDER is sent as the first command (or directly after GET_VERSION)
334  myCurrentSocket = mySockets.begin();
335  while (myCurrentSocket != mySockets.end()) {
336 #ifdef DEBUG_MULTI_CLIENTS
337  std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
338 #endif
339 // bool clientUnordered = true;
340 #ifdef _MSC_VER
341 #pragma warning(push)
342 #pragma warning(disable: 4127) // do not warn about constant conditional expression
343 #endif
344  while (true) {
345 #ifdef _MSC_VER
346 #pragma warning(pop)
347 #endif
349  myCurrentSocket->second->socket->receiveExact(myInputStorage);
350  int commandStart, commandLength;
351  int commandId = readCommandID(commandStart, commandLength);
352 #ifdef DEBUG_MULTI_CLIENTS
353  std::cout << " received command " << commandId << std::endl;
354 #endif
355  // Whether the received command is a permitted command for the initialization phase.
356  // Currently, getVersion and setOrder are permitted.
357  bool initCommand = commandId == CMD_SETORDER || commandId == CMD_GETVERSION;
358  if (initCommand) {
359 #ifdef DEBUG_MULTI_CLIENTS
360  std::cout << " Init command. Sending response." << std::endl;
361 #endif
362  // reset input storage to initial state before reading the commandId
363  // (ugly, but we can't just reset the store's iter_ from here)
364  // Giving the commandId to dispatch command didn't work either
365  tcpip::Storage tmp;
368  myInputStorage.writeUnsignedByte(commandLength);
371 
372  // Handle initialization command completely
373  dispatchCommand();
374  myCurrentSocket->second->socket->sendExact(myOutputStorage);
376  } else {
377 #ifdef DEBUG_MULTI_CLIENTS
378  std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
379 #endif
380  throw ProcessError("Execution order (CMD_SETORDER) was not set for all TraCI clients in pre-execution phase.");
381  }
382  if (commandId == CMD_SETORDER) {
383  // This is what we have waited for.
384  break;
385  }
386  }
387  ++myCurrentSocket;
388  }
389 }
390 
391 
392 void
394  // Process reordering requests
395  if (mySocketReorderRequests.size() > 0) {
396  // process reordering requests
397  std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
398  std::map<int, SocketInfo*>::iterator j;
399 #ifdef DEBUG_MULTI_CLIENTS
400  std::cout << SIMTIME << " Current socket ordering:\n";
401  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
402  std::cout << " " << j->first << ": " << j->second->socket << "\n";
403  }
404  std::cout << "Reordering requests:\n";
405  for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
406  std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
407  }
408  i = mySocketReorderRequests.begin();
409 #endif
410  while (i != mySocketReorderRequests.end()) {
411  j = mySockets.begin();
412  while (j != mySockets.end()) {
413  if (j->second->socket == i->second->socket) {
414  break;
415  } else {
416  j++;
417  }
418  }
419  assert(j != mySockets.end());
420  mySockets.erase(j);
421  mySockets[i->first] = i->second;
422  ++i;
423  }
424  mySocketReorderRequests.clear();
425 #ifdef DEBUG_MULTI_CLIENTS
426  std::cout << "New socket ordering:\n";
427  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
428  std::cout << " " << j->first << ": " << j->second->socket << "\n";
429  }
430  std::cout << std::endl;
431 #endif
432  }
433 }
434 
435 
436 SUMOTime
438 #ifdef DEBUG_MULTI_CLIENTS
439  std::cout << "\n Determining new target time..." << std::endl;
440  if (mySockets.size() == 0) {
441  std::cout << " All clients have disconnected." << std::endl;
442  }
443 #endif
444  std::map<int, SocketInfo*>::const_iterator i;
445  SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
446  for (i = mySockets.begin(); i != mySockets.end(); ++i) {
447 #ifdef DEBUG_MULTI_CLIENTS
448  std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
449 #endif
450  targetTime = MIN2(targetTime, i->second->targetTime);
451  }
452 #ifdef DEBUG_MULTI_CLIENTS
453  std::cout << std::endl;
454 #endif
455  return targetTime;
456 }
457 
458 
459 // send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
460 void
462 #ifdef DEBUG_MULTI_CLIENTS
463  std::cout << "\n Sending subscription results to clients:\n";
464 #endif
465  std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
466  while (i != mySockets.end()) {
467  if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
468  // this client will become active before the next SUMO step. Provide subscription results.
469  i->second->socket->sendExact(myOutputStorage);
470 #ifdef DEBUG_MULTI_CLIENTS
471  std::cout << i->second->socket << "\n";
472 #endif
473  }
474  ++i;
475  }
476 #ifdef DEBUG_MULTI_CLIENTS
477  std::cout << std::endl;
478 #endif
479 }
480 
481 
482 void
484 #ifdef DEBUG_MULTI_CLIENTS
485  std::cout << SIMTIME << " processCommandsUntilSimStep(step = " << step << "):\n" << std::endl;
486 #endif
487  try {
488  const bool firstStep = myCurrentSocket != mySockets.end();
489  // update client order if requested
491  if (!firstStep) {
492  // 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)
493  // update subscription results
495  // Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
496  sendOutputToAll();
498  }
499 
500  // determine minimal next target time among clients
502 
503  if (myAmEmbedded || step < myTargetTime) {
504 #ifdef DEBUG_MULTI_CLIENTS
505  if (step < myTargetTime) {
506  std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommandsUntilSimStep()." << std::endl;
507  }
508 #endif
509  return;
510  }
511 
512  // Simulation should run until
513  // 1. end time reached or
514  // 2. got CMD_CLOSE or
515  // 3. got CMD_LOAD or
516  // 4. Client closes socket connection
517  while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep())) {
518 #ifdef DEBUG_MULTI_CLIENTS
519  std::cout << " Next target time: " << myTargetTime << std::endl;
520 #endif
521  // Iterate over clients and process communication for the ones with target time == myTargetTime
522  myCurrentSocket = mySockets.begin();
523  while (myCurrentSocket != mySockets.end()) {
524 #ifdef DEBUG_MULTI_CLIENTS
525  std::cout << " current socket: " << myCurrentSocket->second->socket
526  << " with target time " << myCurrentSocket->second->targetTime
527  << std::endl;
528 #endif
529 
530  if (myCurrentSocket->second->targetTime > myTargetTime) {
531  // this client must wait
532 #ifdef DEBUG_MULTI_CLIENTS
533  std::cout << " skipping client " << myCurrentSocket->second->socket
534  << " with target time " << myCurrentSocket->second->targetTime << std::endl;
535 #endif
536  myCurrentSocket++;
537  continue;
538  }
539  bool done = false;
540  bool closed = false;
541  bool load = false;
542  while (!done && !closed && !load) {
543  if (!myInputStorage.valid_pos()) {
544  // have read request completely, send response if adequate
545  if (myOutputStorage.size() > 0) {
546 #ifdef DEBUG_MULTI_CLIENTS
547  std::cout << " sending response..." << std::endl;
548 #endif
549  // send response to previous query
550  myCurrentSocket->second->socket->sendExact(myOutputStorage);
552  } else {
553 #ifdef DEBUG_MULTI_CLIENTS
554  std::cout << " No input and no output stored (This is the next client)." << std::endl;
555 #endif
556  }
557 #ifdef DEBUG_MULTI_CLIENTS
558  std::cout << " resetting input storage and reading next command..." << std::endl;
559 #endif
560  // Read next request
562  myCurrentSocket->second->socket->receiveExact(myInputStorage);
563  }
564 
566  // dispatch command
567  const int cmd = dispatchCommand();
568 #ifdef DEBUG_MULTI_CLIENTS
569  std::cout << " Received command " << cmd << std::endl;
570 #endif
571  if (cmd == CMD_SIMSTEP) {
572 #ifdef DEBUG_MULTI_CLIENTS
573  std::cout << " Received command SIM_STEP, end turn for client " << myCurrentSocket->second->socket << std::endl;
574 #endif
575  done = true;
576  } else if (cmd == CMD_LOAD) {
577 #ifdef DEBUG_MULTI_CLIENTS
578  std::cout << " Received command LOAD." << std::endl;
579 #endif
580  load = true;
581  } else if (cmd == CMD_CLOSE) {
582 #ifdef DEBUG_MULTI_CLIENTS
583  std::cout << " Received command CLOSE." << std::endl;
584 #endif
585  closed = true;
586  }
587  }
588  }
589  if (done) {
590  // Clear vehicleStateChanges for this client -> For subsequent TraCI stepping
591  // that is performed within this SUMO step, no updates on vehicle states
592  // belonging to the last SUMO simulation step will be received by this client.
593  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myCurrentSocket->second->vehicleStateChanges.begin(); i != myCurrentSocket->second->vehicleStateChanges.end(); ++i) {
594  (*i).second.clear();
595  }
596  myCurrentSocket++;
597  } else if (load) {
598  myCurrentSocket = mySockets.end();
599  } else {
600  assert(closed);
601  // remove current socket and increment to next socket in ordering
603  }
604  }
605  if (!myLoadArgs.empty()) {
606 #ifdef DEBUG_MULTI_CLIENTS
607  std::cout << " Breaking loop to load new simulation." << std::endl;
608 #endif
609  break;
610  } else if (myDoCloseConnection) {
611 #ifdef DEBUG_MULTI_CLIENTS
612  std::cout << " Breaking loop because last client closed connection." << std::endl;
613 #endif
614  break;
615  }
616  SUMOTime nextT = nextTargetTime();
617  // minimal target time among clients should have been increased during the last loop through mySockets
618  // XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
619  // leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
620  // the next call is then usually simulationStep(step=1000) leading to no further increase
621  // and thus a failing assertion here.
622  //assert(myTargetTime < nextT || myDoCloseConnection);
623  myTargetTime = nextT;
624  }
625  // All clients are done with the current time step
626  // Reset myVehicleStateChanges
627  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
628  (*i).second.clear();
629  }
630  } catch (std::invalid_argument& e) {
631  throw ProcessError(e.what());
632  } catch (libsumo::TraCIException& e) {
633  throw ProcessError(e.what());
634  } catch (tcpip::SocketException& e) {
635  throw ProcessError(e.what());
636  }
637 }
638 
639 
640 void
642  mySubscriptions.clear();
643  myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
644  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
645  myCurrentSocket->second->targetTime = myTargetTime;
646  }
650  std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i;
651  for (i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); i++) {
652  i->second.clear();
653  }
654  myCurrentSocket = mySockets.begin();
655 }
656 
657 
658 #ifdef HAVE_PYTHON
659 // ===========================================================================
660 // python functions (traciemb module)
661 // ===========================================================================
662 static PyObject*
663 traciemb_execute(PyObject* /* self */, PyObject* args) {
664  const char* msg;
665  int size;
666  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
667  return NULL;
668  }
669  std::string result = TraCIServer::execute(std::string(msg, size));
670  return Py_BuildValue("s#", result.c_str(), result.size());
671 }
672 
673 static PyMethodDef EmbMethods[] = {
674  {
675  "execute", traciemb_execute, METH_VARARGS,
676  "Execute the given TraCI command and return the result."
677  },
678  {NULL, NULL, 0, NULL}
679 };
680 
681 
682 std::string
683 TraCIServer::execute(std::string cmd) {
684  try {
685  assert(myInstance != 0);
688  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
690  }
692  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
693  } catch (std::invalid_argument& e) {
694  throw ProcessError(e.what());
695  } catch (libsumo::TraCIException& e) {
696  throw ProcessError(e.what());
697  } catch (tcpip::SocketException& e) {
698  throw ProcessError(e.what());
699  }
700 }
701 
702 
703 void
704 TraCIServer::runEmbedded(std::string pyFile) {
705  PyObject* pName, *pModule;
706  Py_Initialize();
707  Py_InitModule("traciemb", EmbMethods);
708  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
709  PyObject* sys_path, *path;
710  char pathstr[] = "path";
711  sys_path = PySys_GetObject(pathstr);
712  if (sys_path == NULL || !PyList_Check(sys_path)) {
713  throw ProcessError("Could not access python sys.path!");
714  }
715  path = PyString_FromString(FileHelpers::getFilePath(pyFile).c_str());
716  PyList_Insert(sys_path, 0, path);
717  Py_DECREF(path);
718  FILE* pFile = fopen(pyFile.c_str(), "r");
719  if (pFile == NULL) {
720  throw ProcessError("Failed to load \"" + pyFile + "\"!");
721  }
722  PyRun_SimpleFile(pFile, pyFile.c_str());
723  fclose(pFile);
724  } else {
725  pName = PyString_FromString(pyFile.c_str());
726  /* Error checking of pName left out */
727  pModule = PyImport_Import(pName);
728  Py_DECREF(pName);
729  if (pModule == NULL) {
730  PyErr_Print();
731  throw ProcessError("Failed to load \"" + pyFile + "\"!");
732  }
733  }
734  Py_Finalize();
735 }
736 #endif
737 
738 
739 std::map<int, TraCIServer::SocketInfo*>::iterator
741 #ifdef DEBUG_MULTI_CLIENTS
742  std::cout << " Removing socket " << myCurrentSocket->second->socket
743  << " (order " << myCurrentSocket->first << ")" << std::endl;
744 #endif
745 
746  if (mySockets.size() == 1) {
747  // Last client has disconnected
748  delete myCurrentSocket->second->socket;
749  mySockets.clear();
750  myCurrentSocket = mySockets.end();
751  return myCurrentSocket;
752  }
753 
754  const int currOrder = myCurrentSocket->first;
755  delete myCurrentSocket->second->socket;
756  myCurrentSocket++;
757  if (myCurrentSocket != mySockets.end()) {
758  const int nextOrder = myCurrentSocket->first;
759  mySockets.erase(currOrder);
760  myCurrentSocket = mySockets.find(nextOrder);
761  } else {
762  mySockets.erase(currOrder);
763  myCurrentSocket = mySockets.end();
764  }
765  return myCurrentSocket;
766 }
767 
768 
769 int
770 TraCIServer::readCommandID(int& commandStart, int& commandLength) {
771  commandStart = myInputStorage.position();
772  commandLength = myInputStorage.readUnsignedByte();
773  if (commandLength == 0) {
774  commandLength = myInputStorage.readInt();
775  }
777 }
778 
779 
780 int
782  int commandStart, commandLength;
783  int commandId = readCommandID(commandStart, commandLength);
784 #ifdef DEBUG_MULTI_CLIENTS
785  std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
786  << ", commandId = " << commandId << std::endl;
787 #endif
788  bool success = false;
789  // dispatch commands
790  if (myExecutors.find(commandId) != myExecutors.end()) {
791  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
792  } else {
793  switch (commandId) {
794  case CMD_GETVERSION:
795  success = commandGetVersion();
796  break;
797  case CMD_LOAD: {
798  std::vector<std::string> args;
800  return writeErrorStatusCmd(CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
801  }
802 #ifdef DEBUG_MULTI_CLIENTS
803  std::cout << " commandId == CMD_LOAD"
804  << ", args = " << toString(args) << std::endl;
805 #endif
806  try {
807  myLoadArgs = args;
808  success = true;
810  // XXX: This only cares for the client that issued the load command.
811  // Multiclient-load functionality is still to be implemented. Refs #3146.
812  myCurrentSocket->second->socket->sendExact(myOutputStorage);
814  } catch (libsumo::TraCIException& e) {
815  return writeErrorStatusCmd(CMD_LOAD, e.what(), myOutputStorage);
816  }
817  break;
818  }
819  case CMD_SIMSTEP: {
820  const double nextT = myInputStorage.readDouble();
821  if (myAmEmbedded) {
822  if (nextT == 0.) {
824  } else {
825  myTargetTime = TIME2STEPS(nextT);
826  }
827  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
828  (*i).second.clear();
829  }
830  while (MSNet::getInstance()->getCurrentTimeStep() < myTargetTime) {
832  }
834  } else {
835  if (nextT == 0.) {
836  myCurrentSocket->second->targetTime += DELTA_T;
837  } else {
838  myCurrentSocket->second->targetTime = TIME2STEPS(nextT);
839  }
840 #ifdef DEBUG_MULTI_CLIENTS
841  std::cout << " commandId == CMD_SIMSTEP"
842  << ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
843 #endif
844  if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
845  // This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
846  // @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommandsUntilSimStep()
848  }
849  }
850  return commandId;
851  }
852  case CMD_CLOSE:
854  myCurrentSocket->second->socket->sendExact(myOutputStorage);
856  if (mySockets.size() == 1) {
857  // Last client has closed connection
858  myDoCloseConnection = true;
859  }
860  success = true;
861  break;
862  case CMD_SETORDER: {
863  const int order = myInputStorage.readInt();
864 #ifdef DEBUG_MULTI_CLIENTS
865  std::cout << " commandId == CMD_SETORDER"
866  << ", order index is " << order << std::endl;
867 #endif
868  if (order > MAX_ORDER) {
869  return writeErrorStatusCmd(CMD_SETORDER, "A set order command needs an int argument below " + toString(MAX_ORDER) + ".", myOutputStorage);
870  }
871  if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
872  return writeErrorStatusCmd(CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
873  }
874  // memorize reorder request (will only take effect in the next step)
875  mySocketReorderRequests[order] = myCurrentSocket->second;
876  success = true;
878  break;
879  }
895  success = addObjectVariableSubscription(commandId, false);
896  break;
912  success = addObjectVariableSubscription(commandId, true);
913  break;
915  success = addSubscriptionFilter();
916  break;
917  default:
918  if (commandId == CMD_GET_GUI_VARIABLE || commandId == CMD_SET_GUI_VARIABLE) {
919  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "GUI is not running, command not implemented in command line sumo");
920  } else {
921  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
922  }
923  }
924  }
925  if (!success) {
926  while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
928  }
929  }
930  if ((int)myInputStorage.position() != commandStart + commandLength) {
931  std::ostringstream msg;
932  msg << "Wrong position in requestMessage after dispatching command.";
933  msg << " Expected command length was " << commandLength;
934  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
935  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
936  myDoCloseConnection = true;
937  }
938  return commandId;
939 }
940 
941 
942 // ---------- Server-internal command handling
943 bool
945  std::string sumoVersion = VERSION_STRING;
946  // Prepare response
947  tcpip::Storage answerTmp;
948  answerTmp.writeInt(TRACI_VERSION);
949  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
950  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
952  // command length
953  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
954  // command type
956  // and the parameter dependant part
957  myOutputStorage.writeStorage(answerTmp);
958  return true;
959 }
960 
961 
962 void
965 #ifdef DEBUG_MULTI_CLIENTS
966  std::cout << " postProcessSimulationStep() at time " << t << std::endl;
967 #endif
969  int noActive = 0;
970  for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
971  const libsumo::Subscription& s = *i;
975  if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
976  i = mySubscriptions.erase(i);
977  continue;
978  }
979  ++i;
980  if (s.beginTime > t) {
981  continue;
982  }
983  ++noActive;
984  }
986 #ifdef DEBUG_SUBSCRIPTIONS
987  std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
988  << "\n Nr. of active subscriptions = " << noActive << std::endl;
989 #endif
990  mySubscriptionCache.writeInt(noActive);
991 #ifdef DEBUG_SUBSCRIPTIONS
992  std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
993 #endif
994  for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
995  const libsumo::Subscription& s = *i;
996  if (s.beginTime > t) {
997  ++i;
998  continue;
999  }
1000  tcpip::Storage into;
1001  std::string errors;
1002  bool ok = processSingleSubscription(s, into, errors);
1003 #ifdef DEBUG_SUBSCRIPTIONS
1004  std::cout << " Size of into-store for subscription " << s.id
1005  << ": " << into.size() << std::endl;
1006 #endif
1008  if (ok) {
1009  ++i;
1010  } else {
1011  i = mySubscriptions.erase(i);
1012  }
1013  }
1015 #ifdef DEBUG_SUBSCRIPTIONS
1016  std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
1017 #endif
1018 }
1019 
1020 
1021 void
1023 #ifdef DEBUG_MULTI_CLIENTS
1024  std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
1025  << " (-> intermediate TraCI step)."
1026  << "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
1027  << std::endl;
1028 #endif
1030 
1031 // NOTE: the commented code would send an empty response
1032 // myOutputStorage.writeInt(0);
1033 // myCurrentSocket->second->socket->sendExact(myOutputStorage);
1034 // myOutputStorage.reset();
1036  // send results to active client
1037  myCurrentSocket->second->socket->sendExact(myOutputStorage);
1039 }
1040 
1041 
1042 void
1043 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
1044  writeStatusCmd(commandId, status, description, myOutputStorage);
1045 }
1046 
1047 
1048 void
1049 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
1050  if (status == RTYPE_ERR) {
1051  WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
1052  } else if (status == RTYPE_NOTIMPLEMENTED) {
1053  WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
1054  }
1055  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
1056  outputStorage.writeUnsignedByte(commandId); // command type
1057  outputStorage.writeUnsignedByte(status); // status
1058  outputStorage.writeString(description); // description
1059 }
1060 
1061 
1062 bool
1063 TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
1064  writeStatusCmd(commandId, RTYPE_ERR, description, outputStorage);
1065  return false;
1066 }
1067 
1068 
1069 void
1071  tcpip::Storage writeInto;
1072  std::string errors;
1073  libsumo::Subscription* modifiedSubscription = nullptr;
1074  if (processSingleSubscription(s, writeInto, errors)) {
1076  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
1077  } else {
1078  bool needNewSubscription = true;
1080  if (s.commandId == o.commandId && s.id == o.id &&
1081  s.beginTime == o.beginTime && s.endTime == o.endTime &&
1082  s.contextDomain == o.contextDomain && s.range == o.range) {
1083  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1084  for (std::vector<int>::const_iterator j = s.variables.begin(); j != s.variables.end(); ++j, ++k) {
1085  const int offset = (int)(std::find(o.variables.begin(), o.variables.end(), *j) - o.variables.begin());
1086  if (offset == (int)o.variables.size() || o.parameters[offset] != *k) {
1087  o.variables.push_back(*j);
1088  o.parameters.push_back(*k);
1089  }
1090  }
1091  needNewSubscription = false;
1092  modifiedSubscription = &o;
1093  break;
1094  }
1095  }
1096  if (needNewSubscription) {
1097  mySubscriptions.push_back(s);
1098  modifiedSubscription = &mySubscriptions.back();
1099  // Add new subscription to subscription cache (note: seems a bit inefficient)
1101  // copy new subscription into cache
1102  int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1103  tcpip::Storage tmp;
1104  tmp.writeInt(noActive);
1105  while (mySubscriptionCache.valid_pos()) {
1107  }
1108  tmp.writeStorage(writeInto);
1111  }
1112  }
1114  }
1115  if (modifiedSubscription != nullptr && isVehicleToVehicleContextSubscription(*modifiedSubscription)) {
1116  // Set last modified vehicle context subscription active for filter modifications
1117  myLastContextSubscription = modifiedSubscription;
1118  } else {
1119  // adding other subscriptions deactivates the activation for filter addition
1120  myLastContextSubscription = nullptr;
1121  }
1122  } else {
1123  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
1124  }
1125  myOutputStorage.writeStorage(writeInto);
1126 }
1127 
1128 
1129 void
1130 TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1131  bool found = false;
1132  std::vector<libsumo::Subscription>::iterator j;
1133  for (j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1134  if (j->id == id && j->commandId == commandId && (domain < 0 || j->contextDomain == domain)) {
1135  j = mySubscriptions.erase(j);
1136  if (j != mySubscriptions.end() && myLastContextSubscription == &(*j)) {
1137  // Remove also reference for filter additions
1138  myLastContextSubscription = nullptr;
1139  }
1140  found = true;
1141  continue;
1142  }
1143  ++j;
1144  }
1145  // try unsubscribe
1146  if (found) {
1147  writeStatusCmd(commandId, RTYPE_OK, "");
1148  } else {
1149  writeStatusCmd(commandId, RTYPE_ERR, "The subscription to remove was not found.");
1150  }
1151 }
1152 
1153 bool
1156 }
1157 
1158 
1159 bool
1161  std::string& errors) {
1162  bool ok = true;
1163  tcpip::Storage outputStorage;
1164  const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
1165  std::set<std::string> objIDs;
1166  if (s.contextDomain > 0) {
1167  PositionVector shape;
1170  } else {
1171  objIDs.insert(s.id);
1172  }
1173  const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == ID_LIST ? 0 : (int)s.variables.size();
1174  int skipped = 0;
1175  for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1176  if (s.contextDomain > 0) {
1177  //if (centralObject(s, *j)) {
1178  // skipped++;
1179  // continue;
1180  //}
1181  outputStorage.writeString(*j);
1182  }
1183  if (numVars > 0) {
1184  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1185  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1186  tcpip::Storage message;
1187  message.writeUnsignedByte(*i);
1188  message.writeString(*j);
1189  message.writePacket(*k);
1190  tcpip::Storage tmpOutput;
1191  if (myExecutors.find(getCommandId) != myExecutors.end()) {
1192  ok &= myExecutors[getCommandId](*this, message, tmpOutput);
1193  } else {
1194  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1195  ok = false;
1196  }
1197  // copy response part
1198  if (ok) {
1199  int length = tmpOutput.readUnsignedByte();
1200  while (--length > 0) {
1201  tmpOutput.readUnsignedByte();
1202  }
1203  int lengthLength = 1;
1204  length = tmpOutput.readUnsignedByte();
1205  if (length == 0) {
1206  lengthLength = 5;
1207  length = tmpOutput.readInt();
1208  }
1209  //read responseType
1210  tmpOutput.readUnsignedByte();
1211  int variable = tmpOutput.readUnsignedByte();
1212  std::string id = tmpOutput.readString();
1213  outputStorage.writeUnsignedByte(variable);
1214  outputStorage.writeUnsignedByte(RTYPE_OK);
1215  length -= (lengthLength + 1 + 4 + (int)id.length());
1216  while (--length > 0) {
1217  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
1218  }
1219  } else {
1220  //read length
1221  tmpOutput.readUnsignedByte();
1222  //read cmd
1223  tmpOutput.readUnsignedByte();
1224  //read status
1225  tmpOutput.readUnsignedByte();
1226  std::string msg = tmpOutput.readString();
1227  outputStorage.writeUnsignedByte(*i);
1228  outputStorage.writeUnsignedByte(RTYPE_ERR);
1229  outputStorage.writeUnsignedByte(TYPE_STRING);
1230  outputStorage.writeString(msg);
1231  errors = errors + msg;
1232  }
1233  }
1234  }
1235  }
1236  int length = (1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size();
1237  if (s.contextDomain > 0) {
1238  length += 4;
1239  }
1240  writeInto.writeUnsignedByte(0); // command length -> extended
1241  writeInto.writeInt(length);
1242  writeInto.writeUnsignedByte(s.commandId + 0x10);
1243  writeInto.writeString(s.id);
1244  if (s.contextDomain > 0) {
1245  writeInto.writeUnsignedByte(s.contextDomain);
1246  }
1247  writeInto.writeUnsignedByte(numVars);
1248  if (s.contextDomain > 0) {
1249  writeInto.writeInt((int)objIDs.size() - skipped);
1250  }
1251  if (s.contextDomain == 0 || objIDs.size() != 0) {
1252  writeInto.writeStorage(outputStorage);
1253  }
1254  return ok;
1255 }
1256 
1257 
1258 bool
1259 TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1260  const double beginTime = myInputStorage.readDouble();
1261  const double endTime = myInputStorage.readDouble();
1262  const SUMOTime begin = beginTime == INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
1263  const SUMOTime end = endTime == INVALID_DOUBLE_VALUE ? SUMOTime_MAX : TIME2STEPS(endTime);
1264  const std::string id = myInputStorage.readString();
1265  const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1266  const double range = hasContext ? myInputStorage.readDouble() : 0.;
1267  const int num = myInputStorage.readUnsignedByte();
1268  std::vector<int> variables;
1269  std::vector<std::vector<unsigned char> > parameters;
1270  for (int i = 0; i < num; ++i) {
1271  const int varID = myInputStorage.readUnsignedByte();
1272  variables.push_back(varID);
1273  parameters.push_back(std::vector<unsigned char>());
1274  for (int j = 0; j < myParameterSizes[varID]; j++) {
1275  parameters.back().push_back(myInputStorage.readChar());
1276  }
1277  }
1278  // check subscribe/unsubscribe
1279  if (variables.size() == 0) {
1280  removeSubscription(commandId, id, -1);
1281  return true;
1282  }
1283  // process subscription
1284  libsumo::Subscription s(commandId, id, variables, parameters, begin, end, domain, range);
1286  return true;
1287 }
1288 
1289 
1290 
1291 bool
1293  bool success = true;
1294  // Read filter type
1295  int filterType = myInputStorage.readUnsignedByte();
1296 
1297  // dispatch according to filter type
1298  switch (filterType) {
1299  case FILTER_TYPE_NONE:
1300  // Remove all filters
1301  removeFilters();
1302  break;
1303  case FILTER_TYPE_LANES: {
1304  // Read relative lanes to consider for context filter
1305  int nrLanes = (int)myInputStorage.readByte();
1306  std::vector<int> lanes;
1307  for (int i = 0; i < nrLanes; ++i) {
1308  lanes.push_back((int) myInputStorage.readByte());
1309  }
1311  }
1312  break;
1314  // Add no-opposite filter
1316  break;
1318  double dist = myInputStorage.readDouble();
1320  }
1321  break;
1323  double dist = myInputStorage.readDouble();
1325  }
1326  break;
1329  break;
1330  case FILTER_TYPE_LC_MANEUVER: {
1332  }
1333  break;
1336  break;
1337  case FILTER_TYPE_VCLASS: {
1339  addSubscriptionFilterVClass(vClasses);
1340  }
1341  break;
1342  case FILTER_TYPE_VTYPE: {
1343  std::vector<std::string> vTypes = myInputStorage.readStringList();
1345  }
1346  break;
1347  default:
1348  writeStatusCmd(filterType, RTYPE_NOTIMPLEMENTED, "'" + toString(filterType) + "' is no valid filter type code.");
1349  success = false;
1350  }
1351 
1352  if (success) {
1353  // acknowledge filter addition
1355  }
1356 
1357  return success;
1358 }
1359 
1360 
1361 void
1363  std::cout << "Removing filters" << std::endl;
1364  if (myLastContextSubscription != nullptr) {
1366  }
1367 }
1368 
1369 void
1371  std::cout << "Adding lane filter (lanes=" << toString(lanes) << ")" << std::endl;
1372  if (myLastContextSubscription != nullptr) {
1375  }
1376 }
1377 
1378 void
1380  std::cout << "Adding no opposite filter" << std::endl;
1381  if (myLastContextSubscription != nullptr) {
1383  }
1384 }
1385 
1386 void
1388  std::cout << "Adding downstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1389  if (myLastContextSubscription != nullptr) {
1392  }
1393 }
1394 
1395 void
1397  std::cout << "Adding upstream dist filter (dist=" << toString(dist) << ")" << std::endl;
1398  if (myLastContextSubscription != nullptr) {
1401  }
1402 }
1403 
1404 void
1406  std::cout << "Adding CF-maneuver filter" << std::endl;
1407  if (myLastContextSubscription != nullptr) {
1409  }
1410 }
1411 
1412 void
1414  std::cout << "Adding LC-maneuver filter" << std::endl;
1415  if (myLastContextSubscription != nullptr) {
1417  }
1418 }
1419 
1420 void
1422  std::cout << "Adding turn-maneuver filter" << std::endl;
1423  if (myLastContextSubscription != nullptr) {
1425  }
1426 }
1427 
1428 void
1430  std::cout << "Adding vClass filter (vClasses=" << toString(vClasses) << ")" << std::endl;
1431  if (myLastContextSubscription != nullptr) {
1434  }
1435 }
1436 
1437 void
1438 TraCIServer::addSubscriptionFilterVType(std::vector<std::string> vTypes) {
1439  std::cout << "Adding vType filter (vTypes=" << toString(vTypes) << ")" << std::endl;
1440  if (myLastContextSubscription != nullptr) {
1443  }
1444 }
1445 
1446 void
1448  if (tempMsg.size() < 254) {
1449  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1450  } else {
1451  outputStorage.writeUnsignedByte(0); // command length -> extended
1452  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1453  }
1454  outputStorage.writeStorage(tempMsg);
1455 }
1456 
1457 bool
1459  if (inputStorage.readUnsignedByte() != TYPE_INTEGER) {
1460  return false;
1461  }
1462  into = inputStorage.readInt();
1463  return true;
1464 }
1465 
1466 
1467 bool
1469  if (inputStorage.readUnsignedByte() != TYPE_DOUBLE) {
1470  return false;
1471  }
1472  into = inputStorage.readDouble();
1473  return true;
1474 }
1475 
1476 
1477 bool
1478 TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1479  if (inputStorage.readUnsignedByte() != TYPE_STRING) {
1480  return false;
1481  }
1482  into = inputStorage.readString();
1483  return true;
1484 }
1485 
1486 
1487 bool
1488 TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1489  if (inputStorage.readUnsignedByte() != TYPE_STRINGLIST) {
1490  return false;
1491  }
1492  into = inputStorage.readStringList();
1493  return true;
1494 }
1495 
1496 
1497 bool
1499  if (inputStorage.readUnsignedByte() != TYPE_COLOR) {
1500  return false;
1501  }
1502  into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1503  into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1504  into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1505  into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1506  return true;
1507 }
1508 
1509 
1510 bool
1512  if (inputStorage.readUnsignedByte() != POSITION_2D) {
1513  return false;
1514  }
1515  into.x = inputStorage.readDouble();
1516  into.y = inputStorage.readDouble();
1517  into.z = 0;
1518  return true;
1519 }
1520 
1521 
1522 bool
1524  if (inputStorage.readByte() != TYPE_BYTE) {
1525  return false;
1526  }
1527  into = inputStorage.readByte();
1528  return true;
1529 }
1530 
1531 
1532 bool
1534  if (inputStorage.readUnsignedByte() != TYPE_UBYTE) {
1535  return false;
1536  }
1537  into = inputStorage.readUnsignedByte();
1538  return true;
1539 }
1540 
1541 
1542 bool
1544  if (inputStorage.readUnsignedByte() != TYPE_POLYGON) {
1545  return false;
1546  }
1547  into.clear();
1548  int noEntries = inputStorage.readUnsignedByte();
1549  PositionVector shape;
1550  for (int i = 0; i < noEntries; ++i) {
1551  double x = inputStorage.readDouble();
1552  double y = inputStorage.readDouble();
1553  into.push_back(Position(x, y));
1554  }
1555  return true;
1556 }
1557 
1558 
1559 void
1561  myTargetTime = targetTime;
1562  for (auto& s : mySockets) {
1563  s.second->targetTime = targetTime;
1564  }
1565 }
1566 
1567 bool
1568 TraCIServer::centralObject(const libsumo::Subscription& s, const std::string& objID) {
1569  return (s.id == objID && s.commandId + 32 == s.contextDomain);
1570 }
1571 
1572 /****************************************************************************/
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa3: Get Lane Variable)
The vehicle has departed (was inserted into the network)
Definition: MSNet.h:491
#define FILTER_TYPE_NONE
unsigned char g
Definition: TraCIDefs.h:139
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
void addSubscriptionFilterDownstreamDistance(double dist)
#define CMD_SUBSCRIBE_VEHICLE_CONTEXT
#define CMD_SUBSCRIBE_LANE_VARIABLE
#define FILTER_TYPE_LC_MANEUVER
tcpip::Storage mySubscriptionCache
The last timestep&#39;s subscription results.
Definition: TraCIServer.h:374
bool readTypeCheckingColor(tcpip::Storage &inputStorage, libsumo::TraCIColor &into)
Reads the value type and a color, verifying the type.
#define FILTER_TYPE_VCLASS
#define CMD_SUBSCRIBE_LANEAREA_VARIABLE
Representation of a subscription.
Definition: Subscription.h:63
long long int SUMOTime
Definition: SUMOTime.h:36
double range
The range of the context.
Definition: Subscription.h:96
#define CMD_GET_TL_VARIABLE
#define CMD_SUBSCRIBE_JUNCTION_CONTEXT
StorageType::const_iterator end() const
Definition: storage.h:118
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc3: Change Lane State)
bool wrapString(const std::string &objID, const int variable, const std::string &value)
#define CMD_GET_VEHICLE_VARIABLE
bool processSingleSubscription(const libsumo::Subscription &s, tcpip::Storage &writeInto, std::string &errors)
virtual ~TraCIServer()
Destructor.
#define CMD_SUBSCRIBE_SIM_CONTEXT
#define FILTER_TYPE_CF_MANEUVER
bool commandGetVersion()
Returns the TraCI-version.
#define CMD_SUBSCRIBE_VEHICLETYPE_CONTEXT
#define CMD_CLOSE
virtual std::vector< std::string > readStringList()
#define POSITION_2D
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc4: Change Vehicle State)
void addSubscriptionFilterVType(std::vector< std::string > vTypes)
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc7: Change PoI State)
#define CMD_GET_INDUCTIONLOOP_VARIABLE
#define CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE
bool wrapInt(const std::string &objID, const int variable, const int value)
void addSubscriptionFilterTurnManeuver()
#define TYPE_UBYTE
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
#define RTYPE_OK
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa9: Get Junction Variable)
#define CMD_GET_LANEAREA_VARIABLE
#define CMD_GET_PERSON_VARIABLE
virtual double readDouble()
tcpip::Storage myOutputStorage
The storage to write to.
Definition: TraCIServer.h:368
#define FILTER_TYPE_TURN_MANEUVER
#define TYPE_POLYGON
void initialiseSubscription(libsumo::Subscription &s)
#define TRACI_VERSION
void postProcessSimulationStep()
Handles subscriptions to send after a simstep2 command.
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc2: Change Traffic Lights State)
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xab: Get Simulation Variable)
#define MAX_ORDER
bool readTypeCheckingInt(tcpip::Storage &inputStorage, int &into)
Reads the value type and an int, verifying the type.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:160
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc6: Change Route State)
std::vector< std::string > myLoadArgs
Definition: TraCIServer.h:385
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
bool readTypeCheckingString(tcpip::Storage &inputStorage, std::string &into)
Reads the value type and a string, verifying the type.
#define TYPE_COLOR
#define TYPE_STRINGLIST
bool readTypeCheckingDouble(tcpip::Storage &inputStorage, double &into)
Reads the value type and a double, verifying the type.
virtual bool valid_pos()
#define CMD_SUBSCRIBE_POLYGON_CONTEXT
#define POSITION_3D
tcpip::Storage myInputStorage
The storage to read from.
Definition: TraCIServer.h:365
SUMOTime beginTime
The begin time of the subscription.
Definition: Subscription.h:90
#define CMD_GET_POLYGON_VARIABLE
virtual void writePacket(unsigned char *packet, int length)
#define CMD_SUBSCRIBE_JUNCTION_VARIABLE
bool centralObject(const libsumo::Subscription &s, const std::string &objID)
check whether a found objID refers to the central object of a context subscription ...
void cleanup()
clean up subscriptions
#define CMD_SUBSCRIBE_ROUTE_CONTEXT
bool readTypeCheckingPolygon(tcpip::Storage &inputStorage, PositionVector &into)
Reads the value type and a polygon, verifying the type.
#define TIME2STEPS(x)
Definition: SUMOTime.h:60
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xca: Change Edge State)
virtual void writeUnsignedByte(int)
#define CMD_SET_EDGE_VARIABLE
#define CMD_SET_GUI_VARIABLE
bool writeErrorStatusCmd(int commandId, const std::string &description, tcpip::Storage &outputStorage)
Writes a status command to the given storage with status = RTYPE_ERR.
#define CMD_SUBSCRIBE_EDGE_VARIABLE
virtual unsigned char readChar()
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition: MSNet.cpp:810
#define CMD_GET_ROUTE_VARIABLE
#define CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT
virtual void writeInt(int)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:242
#define VAR_POSITION3D
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
#define TYPE_STRING
#define SIMTIME
Definition: SUMOTime.h:65
virtual int readUnsignedByte()
SUMOTime endTime
The end time of the subscription.
Definition: Subscription.h:92
virtual void writeChar(unsigned char)
#define CMD_SUBSCRIBE_POI_VARIABLE
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa4: Get Vehicle Variable)
std::string id
The id of the object that is subscribed.
Definition: Subscription.h:84
static bool myDoCloseConnection
Whether the connection was set to be to close.
Definition: TraCIServer.h:346
std::map< int, SocketInfo * >::iterator removeCurrentSocket()
removes myCurrentSocket from mySockets and returns an iterator pointing to the next member according ...
void addSubscriptionFilterVClass(SVCPermissions vClasses)
The vehicles starts to stop.
Definition: MSNet.h:505
std::map< int, CmdExecutor > myExecutors
Map of commandIds -> their executors; applicable if the executor applies to the method footprint...
Definition: TraCIServer.h:380
#define CMD_SET_TL_VARIABLE
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa1: Get AreaDetector Variable)
int commandId
commandIdArg The command id of the subscription
Definition: Subscription.h:82
#define CMD_SUBSCRIBE_LANE_CONTEXT
#define CMD_SUBSCRIBE_SIM_VARIABLE
void removeSubscription(int commandId, const std::string &identity, int domain)
unsigned char b
Definition: TraCIDefs.h:139
#define CMD_GET_VEHICLETYPE_VARIABLE
int activeFilters
Active filters for the subscription (bitset,.
Definition: Subscription.h:99
static void close()
request termination of connection
bool addObjectVariableSubscription(const int commandId, const bool hasContext)
#define CMD_SET_ROUTE_VARIABLE
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xcb: Set Simulation Variable)
#define CMD_GETVERSION
#define CMD_SUBSCRIBE_GUI_CONTEXT
#define CMD_LOAD
#define FILTER_TYPE_UPSTREAM_DIST
The vehicle got a new route.
Definition: MSNet.h:499
The vehicle arrived at his destination (is deleted)
Definition: MSNet.h:497
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
The vehicles starts to park.
Definition: MSNet.h:501
The vehicle is involved in a collision.
Definition: MSNet.h:509
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xce: Change Person State)
#define FILTER_TYPE_LANES
void addSubscriptionFilterCFManeuver()
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual int readInt()
int contextDomain
The domain ID of the context.
Definition: Subscription.h:94
void addSubscriptionFilterNoOpposite()
double filterDownstreamDist
Downstream distance specified by the downstream distance filter.
Definition: Subscription.h:103
The vehicle had to brake harder than permitted.
Definition: MSNet.h:511
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:748
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
#define CMD_GET_POI_VARIABLE
int filterVClasses
vClasses specified by the vClasses filter,
Definition: Subscription.h:109
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE
A list of positions.
void addSubscriptionFilterLCManeuver()
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT
#define CMD_SET_VEHICLETYPE_VARIABLE
virtual void writeByte(int)
bool wrapStringList(const std::string &objID, const int variable, const std::vector< std::string > &value)
bool readTypeCheckingStringList(tcpip::Storage &inputStorage, std::vector< std::string > &into)
Reads the value type and a string list, verifying the type.
unsigned char a
Definition: TraCIDefs.h:139
virtual void writeStringList(const std::vector< std::string > &s)
#define CMD_SUBSCRIBE_GUI_VARIABLE
#define CMD_GET_LANE_VARIABLE
#define CMD_SUBSCRIBE_LANEAREA_CONTEXT
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:256
#define FILTER_TYPE_NOOPPOSITE
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa5: Get Vehicle Type Variable)
#define CMD_SET_VEHICLE_VARIABLE
SUMOTime string2time(const std::string &r)
Definition: SUMOTime.cpp:42
T MIN2(T a, T b)
Definition: StdDefs.h:62
void addSubscriptionFilterUpstreamDistance(double dist)
bool addSubscriptionFilter()
The vehicle started to teleport.
Definition: MSNet.h:493
tcpip::Storage & getWrapperStorage()
#define CMD_GET_SIM_VARIABLE
virtual std::string readString()
#define CMD_GET_EDGE_VARIABLE
libsumo::Subscription * myLastContextSubscription
The last modified context subscription (the one to add a filter to, see (), currently only for vehicl...
Definition: TraCIServer.h:391
virtual unsigned int position() const
#define CMD_GET_GUI_VARIABLE
bool isVehicleToVehicleContextSubscription(const libsumo::Subscription &s)
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:69
unsigned char r
Definition: TraCIDefs.h:139
SVCPermissions parseVehicleClasses(const std::string &allowedS)
Parses the given definition of allowed vehicle classes into the given containers Deprecated classes g...
#define CMD_SET_POI_VARIABLE
void removeFilters()
int readCommandID(int &commandStart, int &commandLength)
Reads the next command ID from the input storage.
#define VERSION_STRING
Definition: version.h:1
#define CMD_SUBSCRIBE_POLYGON_VARIABLE
static TraCIServer * myInstance
Singleton instance of the server.
Definition: TraCIServer.h:343
#define CMD_SUBSCRIBE_TL_CONTEXT
The vehicle ends to park.
Definition: MSNet.h:503
#define CMD_SUBSCRIBE_EDGE_CONTEXT
#define FILTER_TYPE_VTYPE
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa0: Get Induction Loop Variable)
#define CMD_GET_JUNCTION_VARIABLE
Socket * accept(const bool create=false)
Wait for a incoming connection to port_.
Definition: socket.cpp:230
#define CMD_SUBSCRIBE_PERSON_VARIABLE
bool readTypeCheckingUnsignedByte(tcpip::Storage &inputStorage, int &into)
Reads the value type and an unsigned byte, verifying the type.
TraCI server used to control sumo by a remote TraCI client.
Definition: TraCIServer.h:62
void sendOutputToAll() const
send out subscription results (actually just the content of myOutputStorage) to clients which will ac...
TraCIServer(const SUMOTime begin, const int port, const int numClients)
Constructor.
virtual void writeStorage(tcpip::Storage &store)
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xae: Get Person Variable)
void sendSingleSimStepResponse()
sends an empty response to a simstep command to the current client. (This applies to a situation wher...
#define VAR_LEADER
#define CMD_SET_SIM_VARIABLE
double filterUpstreamDist
Upstream distance specified by the upstream distance filter.
Definition: Subscription.h:105
std::vector< std::vector< unsigned char > > parameters
The parameters for the subscribed variables.
Definition: Subscription.h:88
StorageType::size_type size() const
Definition: storage.h:115
#define INVALID_DOUBLE_VALUE
#define CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE
bool wrapColor(const std::string &objID, const int variable, const libsumo::TraCIColor &value)
void writeResponseWithLength(tcpip::Storage &outputStorage, tcpip::Storage &tempMsg)
#define FILTER_TYPE_DOWNSTREAM_DIST
VehicleState
Definition of a vehicle state.
Definition: MSNet.h:487
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa7: Get PoI Variable)
const bool myAmEmbedded
Whether the server runs in embedded mode.
Definition: TraCIServer.h:377
The vehicle was built, but has not yet departed.
Definition: MSNet.h:489
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:248
void processCommandsUntilSimStep(SUMOTime step)
process all commands until the next SUMO simulation step. It is guaranteed that t->getTargetTime() >=...
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa2: Get Traffic Lights Variable)
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc5: Change Vehicle Type State)
void processReorderingRequests()
checks for and processes reordering requests (relevant for multiple clients)
#define CMD_SET_POLYGON_VARIABLE
static void openSocket(const std::map< int, CmdExecutor > &execs)
Initialises the server.
virtual void writeString(const std::string &s)
#define RTYPE_NOTIMPLEMENTED
#define SUMOTime_MAX
Definition: SUMOTime.h:37
#define CMD_ADD_SUBSCRIPTION_FILTER
#define TYPE_DOUBLE
std::string toHex(const T i, std::streamsize numDigits=0)
Definition: ToString.h:59
#define CMD_SUBSCRIBE_VEHICLE_VARIABLE
bool wrapPosition(const std::string &objID, const int variable, const libsumo::TraCIPosition &value)
#define CMD_SUBSCRIBE_PERSON_CONTEXT
static void collectObjectsInRange(int domain, const PositionVector &shape, double range, std::set< std::string > &into)
Definition: Helper.cpp:356
std::map< int, SocketInfo * >::iterator myCurrentSocket
The currently active client socket.
Definition: TraCIServer.h:359
std::vector< int > variables
The subscribed variables.
Definition: Subscription.h:86
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to, const std::string &info="")
Called if a vehicle changes its state.
SUMOTime nextTargetTime() const
get the minimal next target time among all clients
#define TYPE_BYTE
StorageType::const_iterator begin() const
Definition: storage.h:117
#define CMD_SET_LANE_VARIABLE
void setTargetTime(SUMOTime targetTime)
Sets myTargetTime on server and sockets to the given value.
#define CMD_GET_MULTIENTRYEXIT_VARIABLE
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:113
SUMOTime myTargetTime
The time step to reach until processing the next commands.
Definition: TraCIServer.h:362
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa6: Get Route Variable)
std::vector< libsumo::Subscription > mySubscriptions
The list of known, still valid subscriptions.
Definition: TraCIServer.h:388
The vehicle ends to stop.
Definition: MSNet.h:507
bool readTypeCheckingPosition2D(tcpip::Storage &inputStorage, libsumo::TraCIPosition &into)
Reads the value type and a 2D position, verifying the type.
virtual void writeDouble(double)
#define CMD_SETORDER
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa1: Get MeMeDetector Variable)
void addSubscriptionFilterLanes(std::vector< int > lanes)
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa8: Get Polygon Variable)
int dispatchCommand()
Handles command, writes response to myOutputStorage.
#define CMD_SUBSCRIBE_TL_VARIABLE
tcpip::Storage myWrapperStorage
A temporary storage to let the wrapper write to.
Definition: TraCIServer.h:371
std::map< int, SocketInfo * > mySockets
The socket connections to the clients the first component (index) determines the client&#39;s order (lowe...
Definition: TraCIServer.h:353
void writeStatusCmd(int commandId, int status, const std::string &description, tcpip::Storage &outputStorage)
Writes a status command to the given storage.
std::map< int, SocketInfo * > mySocketReorderRequests
This stores the setOrder(int) requests of the clients.
Definition: TraCIServer.h:356
static std::string getFilePath(const std::string &path)
Removes the file information from the given path.
Definition: FileHelpers.cpp:65
void initWrapper(const int domainID, const int variable, const std::string &objID)
#define CMD_SET_PERSON_VARIABLE
static void findObjectShape(int domain, const std::string &id, PositionVector &shape)
Definition: Helper.cpp:323
void simulationStep()
Performs a single simulation step.
Definition: MSNet.cpp:430
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:243
A 3D-position.
Definition: TraCIDefs.h:107
#define RTYPE_ERR
#define TYPE_INTEGER
#define ID_LIST
std::vector< std::string > filterVTypes
vTypes specified by the vTypes filter
Definition: Subscription.h:107
#define CMD_SUBSCRIBE_POI_CONTEXT
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xaa: Get Edge Variable)
static bool wasClosed()
check whether close was requested
std::map< MSNet::VehicleState, std::vector< std::string > > myVehicleStateChanges
Changes in the states of simulated vehicles.
Definition: TraCIServer.h:400
The vehicle ended being teleported.
Definition: MSNet.h:495
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
#define CMD_SIMSTEP
virtual int readByte()
bool readTypeCheckingByte(tcpip::Storage &inputStorage, int &into)
Reads the value type and a byte, verifying the type.
bool wrapDouble(const std::string &objID, const int variable, const double value)
tcpip::Socket * myServerSocket
The server socket.
Definition: TraCIServer.h:349
#define CMD_SUBSCRIBE_ROUTE_VARIABLE
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc8: Change Polygon State)
std::vector< int > filterLanes
lanes specified by the lanes filter
Definition: Subscription.h:101
std::map< int, int > myParameterSizes
Map of variable ids to the size of the parameter in bytes.
Definition: TraCIServer.h:383
void checkClientOrdering()
Called once after connection of all clients for executing SET_ORDER (and possibly prior GET_VERSION) ...