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-2017 German Aerospace Center (DLR) and others.
4 /****************************************************************************/
5 //
6 // This program and the accompanying materials
7 // are made available under the terms of the Eclipse Public License v2.0
8 // which accompanies this distribution, and is available at
9 // http://www.eclipse.org/legal/epl-v20.html
10 //
11 /****************************************************************************/
27 // TraCI server used to control sumo by a remote TraCI client (e.g., ns2)
28 /****************************************************************************/
29 
30 // ===========================================================================
31 // included modules
32 // ===========================================================================
33 #ifdef _MSC_VER
34 #include <windows_config.h>
35 #else
36 #include <config.h>
37 #endif
38 
39 #ifdef HAVE_VERSION_H
40 #include <version.h>
41 #endif
42 
43 #ifndef NO_TRACI
44 
45 #ifdef HAVE_PYTHON
46 #include <Python.h>
47 #endif
48 
49 #include <string>
50 #include <map>
51 #include <iostream>
52 #include <algorithm>
53 #include <foreign/tcpip/socket.h>
54 #include <foreign/tcpip/storage.h>
55 #include <utils/common/SUMOTime.h>
63 #include <utils/xml/XMLSubSys.h>
64 #include <microsim/MSNet.h>
65 #include <microsim/MSVehicle.h>
66 #include <microsim/MSEdge.h>
69 #include <microsim/MSJunction.h>
70 #include <microsim/MSEdgeControl.h>
71 #include <microsim/MSLane.h>
72 #include <microsim/MSGlobals.h>
74 #include <libsumo/Simulation.h>
75 #include "TraCIConstants.h"
76 #include "TraCIServer.h"
79 #include "TraCIServerAPI_Lane.h"
83 #include "TraCIServerAPI_Vehicle.h"
85 #include "TraCIServerAPI_Route.h"
86 #include "TraCIServerAPI_POI.h"
87 #include "TraCIServerAPI_Polygon.h"
88 #include "TraCIServerAPI_Edge.h"
90 #include "TraCIServerAPI_Person.h"
91 
92 
93 // ===========================================================================
94 // debug constants
95 // ===========================================================================
96 //#define DEBUG_MULTI_CLIENTS
97 //#define DEBUG_SUBSCRIPTIONS
98 
99 
100 // ===========================================================================
101 // static member definitions
102 // ===========================================================================
105 
106 
107 // ===========================================================================
108 // method definitions
109 // ===========================================================================
110 TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
111  : myServerSocket(0),
112  myTargetTime(begin),
113  myAmEmbedded(port == 0) {
114 #ifdef DEBUG_MULTI_CLIENTS
115  std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
116 #endif
117  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
118  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
119  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
120  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
121  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
122  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
123  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
124  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
125  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
126  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
127 
131 
153 
155 
156  myDoCloseConnection = false;
157 
158  // display warning if internal lanes are not used
160  WRITE_WARNING("Starting TraCI without using internal lanes!");
161  MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
162  MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
163  }
164 
165  if (!myAmEmbedded) {
166  try {
167  WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
168  myServerSocket = new tcpip::Socket(port);
169  while ((int)mySockets.size() < numClients) {
170  int index = (int)mySockets.size() + MAX_ORDER + 1;
171  mySockets[index] = new SocketInfo(myServerSocket->accept(true), begin);
172  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
173  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
174  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
175  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
176  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
177  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
178  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
179  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
180  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
181  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
182  }
183  // When got here, all clients have connected
184  if (numClients > 1) {
186  }
187  // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommandsUntilSimStep()
188  myCurrentSocket = mySockets.begin();
189  } catch (tcpip::SocketException& e) {
190  throw ProcessError(e.what());
191  }
192  }
193 }
194 
195 
197  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
198  delete myCurrentSocket->second;
199  }
200  delete myServerSocket;
201  cleanup();
202 }
203 
204 
205 // ---------- Initialisation and Shutdown
206 void
207 TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
208  if (myInstance == 0 && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0
209 #ifdef HAVE_PYTHON
210  || OptionsCont::getOptions().isSet("python-script")
211 #endif
212  )) {
213  myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
214  OptionsCont::getOptions().getInt("remote-port"),
215  OptionsCont::getOptions().getInt("num-clients"));
216  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
217  myInstance->myExecutors[i->first] = i->second;
218  }
219  }
220  if (myInstance != 0) {
221  // maybe net was deleted and built again
223  }
224 }
225 
226 
227 void
229  if (myInstance == 0) {
230  return;
231  }
232  delete myInstance;
233  myInstance = 0;
234  myDoCloseConnection = true;
235 }
236 
237 
238 bool
240  return myDoCloseConnection;
241 }
242 
243 
244 // ---------- Initialisation and Shutdown
245 
246 
247 void
249  if (!myDoCloseConnection) {
250  myVehicleStateChanges[to].push_back(vehicle->getID());
251  if (!myAmEmbedded) {
252  for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
253  i->second->vehicleStateChanges[to].push_back(vehicle->getID());
254  }
255  }
256  }
257 }
258 
259 void
261 #ifdef DEBUG_MULTI_CLIENTS
262  std::cout << "Checking client order requests." << std::endl;
263 #endif
264  // check for SET_ORDER commands queued by connected clients
265  // In multiclient cas it is mandatory that SET_ORDER is sent as the first command (or directly after GET_VERSION)
266  myCurrentSocket = mySockets.begin();
267  while (myCurrentSocket != mySockets.end()) {
268 #ifdef DEBUG_MULTI_CLIENTS
269  std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
270 #endif
271 // bool clientUnordered = true;
272 #ifdef _MSC_VER
273 #pragma warning(push)
274 #pragma warning(disable: 4127) // do not warn about constant conditional expression
275 #endif
276  while (true) {
277 #ifdef _MSC_VER
278 #pragma warning(pop)
279 #endif
281  myCurrentSocket->second->socket->receiveExact(myInputStorage);
282  int commandStart, commandLength;
283  int commandId = readCommandID(commandStart, commandLength);
284 #ifdef DEBUG_MULTI_CLIENTS
285  std::cout << " received command " << commandId << std::endl;
286 #endif
287  // Whether the received command is a permitted command for the initialization phase.
288  // Currently, getVersion and setOrder are permitted.
289  bool initCommand = commandId == CMD_SETORDER || commandId == CMD_GETVERSION;
290  if (initCommand) {
291 #ifdef DEBUG_MULTI_CLIENTS
292  std::cout << " Init command. Sending response." << std::endl;
293 #endif
294  // reset input storage to initial state before reading the commandId
295  // (ugly, but we can't just reset the store's iter_ from here)
296  // Giving the commandId to dispatch command didn't work either
297  tcpip::Storage tmp;
300  myInputStorage.writeUnsignedByte(commandLength);
303 
304  // Handle initialization command completely
305  dispatchCommand();
306  myCurrentSocket->second->socket->sendExact(myOutputStorage);
308  } else {
309 #ifdef DEBUG_MULTI_CLIENTS
310  std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
311 #endif
312  throw ProcessError("Execution order (CMD_SETORDER) was not set for all TraCI clients in pre-execution phase.");
313  }
314  if (commandId == CMD_SETORDER) {
315  // This is what we have waited for.
316  break;
317  }
318  }
319  ++myCurrentSocket;
320  }
321 }
322 
323 
324 void
326  // Process reordering requests
327  if (mySocketReorderRequests.size() > 0) {
328  // process reordering requests
329  std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
330  std::map<int, SocketInfo*>::iterator j;
331 #ifdef DEBUG_MULTI_CLIENTS
332  std::cout << SIMTIME << " Current socket ordering:\n";
333  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
334  std::cout << " " << j->first << ": " << j->second->socket << "\n";
335  }
336  std::cout << "Reordering requests:\n";
337  for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
338  std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
339  }
340  i = mySocketReorderRequests.begin();
341 #endif
342  while (i != mySocketReorderRequests.end()) {
343  j = mySockets.begin();
344  while (j != mySockets.end()) {
345  if (j->second->socket == i->second->socket) {
346  break;
347  } else {
348  j++;
349  }
350  }
351  assert(j != mySockets.end());
352  mySockets.erase(j);
353  mySockets[i->first] = i->second;
354  ++i;
355  }
356  mySocketReorderRequests.clear();
357 #ifdef DEBUG_MULTI_CLIENTS
358  std::cout << "New socket ordering:\n";
359  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
360  std::cout << " " << j->first << ": " << j->second->socket << "\n";
361  }
362  std::cout << std::endl;
363 #endif
364  }
365 }
366 
367 
368 SUMOTime
370 #ifdef DEBUG_MULTI_CLIENTS
371  std::cout << "\n Determining new target time..." << std::endl;
372  if (mySockets.size() == 0) {
373  std::cout << " All clients have disconnected." << std::endl;
374  }
375 #endif
376  std::map<int, SocketInfo*>::const_iterator i;
377  SUMOTime targetTime = std::numeric_limits<SUMOTime>::max();
378  for (i = mySockets.begin(); i != mySockets.end(); ++i) {
379 #ifdef DEBUG_MULTI_CLIENTS
380  std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
381 #endif
382  targetTime = MIN2(targetTime, i->second->targetTime);
383  }
384 #ifdef DEBUG_MULTI_CLIENTS
385  std::cout << std::endl;
386 #endif
387  return targetTime;
388 }
389 
390 
391 // send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
392 void
394 #ifdef DEBUG_MULTI_CLIENTS
395  std::cout << "\n Sending subscription results to clients:\n";
396 #endif
397  std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
398  while (i != mySockets.end()) {
399  if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
400  // this client will become active before the next SUMO step. Provide subscription results.
401  i->second->socket->sendExact(myOutputStorage);
402 #ifdef DEBUG_MULTI_CLIENTS
403  std::cout << i->second->socket << "\n";
404 #endif
405  }
406  ++i;
407  }
408 #ifdef DEBUG_MULTI_CLIENTS
409  std::cout << std::endl;
410 #endif
411 }
412 
413 
414 void
416 #ifdef DEBUG_MULTI_CLIENTS
417  std::cout << SIMTIME << " processCommandsUntilSimStep(step = " << step << "):\n" << std::endl;
418 #endif
419  try {
420  const bool firstStep = myCurrentSocket != mySockets.end();
421  // update client order if requested
423  if (!firstStep) {
424  // 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)
425  // update subscription results
427  // Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
428  sendOutputToAll();
430  }
431 
432  // determine minimal next target time among clients
434 
435  if (myAmEmbedded || step < myTargetTime) {
436 #ifdef DEBUG_MULTI_CLIENTS
437  if (step < myTargetTime) {
438  std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommandsUntilSimStep()." << std::endl;
439  }
440 #endif
441  return;
442  }
443 
444  // Simulation should run until
445  // 1. end time reached or
446  // 2. got CMD_CLOSE or
447  // 3. got CMD_LOAD or
448  // 4. Client closes socket connection
449  while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep())) {
450 #ifdef DEBUG_MULTI_CLIENTS
451  std::cout << " Next target time: " << myTargetTime << std::endl;
452 #endif
453  // Iterate over clients and process communication for the ones with target time == myTargetTime
454  myCurrentSocket = mySockets.begin();
455  while (myCurrentSocket != mySockets.end()) {
456 #ifdef DEBUG_MULTI_CLIENTS
457  std::cout << " current socket: " << myCurrentSocket->second->socket
458  << " with target time " << myCurrentSocket->second->targetTime
459  << std::endl;
460 #endif
461 
462  if (myCurrentSocket->second->targetTime > myTargetTime) {
463  // this client must wait
464 #ifdef DEBUG_MULTI_CLIENTS
465  std::cout << " skipping client " << myCurrentSocket->second->socket
466  << " with target time " << myCurrentSocket->second->targetTime << std::endl;
467 #endif
468  myCurrentSocket++;
469  continue;
470  }
471  bool done = false;
472  bool closed = false;
473  bool load = false;
474  while (!done && !closed && !load) {
475  if (!myInputStorage.valid_pos()) {
476  // have read request completely, send response if adequate
477  if (myOutputStorage.size() > 0) {
478 #ifdef DEBUG_MULTI_CLIENTS
479  std::cout << " sending response..." << std::endl;
480 #endif
481  // send response to previous query
482  myCurrentSocket->second->socket->sendExact(myOutputStorage);
484  } else {
485 #ifdef DEBUG_MULTI_CLIENTS
486  std::cout << " No input and no output stored (This is the next client)." << std::endl;
487 #endif
488  }
489 #ifdef DEBUG_MULTI_CLIENTS
490  std::cout << " resetting input storage and reading next command..." << std::endl;
491 #endif
492  // Read next request
494  myCurrentSocket->second->socket->receiveExact(myInputStorage);
495  }
496 
498  // dispatch command
499  const int cmd = dispatchCommand();
500 #ifdef DEBUG_MULTI_CLIENTS
501  std::cout << " Received command " << cmd << std::endl;
502 #endif
503  if (cmd == CMD_SIMSTEP) {
504 #ifdef DEBUG_MULTI_CLIENTS
505  std::cout << " Received command SIM_STEP, end turn for client " << myCurrentSocket->second->socket << std::endl;
506 #endif
507  done = true;
508  } else if (cmd == CMD_LOAD) {
509 #ifdef DEBUG_MULTI_CLIENTS
510  std::cout << " Received command LOAD." << std::endl;
511 #endif
512  load = true;
513  } else if (cmd == CMD_CLOSE) {
514 #ifdef DEBUG_MULTI_CLIENTS
515  std::cout << " Received command CLOSE." << std::endl;
516 #endif
517  closed = true;
518  }
519  }
520  }
521  if (done) {
522  // Clear vehicleStateChanges for this client -> For subsequent TraCI stepping
523  // that is performed within this SUMO step, no updates on vehicle states
524  // belonging to the last SUMO simulation step will be received by this client.
525  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myCurrentSocket->second->vehicleStateChanges.begin(); i != myCurrentSocket->second->vehicleStateChanges.end(); ++i) {
526  (*i).second.clear();
527  }
528  myCurrentSocket++;
529  } else if (load) {
530  myCurrentSocket = mySockets.end();
531  } else {
532  assert(closed);
533  // remove current socket and increment to next socket in ordering
535  }
536  }
537  if (!myLoadArgs.empty()) {
538 #ifdef DEBUG_MULTI_CLIENTS
539  std::cout << " Breaking loop to load new simulation." << std::endl;
540 #endif
541  break;
542  } else if (myDoCloseConnection) {
543 #ifdef DEBUG_MULTI_CLIENTS
544  std::cout << " Breaking loop because last client closed connection." << std::endl;
545 #endif
546  break;
547  }
548  SUMOTime nextT = nextTargetTime();
549  // minimal target time among clients should have been increased during the last loop through mySockets
550  // XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
551  // leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
552  // the next call is then usually simulationStep(step=1000) leading to no further increase
553  // and thus a failing assertion here.
554  //assert(myTargetTime < nextT || myDoCloseConnection);
555  myTargetTime = nextT;
556  }
557  // All clients are done with the current time step
558  // Reset myVehicleStateChanges
559  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
560  (*i).second.clear();
561  }
562 
563  } catch (std::invalid_argument& e) {
564  throw ProcessError(e.what());
565  } catch (libsumo::TraCIException& e) {
566  throw ProcessError(e.what());
567  } catch (tcpip::SocketException& e) {
568  throw ProcessError(e.what());
569  }
570 }
571 
572 
573 void
575  mySubscriptions.clear();
576  myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
577  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
578  myCurrentSocket->second->targetTime = myTargetTime;
579  }
583  std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i;
584  for (i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); i++) {
585  i->second.clear();
586  }
587  myCurrentSocket = mySockets.begin();
588 }
589 
590 
591 #ifdef HAVE_PYTHON
592 // ===========================================================================
593 // python functions (traciemb module)
594 // ===========================================================================
595 static PyObject*
596 traciemb_execute(PyObject* /* self */, PyObject* args) {
597  const char* msg;
598  int size;
599  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
600  return NULL;
601  }
602  std::string result = TraCIServer::execute(std::string(msg, size));
603  return Py_BuildValue("s#", result.c_str(), result.size());
604 }
605 
606 static PyMethodDef EmbMethods[] = {
607  {
608  "execute", traciemb_execute, METH_VARARGS,
609  "Execute the given TraCI command and return the result."
610  },
611  {NULL, NULL, 0, NULL}
612 };
613 
614 
615 std::string
616 TraCIServer::execute(std::string cmd) {
617  try {
618  assert(myInstance != 0);
621  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
623  }
625  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
626  } catch (std::invalid_argument& e) {
627  throw ProcessError(e.what());
628  } catch (libsumo::TraCIException& e) {
629  throw ProcessError(e.what());
630  } catch (tcpip::SocketException& e) {
631  throw ProcessError(e.what());
632  }
633 }
634 
635 
636 void
637 TraCIServer::runEmbedded(std::string pyFile) {
638  PyObject* pName, *pModule;
639  Py_Initialize();
640  Py_InitModule("traciemb", EmbMethods);
641  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
642  PyObject* sys_path, *path;
643  char pathstr[] = "path";
644  sys_path = PySys_GetObject(pathstr);
645  if (sys_path == NULL || !PyList_Check(sys_path)) {
646  throw ProcessError("Could not access python sys.path!");
647  }
648  path = PyString_FromString(FileHelpers::getFilePath(pyFile).c_str());
649  PyList_Insert(sys_path, 0, path);
650  Py_DECREF(path);
651  FILE* pFile = fopen(pyFile.c_str(), "r");
652  if (pFile == NULL) {
653  throw ProcessError("Failed to load \"" + pyFile + "\"!");
654  }
655  PyRun_SimpleFile(pFile, pyFile.c_str());
656  fclose(pFile);
657  } else {
658  pName = PyString_FromString(pyFile.c_str());
659  /* Error checking of pName left out */
660  pModule = PyImport_Import(pName);
661  Py_DECREF(pName);
662  if (pModule == NULL) {
663  PyErr_Print();
664  throw ProcessError("Failed to load \"" + pyFile + "\"!");
665  }
666  }
667  Py_Finalize();
668 }
669 #endif
670 
671 
672 std::map<int, TraCIServer::SocketInfo*>::iterator
674 #ifdef DEBUG_MULTI_CLIENTS
675  std::cout << " Removing socket " << myCurrentSocket->second->socket
676  << " (order " << myCurrentSocket->first << ")" << std::endl;
677 #endif
678 
679  if (mySockets.size() == 1) {
680  // Last client has disconnected
681  delete myCurrentSocket->second->socket;
682  mySockets.clear();
683  myCurrentSocket = mySockets.end();
684  return myCurrentSocket;
685  }
686 
687  const int currOrder = myCurrentSocket->first;
688  delete myCurrentSocket->second->socket;
689  myCurrentSocket++;
690  if (myCurrentSocket != mySockets.end()) {
691  const int nextOrder = myCurrentSocket->first;
692  mySockets.erase(currOrder);
693  myCurrentSocket = mySockets.find(nextOrder);
694  } else {
695  mySockets.erase(currOrder);
696  myCurrentSocket = mySockets.end();
697  }
698  return myCurrentSocket;
699 }
700 
701 
702 int
703 TraCIServer::readCommandID(int& commandStart, int& commandLength) {
704  commandStart = myInputStorage.position();
705  commandLength = myInputStorage.readUnsignedByte();
706  if (commandLength == 0) {
707  commandLength = myInputStorage.readInt();
708  }
710 }
711 
712 
713 int
715  int commandStart, commandLength;
716  int commandId = readCommandID(commandStart, commandLength);
717 #ifdef DEBUG_MULTI_CLIENTS
718  std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
719  << ", commandId = " << commandId << std::endl;
720 #endif
721  bool success = false;
722  // dispatch commands
723  if (myExecutors.find(commandId) != myExecutors.end()) {
724  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
725  } else {
726  switch (commandId) {
727  case CMD_GETVERSION:
728  success = commandGetVersion();
729  break;
730  case CMD_LOAD: {
731  std::vector<std::string> args;
733  return writeErrorStatusCmd(CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
734  }
735 #ifdef DEBUG_MULTI_CLIENTS
736  std::cout << " commandId == CMD_LOAD"
737  << ", args = " << toString(args) << std::endl;
738 #endif
739  try {
740  myLoadArgs = args;
741  success = true;
743  // XXX: This only cares for the client that issued the load command.
744  // Multiclient-load functionality is still to be implemented. Refs #3146.
745  myCurrentSocket->second->socket->sendExact(myOutputStorage);
747  } catch (libsumo::TraCIException& e) {
748  return writeErrorStatusCmd(CMD_LOAD, e.what(), myOutputStorage);
749  }
750  break;
751  }
752  case CMD_SIMSTEP: {
753  SUMOTime nextT = myInputStorage.readInt();
754  if (myAmEmbedded) {
755  if (nextT == 0) {
757  } else {
758  myTargetTime = nextT;
759  }
760  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
761  (*i).second.clear();
762  }
763  while (MSNet::getInstance()->getCurrentTimeStep() < myTargetTime) {
765  }
767  } else {
768  if (nextT == 0) {
769  myCurrentSocket->second->targetTime += DELTA_T;
770  } else {
771  myCurrentSocket->second->targetTime = nextT;
772  }
773 #ifdef DEBUG_MULTI_CLIENTS
774  std::cout << " commandId == CMD_SIMSTEP"
775  << ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
776 #endif
777  if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
778  // This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
779  // @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommandsUntilSimStep()
781  }
782  }
783  return commandId;
784  }
785  case CMD_CLOSE:
787  myCurrentSocket->second->socket->sendExact(myOutputStorage);
789  if (mySockets.size() == 1) {
790  // Last client has closed connection
791  myDoCloseConnection = true;
792  }
793  success = true;
794  break;
795  case CMD_SETORDER: {
796  const int order = myInputStorage.readInt();
797 #ifdef DEBUG_MULTI_CLIENTS
798  std::cout << " commandId == CMD_SETORDER"
799  << ", order index is " << order << std::endl;
800 #endif
801  if (order > MAX_ORDER) {
802  return writeErrorStatusCmd(CMD_SETORDER, "A set order command needs an int argument below " + toString(MAX_ORDER) + ".", myOutputStorage);
803  }
804  if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
805  return writeErrorStatusCmd(CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
806  }
807  // memorize reorder request (will only take effect in the next step)
808  mySocketReorderRequests[order] = myCurrentSocket->second;
809  success = true;
811  break;
812  }
828  success = addObjectVariableSubscription(commandId, false);
829  break;
845  success = addObjectVariableSubscription(commandId, true);
846  break;
847  default:
848  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
849  }
850  }
851  if (!success) {
852  while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
854  }
855  }
856  if ((int)myInputStorage.position() != commandStart + commandLength) {
857  std::ostringstream msg;
858  msg << "Wrong position in requestMessage after dispatching command.";
859  msg << " Expected command length was " << commandLength;
860  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
861  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
862  myDoCloseConnection = true;
863  }
864  return commandId;
865 }
866 
867 
868 // ---------- Server-internal command handling
869 bool
871  std::string sumoVersion = VERSION_STRING;
872  // Prepare response
873  tcpip::Storage answerTmp;
874  answerTmp.writeInt(TRACI_VERSION);
875  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
876  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
878  // command length
879  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
880  // command type
882  // and the parameter dependant part
883  myOutputStorage.writeStorage(answerTmp);
884  return true;
885 }
886 
887 
888 void
891 #ifdef DEBUG_MULTI_CLIENTS
892  std::cout << " postProcessSimulationStep() at time " << t << std::endl;
893 #endif
895  int noActive = 0;
896  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
897  const Subscription& s = *i;
901  if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
902  i = mySubscriptions.erase(i);
903  continue;
904  }
905  ++i;
906  if (s.beginTime > t) {
907  continue;
908  }
909  ++noActive;
910  }
912 #ifdef DEBUG_SUBSCRIPTIONS
913  std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
914  << "\n Nr. of active subscriptions = " << noActive << std::endl;
915 #endif
916  mySubscriptionCache.writeInt(noActive);
917 #ifdef DEBUG_SUBSCRIPTIONS
918  std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
919 #endif
920  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
921  const Subscription& s = *i;
922  if (s.beginTime > t) {
923  ++i;
924  continue;
925  }
926  tcpip::Storage into;
927  std::string errors;
928  bool ok = processSingleSubscription(s, into, errors);
929 #ifdef DEBUG_SUBSCRIPTIONS
930  std::cout << " Size of into-store for subscription " << s.id
931  << ": " << into.size() << std::endl;
932 #endif
934  if (ok) {
935  ++i;
936  } else {
937  i = mySubscriptions.erase(i);
938  }
939  }
941 #ifdef DEBUG_SUBSCRIPTIONS
942  std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
943 #endif
944 }
945 
946 
947 void
949 #ifdef DEBUG_MULTI_CLIENTS
950  std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
951  << " (-> intermediate TraCI step)."
952  << "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
953  << std::endl;
954 #endif
956 
957 // NOTE: the commented code would send an empty response
958 // myOutputStorage.writeInt(0);
959 // myCurrentSocket->second->socket->sendExact(myOutputStorage);
960 // myOutputStorage.reset();
962  // send results to active client
963  myCurrentSocket->second->socket->sendExact(myOutputStorage);
965 }
966 
967 
968 void
969 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
970  writeStatusCmd(commandId, status, description, myOutputStorage);
971 }
972 
973 
974 void
975 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
976  if (status == RTYPE_ERR) {
977  WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
978  } else if (status == RTYPE_NOTIMPLEMENTED) {
979  WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
980  }
981  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
982  outputStorage.writeUnsignedByte(commandId); // command type
983  outputStorage.writeUnsignedByte(status); // status
984  outputStorage.writeString(description); // description
985 }
986 
987 
988 bool
989 TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
990  writeStatusCmd(commandId, RTYPE_ERR, description, outputStorage);
991  return false;
992 }
993 
994 
995 void
997  tcpip::Storage writeInto;
998  std::string errors;
999  if (processSingleSubscription(s, writeInto, errors)) {
1001  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
1002  } else {
1003  bool needNewSubscription = true;
1004  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end(); ++i) {
1005  if (s.commandId == i->commandId && s.id == i->id &&
1006  s.beginTime == i->beginTime && s.endTime == i->endTime &&
1007  s.contextVars == i->contextVars && s.contextDomain == i->contextDomain && s.range == i->range) {
1008  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1009  for (std::vector<int>::const_iterator j = s.variables.begin(); j != s.variables.end(); ++j, ++k) {
1010  const int offset = (int)(std::find(i->variables.begin(), i->variables.end(), *j) - i->variables.begin());
1011  if (offset == (int)i->variables.size() || i->parameters[offset] != *k) {
1012  i->variables.push_back(*j);
1013  i->parameters.push_back(*k);
1014  }
1015  }
1016  needNewSubscription = false;
1017  break;
1018  }
1019  }
1020  if (needNewSubscription) {
1021  mySubscriptions.push_back(s);
1022  // Add new subscription to subscription cache (note: seems a bit inefficient)
1024  // copy new subscription into cache
1025  int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1026  tcpip::Storage tmp;
1027  tmp.writeInt(noActive);
1028  while (mySubscriptionCache.valid_pos()) {
1030  }
1031  tmp.writeStorage(writeInto);
1034  }
1035  }
1037  }
1038  } else {
1039  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
1040  }
1041  myOutputStorage.writeStorage(writeInto);
1042 }
1043 
1044 
1045 void
1046 TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1047  bool found = false;
1048  for (std::vector<Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1049  if ((*j).id == id && (*j).commandId == commandId && (domain < 0 || (*j).contextDomain == domain)) {
1050  j = mySubscriptions.erase(j);
1051  found = true;
1052  continue;
1053  }
1054  ++j;
1055  }
1056  // try unsubscribe
1057  if (found) {
1058  writeStatusCmd(commandId, RTYPE_OK, "");
1059  } else {
1060  writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
1061  }
1062 }
1063 
1064 
1065 bool
1066 TraCIServer::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
1067  Position p;
1068  switch (domain) {
1071  shape.push_back(p);
1072  return true;
1073  }
1074  break;
1076  break;
1078  break;
1080  if (TraCIServerAPI_Lane::getShape(id, shape)) {
1081  return true;
1082  }
1083  break;
1086  shape.push_back(p);
1087  return true;
1088  }
1089  break;
1092  shape.push_back(p);
1093  return true;
1094  }
1095  break;
1097  break;
1099  break;
1101  if (TraCIServerAPI_POI::getPosition(id, p)) {
1102  shape.push_back(p);
1103  return true;
1104  }
1105  return false;
1107  if (TraCIServerAPI_Polygon::getShape(id, shape)) {
1108  return true;
1109  }
1110  break;
1113  shape.push_back(p);
1114  return true;
1115  }
1116  break;
1118  if (TraCIServerAPI_Edge::getShape(id, shape)) {
1119  return true;
1120  }
1121  break;
1123  return false;
1125  break;
1126  default:
1127  break;
1128  }
1129  return false;
1130 }
1131 
1132 bool
1134  std::string& errors) {
1135  bool ok = true;
1136  tcpip::Storage outputStorage;
1137  const int getCommandId = s.contextVars ? s.contextDomain : s.commandId - 0x30;
1138  std::set<std::string> objIDs;
1139  if (s.contextVars) {
1140  PositionVector shape;
1141  if (!findObjectShape(s.commandId, s.id, shape)) {
1142  return false;
1143  }
1145  } else {
1146  objIDs.insert(s.id);
1147  }
1148  const int numVars = s.contextVars && s.variables.size() == 1 && s.variables[0] == ID_LIST ? 0 : (int)s.variables.size();
1149  for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1150  if (s.contextVars) {
1151  outputStorage.writeString(*j);
1152  }
1153  if (numVars > 0) {
1154  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1155  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1156  tcpip::Storage message;
1157  message.writeUnsignedByte(*i);
1158  message.writeString(*j);
1159  message.writePacket(*k);
1160  tcpip::Storage tmpOutput;
1161  if (myExecutors.find(getCommandId) != myExecutors.end()) {
1162  ok &= myExecutors[getCommandId](*this, message, tmpOutput);
1163  } else {
1164  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1165  ok = false;
1166  }
1167  // copy response part
1168  if (ok) {
1169  int length = tmpOutput.readUnsignedByte();
1170  while (--length > 0) {
1171  tmpOutput.readUnsignedByte();
1172  }
1173  int lengthLength = 1;
1174  length = tmpOutput.readUnsignedByte();
1175  if (length == 0) {
1176  lengthLength = 5;
1177  length = tmpOutput.readInt();
1178  }
1179  //read responseType
1180  tmpOutput.readUnsignedByte();
1181  int variable = tmpOutput.readUnsignedByte();
1182  std::string id = tmpOutput.readString();
1183  outputStorage.writeUnsignedByte(variable);
1184  outputStorage.writeUnsignedByte(RTYPE_OK);
1185  length -= (lengthLength + 1 + 4 + (int)id.length());
1186  while (--length > 0) {
1187  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
1188  }
1189  } else {
1190  //read length
1191  tmpOutput.readUnsignedByte();
1192  //read cmd
1193  tmpOutput.readUnsignedByte();
1194  //read status
1195  tmpOutput.readUnsignedByte();
1196  std::string msg = tmpOutput.readString();
1197  outputStorage.writeUnsignedByte(*i);
1198  outputStorage.writeUnsignedByte(RTYPE_ERR);
1199  outputStorage.writeUnsignedByte(TYPE_STRING);
1200  outputStorage.writeString(msg);
1201  errors = errors + msg;
1202  }
1203  }
1204  }
1205  }
1206  int length = (1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size();
1207  if (s.contextVars) {
1208  length += 4;
1209  }
1210  writeInto.writeUnsignedByte(0); // command length -> extended
1211  writeInto.writeInt(length);
1212  writeInto.writeUnsignedByte(s.commandId + 0x10);
1213  writeInto.writeString(s.id);
1214  if (s.contextVars) {
1215  writeInto.writeUnsignedByte(s.contextDomain);
1216  }
1217  writeInto.writeUnsignedByte(numVars);
1218  if (s.contextVars) {
1219  writeInto.writeInt((int)objIDs.size());
1220  }
1221  if (!s.contextVars || objIDs.size() != 0) {
1222  writeInto.writeStorage(outputStorage);
1223  }
1224  return ok;
1225 }
1226 
1227 
1228 bool
1229 TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1230  const SUMOTime beginTime = myInputStorage.readInt();
1231  const SUMOTime endTime = myInputStorage.readInt();
1232  const std::string id = myInputStorage.readString();
1233  const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1234  const double range = hasContext ? myInputStorage.readDouble() : 0.;
1235  const int num = myInputStorage.readUnsignedByte();
1236  std::vector<int> variables;
1237  std::vector<std::vector<unsigned char> > parameters;
1238  for (int i = 0; i < num; ++i) {
1239  const int varID = myInputStorage.readUnsignedByte();
1240  variables.push_back(varID);
1241  parameters.push_back(std::vector<unsigned char>());
1242  for (int j = 0; j < myParameterSizes[varID]; j++) {
1243  parameters.back().push_back(myInputStorage.readChar());
1244  }
1245  }
1246  // check subscribe/unsubscribe
1247  if (variables.size() == 0) {
1248  removeSubscription(commandId, id, -1);
1249  return true;
1250  }
1251  // process subscription
1252  Subscription s(commandId, id, variables, parameters, beginTime, endTime, hasContext, domain, range);
1254  return true;
1255 }
1256 
1257 
1258 void
1260  if (tempMsg.size() < 254) {
1261  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1262  } else {
1263  outputStorage.writeUnsignedByte(0); // command length -> extended
1264  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1265  }
1266  outputStorage.writeStorage(tempMsg);
1267 }
1268 
1269 
1270 bool
1272  if (inputStorage.readUnsignedByte() != TYPE_INTEGER) {
1273  return false;
1274  }
1275  into = inputStorage.readInt();
1276  return true;
1277 }
1278 
1279 
1280 bool
1282  if (inputStorage.readUnsignedByte() != TYPE_DOUBLE) {
1283  return false;
1284  }
1285  into = inputStorage.readDouble();
1286  return true;
1287 }
1288 
1289 
1290 bool
1291 TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1292  if (inputStorage.readUnsignedByte() != TYPE_STRING) {
1293  return false;
1294  }
1295  into = inputStorage.readString();
1296  return true;
1297 }
1298 
1299 
1300 bool
1301 TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1302  if (inputStorage.readUnsignedByte() != TYPE_STRINGLIST) {
1303  return false;
1304  }
1305  into = inputStorage.readStringList();
1306  return true;
1307 }
1308 
1309 
1310 bool
1312  if (inputStorage.readUnsignedByte() != TYPE_COLOR) {
1313  return false;
1314  }
1315  into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1316  into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1317  into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1318  into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1319  return true;
1320 }
1321 
1322 
1323 bool
1325  if (inputStorage.readUnsignedByte() != POSITION_2D) {
1326  return false;
1327  }
1328  into.x = inputStorage.readDouble();
1329  into.y = inputStorage.readDouble();
1330  into.z = 0;
1331  return true;
1332 }
1333 
1334 
1335 bool
1337  if (inputStorage.readUnsignedByte() != TYPE_BOUNDINGBOX) {
1338  return false;
1339  }
1340  const double xmin = inputStorage.readDouble();
1341  const double ymin = inputStorage.readDouble();
1342  const double xmax = inputStorage.readDouble();
1343  const double ymax = inputStorage.readDouble();
1344  into.set(xmin, ymin, xmax, ymax);
1345  return true;
1346 }
1347 
1348 
1349 bool
1351  if (inputStorage.readUnsignedByte() != TYPE_BYTE) {
1352  return false;
1353  }
1354  into = inputStorage.readByte();
1355  return true;
1356 }
1357 
1358 
1359 bool
1361  if (inputStorage.readUnsignedByte() != TYPE_UBYTE) {
1362  return false;
1363  }
1364  into = inputStorage.readUnsignedByte();
1365  return true;
1366 }
1367 
1368 
1369 bool
1371  if (inputStorage.readUnsignedByte() != TYPE_POLYGON) {
1372  return false;
1373  }
1374  into.clear();
1375  int noEntries = inputStorage.readUnsignedByte();
1376  PositionVector shape;
1377  for (int i = 0; i < noEntries; ++i) {
1378  double x = inputStorage.readDouble();
1379  double y = inputStorage.readDouble();
1380  into.push_back(Position(x, y));
1381  }
1382  return true;
1383 }
1384 
1385 void
1387  myTargetTime = targetTime;
1388  for (auto& s : mySockets) {
1389  s.second->targetTime = targetTime;
1390  }
1391 }
1392 
1393 #endif
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa3: Get Lane Variable)
bool processSingleSubscription(const TraCIServer::Subscription &s, tcpip::Storage &writeInto, std::string &errors)
The vehicle has departed (was inserted into the network)
Definition: MSNet.h:486
unsigned char g
Definition: TraCIDefs.h:79
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:66
#define CMD_SUBSCRIBE_VEHICLE_CONTEXT
#define CMD_SUBSCRIBE_LANE_VARIABLE
static void collectObjectsInRange(int domain, const PositionVector &shape, double range, std::set< std::string > &into)
Definition: Helper.cpp:226
tcpip::Storage mySubscriptionCache
The last timestep&#39;s subscription results.
Definition: TraCIServer.h:378
bool readTypeCheckingColor(tcpip::Storage &inputStorage, libsumo::TraCIColor &into)
Reads the value type and a color, verifying the type.
bool findObjectShape(int domain, const std::string &id, PositionVector &shape)
#define CMD_SUBSCRIBE_LANEAREA_VARIABLE
SUMOTime nextTargetTime() const
get the minimal next target time among all clients
bool contextVars
Whether the subscription is a context subscription (variable subscription otherwise) ...
Definition: TraCIServer.h:425
double range
The range of the context.
Definition: TraCIServer.h:429
#define CMD_GET_TL_VARIABLE
#define CMD_SUBSCRIBE_JUNCTION_CONTEXT
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc3: Change Lane State)
#define CMD_GET_VEHICLE_VARIABLE
virtual ~TraCIServer()
Destructor.
#define CMD_SUBSCRIBE_SIM_CONTEXT
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)
std::vector< std::vector< unsigned char > > parameters
The parameters for the subscribed variables.
Definition: TraCIServer.h:419
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
virtual unsigned int position() const
#define TYPE_UBYTE
#define RTYPE_OK
SUMOTime beginTime
The begin time of the subscription.
Definition: TraCIServer.h:421
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 writeto.
Definition: TraCIServer.h:375
#define TYPE_POLYGON
StorageType::size_type size() const
Definition: storage.h:115
#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 getPosition(const std::string &id, Position &p)
Returns the named vehicle&#39;s position.
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xab: Get Simulation Variable)
#define MAX_ORDER
void set(double xmin, double ymin, double xmax, double ymax)
Sets the boundary to the given values.
Definition: Boundary.cpp:341
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:167
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:389
void sendOutputToAll() const
send out subscription results (actually just the content of myOutputStorage) to clients which will ac...
SUMOTime DELTA_T
Definition: SUMOTime.cpp:39
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
tcpip::Storage myInputStorage
The storage to read from.
Definition: TraCIServer.h:372
#define CMD_GET_POLYGON_VARIABLE
virtual void writePacket(unsigned char *packet, int length)
#define CMD_SUBSCRIBE_JUNCTION_VARIABLE
Representation of a subscription.
Definition: TraCIServer.h:394
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.
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
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:253
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:832
#define CMD_GET_ROUTE_VARIABLE
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:47
#define CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT
virtual void writeInt(int)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:199
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:64
#define TYPE_STRING
#define SIMTIME
Definition: SUMOTime.h:71
virtual int readUnsignedByte()
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)
static bool getPosition(const std::string &id, Position &p)
Returns the named inductive loop&#39;s position.
static bool getPosition(const std::string &id, Position &p)
Returns the named persons&#39;s position.
static bool myDoCloseConnection
Whether the connection was set to be to close.
Definition: TraCIServer.h:353
std::map< int, SocketInfo * >::iterator removeCurrentSocket()
removes myCurrentSocket from mySockets and returns an iterator pointing to the next member according ...
The vehicles starts to stop.
Definition: MSNet.h:500
std::map< int, CmdExecutor > myExecutors
Map of commandIds -> their executors; applicable if the executor applies to the method footprint...
Definition: TraCIServer.h:384
#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)
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to)
Called if a vehicle changes its state.
bool readTypeCheckingBoundary(tcpip::Storage &inputStorage, Boundary &into)
Reads the value type and a 2D bounding box, verifying the type.
#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:79
#define CMD_GET_VEHICLETYPE_VARIABLE
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
The vehicle got a new route.
Definition: MSNet.h:494
The vehicle arrived at his destination (is deleted)
Definition: MSNet.h:492
StorageType::const_iterator end() const
Definition: storage.h:118
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
The vehicles starts to park.
Definition: MSNet.h:496
int commandId
commandIdArg The command id of the subscription
Definition: TraCIServer.h:413
std::vector< Subscription > mySubscriptions
The list of known, still valid subscriptions.
Definition: TraCIServer.h:434
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xce: Change Person State)
Representation of a vehicle.
Definition: SUMOVehicle.h:66
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
virtual int readInt()
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:768
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:45
std::string id
The id of the object that is subscribed.
Definition: TraCIServer.h:415
#define CMD_GET_POI_VARIABLE
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE
A list of positions.
std::vector< int > variables
The subscribed variables.
Definition: TraCIServer.h:417
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT
#define CMD_SET_VEHICLETYPE_VARIABLE
virtual void writeByte(int)
#define TYPE_BOUNDINGBOX
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:79
#define CMD_SUBSCRIBE_GUI_VARIABLE
#define CMD_GET_LANE_VARIABLE
#define CMD_SUBSCRIBE_LANEAREA_CONTEXT
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:46
T MIN2(T a, T b)
Definition: StdDefs.h:67
The vehicle started to teleport.
Definition: MSNet.h:488
#define CMD_GET_SIM_VARIABLE
virtual std::string readString()
#define CMD_GET_EDGE_VARIABLE
unsigned char r
Definition: TraCIDefs.h:79
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:75
#define CMD_SET_POI_VARIABLE
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:350
static bool getPosition(const std::string &id, Position &p)
Returns the named PoI&#39;s position.
#define CMD_SUBSCRIBE_TL_CONTEXT
The vehicle ends to park.
Definition: MSNet.h:498
#define CMD_SUBSCRIBE_EDGE_CONTEXT
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:231
#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:69
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
#define CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE
void writeResponseWithLength(tcpip::Storage &outputStorage, tcpip::Storage &tempMsg)
VehicleState
Definition of a vehicle state.
Definition: MSNet.h:482
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:381
The vehicle was built, but has not yet departed.
Definition: MSNet.h:484
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
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.
static bool getShape(const std::string &id, PositionVector &shape)
Returns the named edge&#39;s shape.
virtual void writeString(const std::string &s)
#define RTYPE_NOTIMPLEMENTED
virtual const char * what() const
Definition: socket.h:70
#define TYPE_DOUBLE
std::string toHex(const T i, std::streamsize numDigits=0)
Definition: ToString.h:65
static bool getPosition(const std::string &id, Position &p)
Returns the named junction&#39;s position.
#define CMD_SUBSCRIBE_VEHICLE_VARIABLE
#define CMD_SUBSCRIBE_PERSON_CONTEXT
std::map< int, SocketInfo * >::iterator myCurrentSocket
The currently active client socket.
Definition: TraCIServer.h:366
#define TYPE_BYTE
#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:84
SUMOTime myTargetTime
The time step to reach until processing the next commands.
Definition: TraCIServer.h:369
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa6: Get Route Variable)
The vehicle ends to stop.
Definition: MSNet.h:502
StorageType::const_iterator begin() const
Definition: storage.h:117
bool readTypeCheckingPosition2D(tcpip::Storage &inputStorage, libsumo::TraCIPosition &into)
Reads the value type and a 2D position, verifying the type.
#define CMD_SETORDER
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa1: Get MeMeDetector Variable)
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
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:360
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:363
long long int SUMOTime
Definition: TraCIDefs.h:51
static std::string getFilePath(const std::string &path)
Removes the file information from the given path.
Definition: FileHelpers.cpp:71
#define CMD_SET_PERSON_VARIABLE
void simulationStep()
Performs a single simulation step.
Definition: MSNet.cpp:439
int contextDomain
The domain ID of the context.
Definition: TraCIServer.h:427
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:200
A 3D-position.
Definition: TraCIDefs.h:71
#define RTYPE_ERR
void initialiseSubscription(const Subscription &s)
#define TYPE_INTEGER
#define ID_LIST
#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:443
The vehicle ended being teleported.
Definition: MSNet.h:490
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
#define CMD_SIMSTEP
virtual int readByte()
static bool getShape(const std::string &id, PositionVector &shape)
Returns the named polygons&#39;s shape.
bool readTypeCheckingByte(tcpip::Storage &inputStorage, int &into)
Reads the value type and a byte, verifying the type.
tcpip::Socket * myServerSocket
The server socket.
Definition: TraCIServer.h:356
SUMOTime endTime
The end time of the subscription.
Definition: TraCIServer.h:423
#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)
static bool getShape(const std::string &id, PositionVector &shape)
Returns the named lane&#39;s shape.
std::map< int, int > myParameterSizes
Map of variable ids to the size of the parameter in bytes.
Definition: TraCIServer.h:387
void checkClientOrdering()
Called once after connection of all clients for executing SET_ORDER (and possibly prior GET_VERSION) ...