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
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
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)
#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
#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
#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
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
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
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
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
virtual const char * what() const
Definition: socket.h:70
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
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:253
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
virtual unsigned int position() const
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 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
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
StorageType::size_type size() const
Definition: storage.h:115
#define CMD_SUBSCRIBE_VEHICLETYPE_VARIABLE
void writeResponseWithLength(tcpip::Storage &outputStorage, tcpip::Storage &tempMsg)
#define VERSION_STRING
Definition: config.h:210
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
#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
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: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
bool readTypeCheckingPosition2D(tcpip::Storage &inputStorage, libsumo::TraCIPosition &into)
Reads the value type and a 2D position, verifying the type.
#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)
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) ...