SUMO - Simulation of Urban MObility
TraCIServer.cpp
Go to the documentation of this file.
1 /****************************************************************************/
17 // TraCI server used to control sumo by a remote TraCI client (e.g., ns2)
18 /****************************************************************************/
19 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
20 // Copyright (C) 2007-2017 DLR (http://www.dlr.de/) and contributors
21 /****************************************************************************/
22 //
23 // This file is part of SUMO.
24 // SUMO is free software: you can redistribute it and/or modify
25 // it under the terms of the GNU General Public License as published by
26 // the Free Software Foundation, either version 3 of the License, or
27 // (at your option) any later version.
28 //
29 /****************************************************************************/
30 
31 // ===========================================================================
32 // included modules
33 // ===========================================================================
34 #ifdef _MSC_VER
35 #include <windows_config.h>
36 #else
37 #include <config.h>
38 #endif
39 
40 #ifdef HAVE_VERSION_H
41 #include <version.h>
42 #endif
43 
44 #ifndef NO_TRACI
45 
46 #ifdef HAVE_PYTHON
47 #include <Python.h>
48 #endif
49 
50 #include <string>
51 #include <map>
52 #include <iostream>
53 #include <algorithm>
54 #include <foreign/tcpip/socket.h>
55 #include <foreign/tcpip/storage.h>
56 #include <utils/common/SUMOTime.h>
64 #include <utils/xml/XMLSubSys.h>
65 #include <microsim/MSNet.h>
67 #include <microsim/MSVehicle.h>
68 #include <microsim/MSEdge.h>
71 #include <microsim/MSJunction.h>
72 #include <microsim/MSEdgeControl.h>
73 #include <microsim/MSLane.h>
74 #include <microsim/MSGlobals.h>
76 #include "lib/TraCI.h"
77 #include "TraCIConstants.h"
78 #include "TraCIServer.h"
81 #include "TraCIServerAPI_Lane.h"
84 #include "TraCIServerAPI_TLS.h"
85 #include "TraCIServerAPI_Vehicle.h"
87 #include "TraCIServerAPI_Route.h"
88 #include "TraCIServerAPI_POI.h"
89 #include "TraCIServerAPI_Polygon.h"
90 #include "TraCIServerAPI_Edge.h"
92 #include "TraCIServerAPI_Person.h"
93 
94 
95 // ===========================================================================
96 // debug constants
97 // ===========================================================================
98 //#define DEBUG_MULTI_CLIENTS
99 //#define DEBUG_SUBSCRIPTIONS
100 
101 
102 // ===========================================================================
103 // static member definitions
104 // ===========================================================================
107 
108 
109 // ===========================================================================
110 // method definitions
111 // ===========================================================================
112 TraCIServer::TraCIServer(const SUMOTime begin, const int port, const int numClients)
113  : myServerSocket(0),
114  myTargetTime(begin),
115  myAmEmbedded(port == 0),
116  myLaneTree(0) {
117 #ifdef DEBUG_MULTI_CLIENTS
118  std::cout << "Creating new TraCIServer for " << numClients << " clients on port " << port << "." << std::endl;
119 #endif
120  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
121  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
122  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
123  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
124  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
125  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
126  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
127  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
128  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
129  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
130 
134 
156 
158 
159  myDoCloseConnection = false;
160 
161  // display warning if internal lanes are not used
163  WRITE_WARNING("Starting TraCI without using internal lanes!");
164  MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
165  MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
166  }
167 
168  if (!myAmEmbedded) {
169  try {
170  WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
171  myServerSocket = new tcpip::Socket(port);
172  while ((int)mySockets.size() < numClients) {
173  int index = (int)mySockets.size() + MAX_ORDER + 1;
174  mySockets[index] = new SocketInfo(myServerSocket->accept(true), begin);
175  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
176  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
177  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
178  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
179  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
180  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
181  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
182  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
183  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
184  mySockets[index]->vehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
185  }
186  // When got here, all clients have connected
187  if (numClients > 1) {
189  }
190  // set myCurrentSocket != mySockets.end() to indicate that this is the first step in processCommandsUntilSimStep()
191  myCurrentSocket = mySockets.begin();
192  } catch (tcpip::SocketException& e) {
193  throw ProcessError(e.what());
194  }
195  }
196 }
197 
198 
200  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
201  delete myCurrentSocket->second;
202  }
203  delete myServerSocket;
204  cleanup();
205 }
206 
207 
208 // ---------- Initialisation and Shutdown
209 void
210 TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
211  if (myInstance == 0 && !myDoCloseConnection && (OptionsCont::getOptions().getInt("remote-port") != 0
212 #ifdef HAVE_PYTHON
213  || OptionsCont::getOptions().isSet("python-script")
214 #endif
215  )) {
216  myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
217  OptionsCont::getOptions().getInt("remote-port"),
218  OptionsCont::getOptions().getInt("num-clients"));
219  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
220  myInstance->myExecutors[i->first] = i->second;
221  }
222  }
223  if (myInstance != 0) {
224  // maybe net was deleted and built again
226  }
227 }
228 
229 
230 void
232  if (myInstance == 0) {
233  return;
234  }
235  delete myInstance;
236  myInstance = 0;
237  myDoCloseConnection = true;
238 }
239 
240 
241 bool
243  return myDoCloseConnection;
244 }
245 
246 
247 void
248 TraCIServer::setVTDControlled(MSVehicle* v, Position xyPos, MSLane* l, double pos, double posLat, double angle,
249  int edgeOffset, ConstMSEdgeVector route, SUMOTime t) {
250  myVTDControlledVehicles[v->getID()] = v;
251  v->getInfluencer().setVTDControlled(xyPos, l, pos, posLat, angle, edgeOffset, route, t);
252 }
253 
254 
255 void
257  for (std::map<std::string, MSVehicle*>::const_iterator i = myVTDControlledVehicles.begin(); i != myVTDControlledVehicles.end(); ++i) {
258  if (MSNet::getInstance()->getVehicleControl().getVehicle((*i).first) != 0) {
259  (*i).second->getInfluencer().postProcessVTD((*i).second);
260  } else {
261  WRITE_WARNING("Vehicle '" + (*i).first + "' was removed though being controlled by VTD");
262  }
263  }
264  myVTDControlledVehicles.clear();
265 }
266 
267 
268 // ---------- Initialisation and Shutdown
269 
270 
271 void
273  if (!myDoCloseConnection) {
274  myVehicleStateChanges[to].push_back(vehicle->getID());
275  if (!myAmEmbedded) {
276  for (std::map<int, SocketInfo*>::iterator i = mySockets.begin(); i != mySockets.end(); ++i) {
277  i->second->vehicleStateChanges[to].push_back(vehicle->getID());
278  }
279  }
280  }
281 }
282 
283 void
285 #ifdef DEBUG_MULTI_CLIENTS
286  std::cout << "Checking client order requests." << std::endl;
287 #endif
288  // check for SET_ORDER commands queued by connected clients
289  // In multiclient cas it is mandatory that SET_ORDER is sent as the first command (or directly after GET_VERSION)
290  myCurrentSocket = mySockets.begin();
291  while (myCurrentSocket != mySockets.end()) {
292 #ifdef DEBUG_MULTI_CLIENTS
293  std::cout << " Socket " << myCurrentSocket->second->socket << ":" << std::endl;
294 #endif
295 // bool clientUnordered = true;
296 #ifdef _MSC_VER
297 #pragma warning(push)
298 #pragma warning(disable: 4127) // do not warn about constant conditional expression
299 #endif
300  while (true) {
301 #ifdef _MSC_VER
302 #pragma warning(pop)
303 #endif
305  myCurrentSocket->second->socket->receiveExact(myInputStorage);
306  int commandStart, commandLength;
307  int commandId = readCommandID(commandStart, commandLength);
308 #ifdef DEBUG_MULTI_CLIENTS
309  std::cout << " received command " << commandId << std::endl;
310 #endif
311  // Whether the received command is a permitted command for the initialization phase.
312  // Currently, getVersion and setOrder are permitted.
313  bool initCommand = commandId == CMD_SETORDER || commandId == CMD_GETVERSION;
314  if (initCommand) {
315 #ifdef DEBUG_MULTI_CLIENTS
316  std::cout << " Init command. Sending response." << std::endl;
317 #endif
318  // reset input storage to initial state before reading the commandId
319  // (ugly, but we can't just reset the store's iter_ from here)
320  // Giving the commandId to dispatch command didn't work either
321  tcpip::Storage tmp;
324  myInputStorage.writeUnsignedByte(commandLength);
327 
328  // Handle initialization command completely
329  dispatchCommand();
330  myCurrentSocket->second->socket->sendExact(myOutputStorage);
332  } else {
333 #ifdef DEBUG_MULTI_CLIENTS
334  std::cout << " Client " << myCurrentSocket->second->socket << " did not set order initially." << std::endl;
335 #endif
336  throw ProcessError("Execution order (CMD_SETORDER) was not set for all TraCI clients in pre-execution phase.");
337  }
338  if (commandId == CMD_SETORDER) {
339  // This is what we have waited for.
340  break;
341  }
342  }
343  ++myCurrentSocket;
344  }
345 }
346 
347 
348 void
350  // Process reordering requests
351  if (mySocketReorderRequests.size() > 0) {
352  // process reordering requests
353  std::map<int, SocketInfo*>::const_iterator i = mySocketReorderRequests.begin();
354  std::map<int, SocketInfo*>::iterator j;
355 #ifdef DEBUG_MULTI_CLIENTS
356  std::cout << SIMTIME << " Current socket ordering:\n";
357  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
358  std::cout << " " << j->first << ": " << j->second->socket << "\n";
359  }
360  std::cout << "Reordering requests:\n";
361  for (i = mySocketReorderRequests.begin(); i != mySocketReorderRequests.end(); ++i) {
362  std::cout << " Socket " << i->second->socket << " -> " << i->first << "\n";
363  }
364  i = mySocketReorderRequests.begin();
365 #endif
366  while (i != mySocketReorderRequests.end()) {
367  j = mySockets.begin();
368  while (j != mySockets.end()) {
369  if (j->second->socket == i->second->socket) {
370  break;
371  } else {
372  j++;
373  }
374  }
375  assert(j != mySockets.end());
376  mySockets.erase(j);
377  mySockets[i->first] = i->second;
378  ++i;
379  }
380  mySocketReorderRequests.clear();
381 #ifdef DEBUG_MULTI_CLIENTS
382  std::cout << "New socket ordering:\n";
383  for (j = mySockets.begin(); j != mySockets.end(); ++j) {
384  std::cout << " " << j->first << ": " << j->second->socket << "\n";
385  }
386  std::cout << std::endl;
387 #endif
388  }
389 }
390 
391 
392 SUMOTime
394 #ifdef DEBUG_MULTI_CLIENTS
395  std::cout << "\n Determining new target time..." << std::endl;
396  if (mySockets.size() == 0) {
397  std::cout << " All clients have disconnected." << std::endl;
398  }
399 #endif
400  std::map<int, SocketInfo*>::const_iterator i;
402  for (i = mySockets.begin(); i != mySockets.end(); ++i) {
403 #ifdef DEBUG_MULTI_CLIENTS
404  std::cout << " target time for client " << i->second->socket << ": " << i->second->targetTime << "\n";
405 #endif
406  targetTime = MIN2(targetTime, i->second->targetTime);
407  }
408 #ifdef DEBUG_MULTI_CLIENTS
409  std::cout << std::endl;
410 #endif
411  return targetTime;
412 }
413 
414 
415 // send out subscription results to clients which will act in this step (i.e. with client target time <= myTargetTime)
416 void
418 #ifdef DEBUG_MULTI_CLIENTS
419  std::cout << "\n Sending subscription results to clients:\n";
420 #endif
421  std::map<int, SocketInfo*>::const_iterator i = mySockets.begin();
422  while (i != mySockets.end()) {
423  if (i->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
424  // this client will become active before the next SUMO step. Provide subscription results.
425  i->second->socket->sendExact(myOutputStorage);
426 #ifdef DEBUG_MULTI_CLIENTS
427  std::cout << i->second->socket << "\n";
428 #endif
429  }
430  ++i;
431  }
432 #ifdef DEBUG_MULTI_CLIENTS
433  std::cout << std::endl;
434 #endif
435 }
436 
437 
438 void
440 #ifdef DEBUG_MULTI_CLIENTS
441  std::cout << SIMTIME << " processCommandsUntilSimStep(step = " << step << "):\n" << std::endl;
442 #endif
443  try {
444  const bool firstStep = myCurrentSocket != mySockets.end();
445  // update client order if requested
447  if (!firstStep) {
448  // 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)
449  // update subscription results
451  // Send out subscription results to clients which will act in this SUMO step (i.e. with client target time <= current sumo timestep end)
452  sendOutputToAll();
454  }
455 
456  // determine minimal next target time among clients
458 
459  if (myAmEmbedded || step < myTargetTime) {
460 #ifdef DEBUG_MULTI_CLIENTS
461  if (step < myTargetTime) {
462  std::cout << " next target time is larger than next SUMO simstep (" << step << "). Returning from processCommandsUntilSimStep()." << std::endl;
463  }
464 #endif
465  return;
466  }
467 
468  // Simulation should run until
469  // 1. end time reached or
470  // 2. got CMD_CLOSE or
471  // 3. got CMD_LOAD or
472  // 4. Client closes socket connection
473  while (!myDoCloseConnection && myTargetTime <= (MSNet::getInstance()->getCurrentTimeStep())) {
474 #ifdef DEBUG_MULTI_CLIENTS
475  std::cout << " Next target time: " << myTargetTime << std::endl;
476 #endif
477  // Iterate over clients and process communication for the ones with target time == myTargetTime
478  myCurrentSocket = mySockets.begin();
479  while (myCurrentSocket != mySockets.end()) {
480 #ifdef DEBUG_MULTI_CLIENTS
481  std::cout << " current socket: " << myCurrentSocket->second->socket
482  << " with target time " << myCurrentSocket->second->targetTime
483  << std::endl;
484 #endif
485 
486  if (myCurrentSocket->second->targetTime > myTargetTime) {
487  // this client must wait
488 #ifdef DEBUG_MULTI_CLIENTS
489  std::cout << " skipping client " << myCurrentSocket->second->socket
490  << " with target time " << myCurrentSocket->second->targetTime << std::endl;
491 #endif
492  myCurrentSocket++;
493  continue;
494  }
495  bool done = false;
496  bool closed = false;
497  bool load = false;
498  while (!done && !closed && !load) {
499  if (!myInputStorage.valid_pos()) {
500  // have read request completely, send response if adequate
501  if (myOutputStorage.size() > 0) {
502 #ifdef DEBUG_MULTI_CLIENTS
503  std::cout << " sending response..." << std::endl;
504 #endif
505  // send response to previous query
506  myCurrentSocket->second->socket->sendExact(myOutputStorage);
508  } else {
509 #ifdef DEBUG_MULTI_CLIENTS
510  std::cout << " No input and no output stored (This is the next client)." << std::endl;
511 #endif
512  }
513 #ifdef DEBUG_MULTI_CLIENTS
514  std::cout << " resetting input storage and reading next command..." << std::endl;
515 #endif
516  // Read next request
518  myCurrentSocket->second->socket->receiveExact(myInputStorage);
519  }
520 
522  // dispatch command
523  const int cmd = dispatchCommand();
524 #ifdef DEBUG_MULTI_CLIENTS
525  std::cout << " Received command " << cmd << std::endl;
526 #endif
527  if (cmd == CMD_SIMSTEP) {
528 #ifdef DEBUG_MULTI_CLIENTS
529  std::cout << " Received command SIM_STEP, end turn for client " << myCurrentSocket->second->socket << std::endl;
530 #endif
531  done = true;
532  } else if (cmd == CMD_LOAD) {
533 #ifdef DEBUG_MULTI_CLIENTS
534  std::cout << " Received command LOAD." << std::endl;
535 #endif
536  load = true;
537  } else if (cmd == CMD_CLOSE) {
538 #ifdef DEBUG_MULTI_CLIENTS
539  std::cout << " Received command CLOSE." << std::endl;
540 #endif
541  closed = true;
542  }
543  }
544  }
545  if (done) {
546  // Clear vehicleStateChanges for this client -> For subsequent TraCI stepping
547  // that is performed within this SUMO step, no updates on vehicle states
548  // belonging to the last SUMO simulation step will be received by this client.
549  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myCurrentSocket->second->vehicleStateChanges.begin(); i != myCurrentSocket->second->vehicleStateChanges.end(); ++i) {
550  (*i).second.clear();
551  }
552  myCurrentSocket++;
553  } else if (load) {
554  myCurrentSocket = mySockets.end();
555  } else {
556  assert(closed);
557  // remove current socket and increment to next socket in ordering
559  }
560  }
561  if (!TraCI::getLoadArgs().empty()) {
562 #ifdef DEBUG_MULTI_CLIENTS
563  std::cout << " Breaking loop to load new simulation." << std::endl;
564 #endif
565  break;
566  } else if (myDoCloseConnection) {
567 #ifdef DEBUG_MULTI_CLIENTS
568  std::cout << " Breaking loop because last client closed connection." << std::endl;
569 #endif
570  break;
571  }
572  SUMOTime nextT = nextTargetTime();
573  // minimal target time among clients should have been increased during the last loop through mySockets
574  // XXX: The assert below is disabled since many tests do sth. like simulationStep(step). Such that for a first call step=0,
575  // leading to targetTime==1000 (increased by DELTA_T in dispatchCommand()),
576  // the next call is then usually simulationStep(step=1000) leading to no further increase
577  // and thus a failing assertion here.
578  //assert(myTargetTime < nextT || myDoCloseConnection);
579  myTargetTime = nextT;
580  }
581  // All clients are done with the current time step
582  // Reset myVehicleStateChanges
583  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
584  (*i).second.clear();
585  }
586 
587  } catch (std::invalid_argument& e) {
588  throw ProcessError(e.what());
589  } catch (TraCIException& e) {
590  throw ProcessError(e.what());
591  } catch (tcpip::SocketException& e) {
592  throw ProcessError(e.what());
593  }
594 }
595 
596 
597 void
599  mySubscriptions.clear();
600  for (std::map<int, NamedRTree*>::const_iterator i = myObjects.begin(); i != myObjects.end(); ++i) {
601  delete(*i).second;
602  }
603  myObjects.clear();
604  delete myLaneTree;
605  myLaneTree = 0;
606  myTargetTime = string2time(OptionsCont::getOptions().getString("begin"));
607  for (myCurrentSocket = mySockets.begin(); myCurrentSocket != mySockets.end(); ++myCurrentSocket) {
608  myCurrentSocket->second->targetTime = myTargetTime;
609  }
613  std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i;
614  for (i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); i++) {
615  i->second.clear();
616  }
617  myCurrentSocket = mySockets.begin();
618 }
619 
620 
621 #ifdef HAVE_PYTHON
622 // ===========================================================================
623 // python functions (traciemb module)
624 // ===========================================================================
625 static PyObject*
626 traciemb_execute(PyObject* /* self */, PyObject* args) {
627  const char* msg;
628  int size;
629  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
630  return NULL;
631  }
632  std::string result = TraCIServer::execute(std::string(msg, size));
633  return Py_BuildValue("s#", result.c_str(), result.size());
634 }
635 
636 static PyMethodDef EmbMethods[] = {
637  {
638  "execute", traciemb_execute, METH_VARARGS,
639  "Execute the given TraCI command and return the result."
640  },
641  {NULL, NULL, 0, NULL}
642 };
643 
644 
645 std::string
646 TraCIServer::execute(std::string cmd) {
647  try {
648  assert(myInstance != 0);
651  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
653  }
655  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
656  } catch (std::invalid_argument& e) {
657  throw ProcessError(e.what());
658  } catch (TraCIException& e) {
659  throw ProcessError(e.what());
660  } catch (tcpip::SocketException& e) {
661  throw ProcessError(e.what());
662  }
663 }
664 
665 
666 void
667 TraCIServer::runEmbedded(std::string pyFile) {
668  PyObject* pName, *pModule;
669  Py_Initialize();
670  Py_InitModule("traciemb", EmbMethods);
671  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
672  PyObject* sys_path, *path;
673  char pathstr[] = "path";
674  sys_path = PySys_GetObject(pathstr);
675  if (sys_path == NULL || !PyList_Check(sys_path)) {
676  throw ProcessError("Could not access python sys.path!");
677  }
678  path = PyString_FromString(FileHelpers::getFilePath(pyFile).c_str());
679  PyList_Insert(sys_path, 0, path);
680  Py_DECREF(path);
681  FILE* pFile = fopen(pyFile.c_str(), "r");
682  if (pFile == NULL) {
683  throw ProcessError("Failed to load \"" + pyFile + "\"!");
684  }
685  PyRun_SimpleFile(pFile, pyFile.c_str());
686  fclose(pFile);
687  } else {
688  pName = PyString_FromString(pyFile.c_str());
689  /* Error checking of pName left out */
690  pModule = PyImport_Import(pName);
691  Py_DECREF(pName);
692  if (pModule == NULL) {
693  PyErr_Print();
694  throw ProcessError("Failed to load \"" + pyFile + "\"!");
695  }
696  }
697  Py_Finalize();
698 }
699 #endif
700 
701 
702 std::map<int, TraCIServer::SocketInfo*>::iterator
704 #ifdef DEBUG_MULTI_CLIENTS
705  std::cout << " Removing socket " << myCurrentSocket->second->socket
706  << " (order " << myCurrentSocket->first << ")" << std::endl;
707 #endif
708 
709  if (mySockets.size() == 1) {
710  // Last client has disconnected
711  delete myCurrentSocket->second->socket;
712  mySockets.clear();
713  myCurrentSocket = mySockets.end();
714  return myCurrentSocket;
715  }
716 
717  const int currOrder = myCurrentSocket->first;
718  delete myCurrentSocket->second->socket;
719  myCurrentSocket++;
720  if (myCurrentSocket != mySockets.end()) {
721  const int nextOrder = myCurrentSocket->first;
722  mySockets.erase(currOrder);
723  myCurrentSocket = mySockets.find(nextOrder);
724  } else {
725  mySockets.erase(currOrder);
726  myCurrentSocket = mySockets.end();
727  }
728  return myCurrentSocket;
729 }
730 
731 
732 int
733 TraCIServer::readCommandID(int& commandStart, int& commandLength) {
734  commandStart = myInputStorage.position();
735  commandLength = myInputStorage.readUnsignedByte();
736  if (commandLength == 0) {
737  commandLength = myInputStorage.readInt();
738  }
740 }
741 
742 
743 int
745  int commandStart, commandLength;
746  int commandId = readCommandID(commandStart, commandLength);
747 #ifdef DEBUG_MULTI_CLIENTS
748  std::cout << " dispatchCommand() called for client " << myCurrentSocket->second->socket
749  << ", commandId = " << commandId << std::endl;
750 #endif
751  bool success = false;
752  // dispatch commands
753  if (myExecutors.find(commandId) != myExecutors.end()) {
754  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
755  } else {
756  switch (commandId) {
757  case CMD_GETVERSION:
758  success = commandGetVersion();
759  break;
760  case CMD_LOAD: {
761  std::vector<std::string> args;
763  return writeErrorStatusCmd(CMD_LOAD, "A load command needs a list of string arguments.", myOutputStorage);
764  }
765 #ifdef DEBUG_MULTI_CLIENTS
766  std::cout << " commandId == CMD_LOAD"
767  << ", args = " << toString(args) << std::endl;
768 #endif
769  try {
770  TraCI::load(args);
771  success = true;
773  // XXX: This only cares for the client that issued the load command.
774  // Multiclient-load functionality is still to be implemented. Refs #3146.
775  myCurrentSocket->second->socket->sendExact(myOutputStorage);
777  } catch (TraCIException& e) {
778  return writeErrorStatusCmd(CMD_LOAD, e.what(), myOutputStorage);
779  }
780  break;
781  }
782  case CMD_SIMSTEP: {
783  SUMOTime nextT = myInputStorage.readInt();
784  if (myAmEmbedded) {
785  if (nextT == 0) {
787  } else {
788  myTargetTime = nextT;
789  }
790  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myVehicleStateChanges.begin(); i != myVehicleStateChanges.end(); ++i) {
791  (*i).second.clear();
792  }
793  while (MSNet::getInstance()->getCurrentTimeStep() < myTargetTime) {
795  }
797  } else {
798  if (nextT == 0) {
799  myCurrentSocket->second->targetTime += DELTA_T;
800  } else {
801  myCurrentSocket->second->targetTime = nextT;
802  }
803 #ifdef DEBUG_MULTI_CLIENTS
804  std::cout << " commandId == CMD_SIMSTEP"
805  << ", next target time for client is " << myCurrentSocket->second->targetTime << std::endl;
806 #endif
807  if (myCurrentSocket->second->targetTime <= MSNet::getInstance()->getCurrentTimeStep()) {
808  // This is not the last TraCI simstep in the current SUMO simstep -> send single simstep response.
809  // @note: In the other case the simstep results are sent to all after the SUMO step was performed, see entry point for processCommandsUntilSimStep()
811  }
812  }
813  return commandId;
814  }
815  case CMD_CLOSE:
817  myCurrentSocket->second->socket->sendExact(myOutputStorage);
819  if (mySockets.size() == 1) {
820  // Last client has closed connection
821  myDoCloseConnection = true;
822  }
823  success = true;
824  break;
825  case CMD_SETORDER: {
826  const int order = myInputStorage.readInt();
827  if (order > MAX_ORDER) {
828  return writeErrorStatusCmd(CMD_SETORDER, "A set order command needs an int argument below " + toString(MAX_ORDER) + ".", myOutputStorage);
829  }
830  if (mySockets.count(order) > 0 || mySocketReorderRequests.count(order) > 0) {
831  return writeErrorStatusCmd(CMD_SETORDER, "Order '" + toString(order) + "' is already taken.", myOutputStorage);
832  }
833  // memorize reorder request (will only take effect in the next step)
834  mySocketReorderRequests[order] = myCurrentSocket->second;
835  success = true;
837  break;
838  }
854  success = addObjectVariableSubscription(commandId, false);
855  break;
871  success = addObjectVariableSubscription(commandId, true);
872  break;
873  default:
874  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
875  }
876  }
877  if (!success) {
878  while (myInputStorage.valid_pos() && (int)myInputStorage.position() < commandStart + commandLength) {
880  }
881  }
882  if ((int)myInputStorage.position() != commandStart + commandLength) {
883  std::ostringstream msg;
884  msg << "Wrong position in requestMessage after dispatching command.";
885  msg << " Expected command length was " << commandLength;
886  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
887  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
888  myDoCloseConnection = true;
889  }
890  return commandId;
891 }
892 
893 
894 // ---------- Server-internal command handling
895 bool
897  std::string sumoVersion = VERSION_STRING;
898  // Prepare response
899  tcpip::Storage answerTmp;
900  answerTmp.writeInt(TRACI_VERSION);
901  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
902  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
904  // command length
905  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
906  // command type
908  // and the parameter dependant part
909  myOutputStorage.writeStorage(answerTmp);
910  return true;
911 }
912 
913 
914 void
917 #ifdef DEBUG_MULTI_CLIENTS
918  std::cout << " postProcessSimulationStep() at time " << t << std::endl;
919 #endif
921  int noActive = 0;
922  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
923  const Subscription& s = *i;
927  if ((s.endTime < t) || isArrivedVehicle || isArrivedPerson) {
928  i = mySubscriptions.erase(i);
929  continue;
930  }
931  ++i;
932  if (s.beginTime > t) {
933  continue;
934  }
935  ++noActive;
936  }
938 #ifdef DEBUG_SUBSCRIPTIONS
939  std::cout << " Initial size of mySubscriptionCache is " << mySubscriptionCache.size()
940  << "\n Nr. of active subscriptions = " << noActive << std::endl;
941 #endif
942  mySubscriptionCache.writeInt(noActive);
943 #ifdef DEBUG_SUBSCRIPTIONS
944  std::cout << " Size after writing an int is " << mySubscriptionCache.size() << std::endl;
945 #endif
946  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
947  const Subscription& s = *i;
948  if (s.beginTime > t) {
949  ++i;
950  continue;
951  }
952  tcpip::Storage into;
953  std::string errors;
954  bool ok = processSingleSubscription(s, into, errors);
955 #ifdef DEBUG_SUBSCRIPTIONS
956  std::cout << " Size of into-store for subscription " << s.id
957  << ": " << into.size() << std::endl;
958 #endif
960  if (ok) {
961  ++i;
962  } else {
963  i = mySubscriptions.erase(i);
964  }
965  }
967 #ifdef DEBUG_SUBSCRIPTIONS
968  std::cout << " Size after writing subscriptions is " << mySubscriptionCache.size() << std::endl;
969 #endif
970 }
971 
972 
973 void
975 #ifdef DEBUG_MULTI_CLIENTS
976  std::cout << " Sending cached simstep response to current client " << myCurrentSocket->second->socket
977  << " (-> intermediate TraCI step)."
978  << "\n Size of mySubscriptionCache is " << mySubscriptionCache.size()
979  << std::endl;
980 #endif
982 
983 // NOTE: the commented code would send an empty response
984 // myOutputStorage.writeInt(0);
985 // myCurrentSocket->second->socket->sendExact(myOutputStorage);
986 // myOutputStorage.reset();
988  // send results to active client
989  myCurrentSocket->second->socket->sendExact(myOutputStorage);
991 }
992 
993 
994 void
995 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
996  writeStatusCmd(commandId, status, description, myOutputStorage);
997 }
998 
999 
1000 void
1001 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
1002  if (status == RTYPE_ERR) {
1003  WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
1004  } else if (status == RTYPE_NOTIMPLEMENTED) {
1005  WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
1006  }
1007  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
1008  outputStorage.writeUnsignedByte(commandId); // command type
1009  outputStorage.writeUnsignedByte(status); // status
1010  outputStorage.writeString(description); // description
1011 }
1012 
1013 
1014 bool
1015 TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
1016  writeStatusCmd(commandId, RTYPE_ERR, description, outputStorage);
1017  return false;
1018 }
1019 
1020 
1021 void
1023  tcpip::Storage writeInto;
1024  std::string errors;
1025  if (processSingleSubscription(s, writeInto, errors)) {
1027  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
1028  } else {
1029  bool needNewSubscription = true;
1030  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end(); ++i) {
1031  if (s.commandId == i->commandId && s.id == i->id &&
1032  s.beginTime == i->beginTime && s.endTime == i->endTime &&
1033  s.contextVars == i->contextVars && s.contextDomain == i->contextDomain && s.range == i->range) {
1034  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1035  for (std::vector<int>::const_iterator j = s.variables.begin(); j != s.variables.end(); ++j, ++k) {
1036  const int offset = (int)(std::find(i->variables.begin(), i->variables.end(), *j) - i->variables.begin());
1037  if (offset == (int)i->variables.size() || i->parameters[offset] != *k) {
1038  i->variables.push_back(*j);
1039  i->parameters.push_back(*k);
1040  }
1041  }
1042  needNewSubscription = false;
1043  break;
1044  }
1045  }
1046  if (needNewSubscription) {
1047  mySubscriptions.push_back(s);
1048  // Add new subscription to subscription cache (note: seems a bit inefficient)
1050  // copy new subscription into cache
1051  int noActive = 1 + (mySubscriptionCache.size() > 0 ? mySubscriptionCache.readInt() : 0);
1052  tcpip::Storage tmp;
1053  tmp.writeInt(noActive);
1054  while (mySubscriptionCache.valid_pos()) {
1056  }
1057  tmp.writeStorage(writeInto);
1060  }
1061  }
1063  }
1064  } else {
1065  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
1066  }
1067  myOutputStorage.writeStorage(writeInto);
1068 }
1069 
1070 
1071 void
1072 TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
1073  bool found = false;
1074  for (std::vector<Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
1075  if ((*j).id == id && (*j).commandId == commandId && (domain < 0 || (*j).contextDomain == domain)) {
1076  j = mySubscriptions.erase(j);
1077  found = true;
1078  continue;
1079  }
1080  ++j;
1081  }
1082  // try unsubscribe
1083  if (found) {
1084  writeStatusCmd(commandId, RTYPE_OK, "");
1085  } else {
1086  writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
1087  }
1088 }
1089 
1090 
1091 bool
1092 TraCIServer::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
1093  Position p;
1094  switch (domain) {
1097  shape.push_back(p);
1098  return true;
1099  }
1100  break;
1102  break;
1104  break;
1106  if (TraCIServerAPI_Lane::getShape(id, shape)) {
1107  return true;
1108  }
1109  break;
1112  shape.push_back(p);
1113  return true;
1114  }
1115  break;
1118  shape.push_back(p);
1119  return true;
1120  }
1121  break;
1123  break;
1125  break;
1127  if (TraCIServerAPI_POI::getPosition(id, p)) {
1128  shape.push_back(p);
1129  return true;
1130  }
1131  return false;
1133  if (TraCIServerAPI_Polygon::getShape(id, shape)) {
1134  return true;
1135  }
1136  break;
1139  shape.push_back(p);
1140  return true;
1141  }
1142  break;
1144  if (TraCIServerAPI_Edge::getShape(id, shape)) {
1145  return true;
1146  }
1147  break;
1149  return false;
1151  break;
1152  default:
1153  break;
1154  }
1155  return false;
1156 }
1157 
1158 void
1159 TraCIServer::collectObjectsInRange(int domain, const PositionVector& shape, double range, std::set<std::string>& into) {
1160  // build the look-up tree if not yet existing
1161  if (myObjects.find(domain) == myObjects.end()) {
1162  switch (domain) {
1165  break;
1166  case CMD_GET_EDGE_VARIABLE:
1167  case CMD_GET_LANE_VARIABLE:
1176  break;
1177  case CMD_GET_POI_VARIABLE:
1179  break;
1182  break;
1185  break;
1186  default:
1187  break;
1188  }
1189  }
1190  const Boundary b = shape.getBoxBoundary().grow(range);
1191  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
1192  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
1193  switch (domain) {
1195  case CMD_GET_POI_VARIABLE:
1198  Named::StoringVisitor sv(into);
1199  myObjects[domain]->Search(cmin, cmax, sv);
1200  }
1201  break;
1202  case CMD_GET_EDGE_VARIABLE:
1203  case CMD_GET_LANE_VARIABLE:
1205  case CMD_GET_VEHICLE_VARIABLE: {
1206  TraCIServerAPI_Lane::StoringVisitor sv(into, shape, range, domain);
1207  myLaneTree->Search(cmin, cmax, sv);
1208  }
1209  break;
1210  default:
1211  break;
1212  }
1213 }
1214 
1215 
1216 bool
1218  std::string& errors) {
1219  bool ok = true;
1220  tcpip::Storage outputStorage;
1221  const int getCommandId = s.contextVars ? s.contextDomain : s.commandId - 0x30;
1222  std::set<std::string> objIDs;
1223  if (s.contextVars) {
1224  PositionVector shape;
1225  if (!findObjectShape(s.commandId, s.id, shape)) {
1226  return false;
1227  }
1228  collectObjectsInRange(s.contextDomain, shape, s.range, objIDs);
1229  } else {
1230  objIDs.insert(s.id);
1231  }
1232  const int numVars = s.contextVars && s.variables.size() == 1 && s.variables[0] == ID_LIST ? 0 : (int)s.variables.size();
1233  for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
1234  if (s.contextVars) {
1235  outputStorage.writeString(*j);
1236  }
1237  if (numVars > 0) {
1238  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
1239  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
1240  tcpip::Storage message;
1241  message.writeUnsignedByte(*i);
1242  message.writeString(*j);
1243  message.writePacket(*k);
1244  tcpip::Storage tmpOutput;
1245  if (myExecutors.find(getCommandId) != myExecutors.end()) {
1246  ok &= myExecutors[getCommandId](*this, message, tmpOutput);
1247  } else {
1248  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
1249  ok = false;
1250  }
1251  // copy response part
1252  if (ok) {
1253  int length = tmpOutput.readUnsignedByte();
1254  while (--length > 0) {
1255  tmpOutput.readUnsignedByte();
1256  }
1257  int lengthLength = 1;
1258  length = tmpOutput.readUnsignedByte();
1259  if (length == 0) {
1260  lengthLength = 5;
1261  length = tmpOutput.readInt();
1262  }
1263  //read responseType
1264  tmpOutput.readUnsignedByte();
1265  int variable = tmpOutput.readUnsignedByte();
1266  std::string id = tmpOutput.readString();
1267  outputStorage.writeUnsignedByte(variable);
1268  outputStorage.writeUnsignedByte(RTYPE_OK);
1269  length -= (lengthLength + 1 + 4 + (int)id.length());
1270  while (--length > 0) {
1271  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
1272  }
1273  } else {
1274  //read length
1275  tmpOutput.readUnsignedByte();
1276  //read cmd
1277  tmpOutput.readUnsignedByte();
1278  //read status
1279  tmpOutput.readUnsignedByte();
1280  std::string msg = tmpOutput.readString();
1281  outputStorage.writeUnsignedByte(*i);
1282  outputStorage.writeUnsignedByte(RTYPE_ERR);
1283  outputStorage.writeUnsignedByte(TYPE_STRING);
1284  outputStorage.writeString(msg);
1285  errors = errors + msg;
1286  }
1287  }
1288  }
1289  }
1290  int length = (1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size();
1291  if (s.contextVars) {
1292  length += 4;
1293  }
1294  writeInto.writeUnsignedByte(0); // command length -> extended
1295  writeInto.writeInt(length);
1296  writeInto.writeUnsignedByte(s.commandId + 0x10);
1297  writeInto.writeString(s.id);
1298  if (s.contextVars) {
1299  writeInto.writeUnsignedByte(s.contextDomain);
1300  }
1301  writeInto.writeUnsignedByte(numVars);
1302  if (s.contextVars) {
1303  writeInto.writeInt((int)objIDs.size());
1304  }
1305  if (!s.contextVars || objIDs.size() != 0) {
1306  writeInto.writeStorage(outputStorage);
1307  }
1308  return ok;
1309 }
1310 
1311 
1312 bool
1313 TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
1314  const SUMOTime beginTime = myInputStorage.readInt();
1315  const SUMOTime endTime = myInputStorage.readInt();
1316  const std::string id = myInputStorage.readString();
1317  const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
1318  const double range = hasContext ? myInputStorage.readDouble() : 0.;
1319  const int num = myInputStorage.readUnsignedByte();
1320  std::vector<int> variables;
1321  std::vector<std::vector<unsigned char> > parameters;
1322  for (int i = 0; i < num; ++i) {
1323  const int varID = myInputStorage.readUnsignedByte();
1324  variables.push_back(varID);
1325  parameters.push_back(std::vector<unsigned char>());
1326  for (int j = 0; j < myParameterSizes[varID]; j++) {
1327  parameters.back().push_back(myInputStorage.readChar());
1328  }
1329  }
1330  // check subscribe/unsubscribe
1331  if (variables.size() == 0) {
1332  removeSubscription(commandId, id, -1);
1333  return true;
1334  }
1335  // process subscription
1336  Subscription s(commandId, id, variables, parameters, beginTime, endTime, hasContext, domain, range);
1338  return true;
1339 }
1340 
1341 
1342 void
1344  if (tempMsg.size() < 254) {
1345  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
1346  } else {
1347  outputStorage.writeUnsignedByte(0); // command length -> extended
1348  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
1349  }
1350  outputStorage.writeStorage(tempMsg);
1351 }
1352 
1353 
1354 bool
1356  if (inputStorage.readUnsignedByte() != TYPE_INTEGER) {
1357  return false;
1358  }
1359  into = inputStorage.readInt();
1360  return true;
1361 }
1362 
1363 
1364 bool
1366  if (inputStorage.readUnsignedByte() != TYPE_DOUBLE) {
1367  return false;
1368  }
1369  into = inputStorage.readDouble();
1370  return true;
1371 }
1372 
1373 
1374 bool
1375 TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
1376  if (inputStorage.readUnsignedByte() != TYPE_STRING) {
1377  return false;
1378  }
1379  into = inputStorage.readString();
1380  return true;
1381 }
1382 
1383 
1384 bool
1385 TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
1386  if (inputStorage.readUnsignedByte() != TYPE_STRINGLIST) {
1387  return false;
1388  }
1389  into = inputStorage.readStringList();
1390  return true;
1391 }
1392 
1393 
1394 bool
1396  if (inputStorage.readUnsignedByte() != TYPE_COLOR) {
1397  return false;
1398  }
1399  into.r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1400  into.g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1401  into.b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1402  into.a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
1403  return true;
1404 }
1405 
1406 
1407 bool
1409  if (inputStorage.readUnsignedByte() != POSITION_2D) {
1410  return false;
1411  }
1412  into.x = inputStorage.readDouble();
1413  into.y = inputStorage.readDouble();
1414  into.z = 0;
1415  return true;
1416 }
1417 
1418 
1419 bool
1421  if (inputStorage.readUnsignedByte() != TYPE_BOUNDINGBOX) {
1422  return false;
1423  }
1424  const double xmin = inputStorage.readDouble();
1425  const double ymin = inputStorage.readDouble();
1426  const double xmax = inputStorage.readDouble();
1427  const double ymax = inputStorage.readDouble();
1428  into.set(xmin, ymin, xmax, ymax);
1429  return true;
1430 }
1431 
1432 
1433 bool
1435  if (inputStorage.readUnsignedByte() != TYPE_BYTE) {
1436  return false;
1437  }
1438  into = inputStorage.readByte();
1439  return true;
1440 }
1441 
1442 
1443 bool
1445  if (inputStorage.readUnsignedByte() != TYPE_UBYTE) {
1446  return false;
1447  }
1448  into = inputStorage.readUnsignedByte();
1449  return true;
1450 }
1451 
1452 
1453 bool
1455  if (inputStorage.readUnsignedByte() != TYPE_POLYGON) {
1456  return false;
1457  }
1458  into.clear();
1459  int noEntries = inputStorage.readUnsignedByte();
1460  PositionVector shape;
1461  for (int i = 0; i < noEntries; ++i) {
1462  double x = inputStorage.readDouble();
1463  double y = inputStorage.readDouble();
1464  into.push_back(Position(x, y));
1465  }
1466  return true;
1467 }
1468 
1469 #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:575
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
double x
Definition: TraCIDefs.h:72
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:132
static std::vector< std::string > & getLoadArgs()
Definition: TraCI.h:103
#define CMD_SUBSCRIBE_VEHICLE_CONTEXT
#define CMD_SUBSCRIBE_LANE_VARIABLE
tcpip::Storage mySubscriptionCache
The last timestep&#39;s subscription results.
Definition: TraCIServer.h:380
bool readTypeCheckingColor(tcpip::Storage &inputStorage, 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
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:83
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:428
double range
The range of the context.
Definition: TraCIServer.h:432
#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:422
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
static NamedRTree * getTree()
Returns a tree filled with junction instances.
static NamedRTree * getTree()
Returns a tree filled with polygon instances.
static void fill(RTREE &into)
Fills the given RTree with lane instances.
Definition: MSLane.cpp:1593
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:144
#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:424
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:377
#define TYPE_POLYGON
unsigned char g
Definition: TraCIDefs.h:79
StorageType::size_type size() const
Definition: storage.h:115
#define TRACI_VERSION
void postProcessSimulationStep()
Handles subscriptions to send after a simstep2 command.
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:342
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:169
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc6: Change Route State)
static void load(const std::vector< std::string > &args)
load a simulation with the given arguments
Definition: TraCI.cpp:61
void sendOutputToAll() const
send out subscription results (actually just the content of myOutputStorage) to clients which will ac...
SUMOTime DELTA_T
Definition: SUMOTime.cpp:40
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
unsigned char r
Definition: TraCIDefs.h:79
tcpip::Storage myInputStorage
The storage to read from.
Definition: TraCIServer.h:374
#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:397
void cleanup()
clean up subscriptions
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:79
#define CMD_SUBSCRIBE_ROUTE_CONTEXT
void setVTDControlled(Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector &route, SUMOTime t)
Definition: MSVehicle.cpp:453
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:252
bool writeErrorStatusCmd(int commandId, const std::string &description, tcpip::Storage &outputStorage)
Writes a status command to the given storage with status = RTYPE_ERR.
unsigned char a
Definition: TraCIDefs.h:79
#define CMD_SUBSCRIBE_EDGE_VARIABLE
virtual unsigned char readChar()
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition: MSNet.cpp:831
#define CMD_GET_ROUTE_VARIABLE
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
#define CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT
virtual void writeInt(int)
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:65
#define TYPE_STRING
#define SIMTIME
Definition: SUMOTime.h:70
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:355
std::map< int, SocketInfo * >::iterator removeCurrentSocket()
removes myCurrentSocket from mySockets and returns an iterator pointing to the next member according ...
void postProcessVTD()
The vehicles starts to stop.
Definition: MSNet.h:589
std::map< int, CmdExecutor > myExecutors
Map of commandIds -> their executors; applicable if the executor applies to the method footprint...
Definition: TraCIServer.h:386
#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)
double z
Definition: TraCIDefs.h:72
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.
static NamedRTree * getTree()
Returns a tree filled with PoI instances.
#define CMD_SUBSCRIBE_LANE_CONTEXT
#define CMD_SUBSCRIBE_SIM_VARIABLE
void removeSubscription(int commandId, const std::string &identity, int domain)
#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 max(a, b)
Definition: polyfonts.c:65
#define CMD_GETVERSION
#define CMD_SUBSCRIBE_GUI_CONTEXT
#define CMD_LOAD
Allows to store the object; used as context while traveling the rtree in TraCI.
The vehicle got a new route.
Definition: MSNet.h:583
The vehicle arrived at his destination (is deleted)
Definition: MSNet.h:581
StorageType::const_iterator end() const
Definition: storage.h:118
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
The vehicles starts to park.
Definition: MSNet.h:585
int commandId
commandIdArg The command id of the subscription
Definition: TraCIServer.h:416
std::vector< Subscription > mySubscriptions
The list of known, still valid subscriptions.
Definition: TraCIServer.h:437
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:67
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
virtual int readInt()
A 3D-position.
Definition: TraCIDefs.h:71
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:767
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
std::string id
The id of the object that is subscribed.
Definition: TraCIServer.h:418
#define CMD_GET_POI_VARIABLE
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE
A list of positions.
std::vector< int > variables
The subscribed variables.
Definition: TraCIServer.h:420
#define CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:305
#define CMD_SET_VEHICLETYPE_VARIABLE
virtual void writeByte(int)
void setVTDControlled(MSVehicle *v, Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, ConstMSEdgeVector route, SUMOTime t)
#define TYPE_BOUNDINGBOX
bool readTypeCheckingStringList(tcpip::Storage &inputStorage, std::vector< std::string > &into)
Reads the value type and a string list, verifying the type.
#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:47
T MIN2(T a, T b)
Definition: StdDefs.h:68
The vehicle started to teleport.
Definition: MSNet.h:577
#define CMD_GET_SIM_VARIABLE
virtual std::string readString()
#define CMD_GET_EDGE_VARIABLE
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:302
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:76
#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:352
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:587
#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:74
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:571
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:383
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
The vehicle was built, but has not yet departed.
Definition: MSNet.h:573
void processCommandsUntilSimStep(SUMOTime step)
process all commands until the next SUMO simulation step. It is guaranteed that t->getTargetTime() >=...
LANE_RTREE_QUAL * myLaneTree
A storage of lanes.
Definition: TraCIServer.h:452
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc5: Change Vehicle Type State)
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:100
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
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:4223
virtual const char * what() const
Definition: socket.h:70
void collectObjectsInRange(int domain, const PositionVector &shape, double range, std::set< std::string > &into)
#define TYPE_DOUBLE
std::string toHex(const T i, std::streamsize numDigits=0)
Definition: ToString.h:66
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:368
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:126
#define TYPE_BYTE
#define CMD_SET_LANE_VARIABLE
#define CMD_GET_MULTIENTRYEXIT_VARIABLE
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:85
SUMOTime myTargetTime
The time step to reach until processing the next commands.
Definition: TraCIServer.h:371
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa6: Get Route Variable)
static NamedRTree * getTree()
Returns a tree filled with inductive loop instances.
The vehicle ends to stop.
Definition: MSNet.h:591
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
#define LANE_RTREE_QUAL
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:138
std::map< int, NamedRTree * > myObjects
A storage of objects.
Definition: TraCIServer.h:449
StorageType::const_iterator begin() const
Definition: storage.h:117
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
#define CMD_SETORDER
bool readTypeCheckingPosition2D(tcpip::Storage &inputStorage, TraCIPosition &into)
Reads the value type and a 2D position, verifying the type.
std::map< std::string, MSVehicle * > myVTDControlledVehicles
Definition: TraCIServer.h:391
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.
unsigned char b
Definition: TraCIDefs.h:79
void visit(const TraCIServerAPI_Lane::StoringVisitor &cont) const
Callback for visiting the lane when traversing an RTree.
Definition: MSLane.h:1032
#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:362
static bool processSet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a set value command (Command 0xc2: Change Traffic Lights State)
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:365
long long int SUMOTime
Definition: TraCIDefs.h:52
static std::string getFilePath(const std::string &path)
Removes the file information from the given path.
Definition: FileHelpers.cpp:72
double y
Definition: TraCIDefs.h:72
#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:430
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:201
#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)
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
Representation of a lane in the micro simulation.
Definition: MSLane.h:79
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:446
The vehicle ended being teleported.
Definition: MSNet.h:579
#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:358
SUMOTime endTime
The end time of the subscription.
Definition: TraCIServer.h:426
static bool processGet(TraCIServer &server, tcpip::Storage &inputStorage, tcpip::Storage &outputStorage)
Processes a get value command (Command 0xa2: Get Traffic Lights Variable)
#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.
const std::string & getID() const
Returns the name of the vehicle.
std::map< int, int > myParameterSizes
Map of variable ids to the size of the parameter in bytes.
Definition: TraCIServer.h:389
void checkClientOrdering()
Called once after connection of all clients for executing SET_ORDER (and possibly prior GET_VERSION) ...