SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TraCIServer.cpp
Go to the documentation of this file.
1 /****************************************************************************/
16 /****************************************************************************/
17 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
18 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
19 /****************************************************************************/
20 //
21 // This file is part of SUMO.
22 // SUMO is free software: you can redistribute it and/or modify
23 // it under the terms of the GNU General Public License as published by
24 // the Free Software Foundation, either version 3 of the License, or
25 // (at your option) any later version.
26 //
27 /****************************************************************************/
28 
29 // ===========================================================================
30 // included modules
31 // ===========================================================================
32 #ifdef _MSC_VER
33 #include <windows_config.h>
34 #else
35 #include <config.h>
36 #endif
37 
38 #ifdef HAVE_VERSION_H
39 #include <version.h>
40 #endif
41 
42 #ifndef NO_TRACI
43 
44 #ifdef HAVE_PYTHON
45 #include <Python.h>
46 #endif
47 
48 #include <string>
49 #include <map>
50 #include <iostream>
51 #include <foreign/tcpip/socket.h>
52 #include <foreign/tcpip/storage.h>
53 #include <utils/common/SUMOTime.h>
63 #include <utils/shapes/Polygon.h>
64 #include <utils/xml/XMLSubSys.h>
65 #include <microsim/MSNet.h>
67 #include <microsim/MSVehicle.h>
68 #include <microsim/MSEdge.h>
70 #include <microsim/MSJunction.h>
71 #include <microsim/MSEdgeControl.h>
72 #include <microsim/MSLane.h>
73 #include <microsim/MSGlobals.h>
75 #include "TraCIConstants.h"
76 #include "TraCIServer.h"
79 #include "TraCIServerAPI_Lane.h"
81 #include "TraCIServerAPI_TLS.h"
82 #include "TraCIServerAPI_Vehicle.h"
84 #include "TraCIServerAPI_Route.h"
85 #include "TraCIServerAPI_POI.h"
86 #include "TraCIServerAPI_Polygon.h"
87 #include "TraCIServerAPI_Edge.h"
89 
90 #ifdef CHECK_MEMORY_LEAKS
91 #include <foreign/nvwa/debug_new.h>
92 #endif // CHECK_MEMORY_LEAKS
93 
94 
95 // ===========================================================================
96 // used namespaces
97 // ===========================================================================
98 namespace traci {
99 
100 // ===========================================================================
101 // static member definitions
102 // ===========================================================================
105 
106 
107 // ===========================================================================
108 // method definitions
109 // ===========================================================================
110 
111 void
112 TraCIServer::openSocket(const std::map<int, CmdExecutor> &execs) {
113  if (myInstance == 0) {
114  if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
115  myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
116  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
117  myInstance->myExecutors[i->first] = i->second;
118  }
119  }
120  }
121 }
122 
123 /*****************************************************************************/
124 
126  : mySocket(0), myTargetTime(0), myDoingSimStep(false), myHaveWarnedDeprecation(false), myAmEmbedded(port == 0) {
127  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
128  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
129  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
130  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
131  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
132  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
134 
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  mySocket = new tcpip::Socket(port);
169  mySocket->accept();
170  // When got here, a client has connected
171  } catch (tcpip::SocketException& e) {
172  throw ProcessError(e.what());
173  }
174  }
175 }
176 
177 /*****************************************************************************/
178 
181  if (mySocket != NULL) {
182  mySocket->close();
183  delete mySocket;
184  }
185 }
186 
187 /*****************************************************************************/
188 
189 void
191  if (myDoCloseConnection || OptionsCont::getOptions().getInt("remote-port") == 0) {
192  return;
193  }
194  myVehicleStateChanges[to].push_back(vehicle->getID());
195 }
196 
197 /*****************************************************************************/
198 void
200  try {
201  if (myInstance == 0) {
202  if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
203  myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
204  } else {
205  return;
206  }
207  }
208  if (myInstance->myAmEmbedded || step < myInstance->myTargetTime) {
209  return;
210  }
211  // Simulation should run until
212  // 1. end time reached or
213  // 2. got CMD_CLOSE or
214  // 3. Client closes socket connection
215  if (myInstance->myDoingSimStep) {
217  myInstance->myDoingSimStep = false;
218  }
219  while (!myDoCloseConnection) {
221  if (myInstance->myOutputStorage.size() > 0) {
222  // send out all answers as one storage
224  }
227  // Read a message
229  }
231  // dispatch each command
232  int cmd = myInstance->dispatchCommand();
233  if (cmd == CMD_SIMSTEP2) {
234  myInstance->myDoingSimStep = true;
235  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
236  (*i).second.clear();
237  }
238  return;
239  }
240  }
241  }
243  // send out all answers as one storage
245  }
246  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
247  (*i).second.clear();
248  }
249  } catch (std::invalid_argument& e) {
250  throw ProcessError(e.what());
251  } catch (TraCIException& e) {
252  throw ProcessError(e.what());
253  } catch (tcpip::SocketException& e) {
254  throw ProcessError(e.what());
255  }
256  if (myInstance != NULL) {
257  delete myInstance;
258  myInstance = 0;
259  myDoCloseConnection = true;
260  }
261 }
262 
263 /*****************************************************************************/
264 
265 bool
267  return myDoCloseConnection;
268 }
269 
270 
271 void
273  if (myInstance != 0) {
274  delete myInstance;
275  myInstance = 0;
276  myDoCloseConnection = true;
277  }
278 }
279 
280 /*****************************************************************************/
281 
282 #ifdef HAVE_PYTHON
283 // ===========================================================================
284 // python functions (traciemb module)
285 // ===========================================================================
286 static PyObject*
287 traciemb_execute(PyObject* self, PyObject* args) {
288  const char* msg;
289  int size;
290  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
291  return NULL;
292  }
293  std::string result = traci::TraCIServer::execute(std::string(msg, size));
294  return Py_BuildValue("s#", result.c_str(), result.size());
295 }
296 
297 static PyMethodDef EmbMethods[] = {
298  {
299  "execute", traciemb_execute, METH_VARARGS,
300  "Execute the given TraCI command and return the result."
301  },
302  {NULL, NULL, 0, NULL}
303 };
304 
305 
306 std::string
307 TraCIServer::execute(std::string cmd) {
308  try {
309  if (myInstance == 0) {
310  if (!myDoCloseConnection) {
312  } else {
313  return "";
314  }
315  }
318  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
320  }
322  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
323  } catch (std::invalid_argument& e) {
324  throw ProcessError(e.what());
325  } catch (TraCIException& e) {
326  throw ProcessError(e.what());
327  } catch (tcpip::SocketException& e) {
328  throw ProcessError(e.what());
329  }
330 }
331 
332 
333 void
334 TraCIServer::runEmbedded(std::string pyFile) {
335  PyObject* pName, *pModule;
336  Py_Initialize();
337  Py_InitModule("traciemb", EmbMethods);
338  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
339  FILE* pFile = fopen(pyFile.c_str(), "r");
340  PyRun_SimpleFile(pFile, pyFile.c_str());
341  fclose(pFile);
342  } else {
343  pName = PyString_FromString(pyFile.c_str());
344  /* Error checking of pName left out */
345  pModule = PyImport_Import(pName);
346  Py_DECREF(pName);
347  if (pModule == NULL) {
348  PyErr_Print();
349  throw ProcessError("Failed to load \"" + pyFile + "\"!");
350  }
351  }
352  Py_Finalize();
353 }
354 #endif
355 
356 /*****************************************************************************/
357 
358 int
360  unsigned int commandStart = myInputStorage.position();
361  unsigned int commandLength = myInputStorage.readUnsignedByte();
362  if (commandLength == 0) {
363  commandLength = myInputStorage.readInt();
364  }
365 
366  int commandId = myInputStorage.readUnsignedByte();
367  bool success = false;
368  // dispatch commands
369  if (myExecutors.find(commandId) != myExecutors.end()) {
370  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
371  } else {
372  switch (commandId) {
373  case CMD_GETVERSION:
374  success = commandGetVersion();
375  break;
376  case CMD_SIMSTEP2: {
377  SUMOTime nextT = myInputStorage.readInt();
378  success = true;
379  if (nextT != 0) {
380  myTargetTime = nextT;
381  } else {
383  }
384  if (myAmEmbedded) {
387  }
388  return commandId;
389  }
390  case CMD_CLOSE:
391  success = commandCloseConnection();
392  break;
393  case CMD_POSITIONCONVERSION: {
395  WRITE_WARNING("Using old TraCI API, please update your client!");
397  }
398  tcpip::Storage tempMsg;
400  if (success) {
402  myOutputStorage.writeStorage(tempMsg);
403  }
404  }
405  break;
406  case CMD_ADDVEHICLE:
408  WRITE_WARNING("Using old TraCI API, please update your client!");
410  }
411  success = commandAddVehicle();
412  break;
413  case CMD_DISTANCEREQUEST: {
415  WRITE_WARNING("Using old TraCI API, please update your client!");
417  }
418  tcpip::Storage tempMsg;
420  if (success) {
422  myOutputStorage.writeStorage(tempMsg);
423  }
424  }
425  break;
439  success = addSubscription(commandId);
440  break;
441  default:
442  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
443  }
444  }
445  if (!success) {
446  while (myInputStorage.valid_pos() && myInputStorage.position() < commandStart + commandLength) {
448  }
449  }
450  if (myInputStorage.position() != commandStart + commandLength) {
451  std::ostringstream msg;
452  msg << "Wrong position in requestMessage after dispatching command.";
453  msg << " Expected command length was " << commandLength;
454  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
455  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
456  myDoCloseConnection = true;
457  }
458  return commandId;
459 }
460 
461 /*****************************************************************************/
462 
463 void
467  int noActive = 0;
468  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
469  const Subscription& s = *i;
471  if ((s.endTime < t) || isArrivedVehicle) {
472  i = mySubscriptions.erase(i);
473  continue;
474  }
475  ++i;
476  if (s.beginTime > t) {
477  continue;
478  }
479  ++noActive;
480  }
481  myOutputStorage.writeInt(noActive);
482  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end(); ++i) {
483  const Subscription& s = *i;
484  if (s.beginTime > t) {
485  continue;
486  }
487  tcpip::Storage into;
488  std::string errors;
489  processSingleSubscription(s, into, errors);
491  }
492 }
493 
494 /*****************************************************************************/
495 
496 bool
498 
499  std::string sumoVersion = VERSION_STRING;
500 
501  // Prepare response
502  tcpip::Storage answerTmp;
503 
504  answerTmp.writeInt(TRACI_VERSION);
505  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
506 
507  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
509 
510  // command length
511  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
512  // command type
514  // and the parameter dependant part
515  myOutputStorage.writeStorage(answerTmp);
516  return true;
517 }
518 
519 /*****************************************************************************/
520 
521 bool
523  myDoCloseConnection = true;
524  // write answer
525  writeStatusCmd(CMD_CLOSE, RTYPE_OK, "Goodbye");
526  return true;
527 }
528 
529 /*****************************************************************************/
530 
531 bool
533 
534  // read parameters
535  std::string vehicleId = myInputStorage.readString();
536  std::string vehicleTypeId = myInputStorage.readString();
537  std::string routeId = myInputStorage.readString();
538  std::string laneId = myInputStorage.readString();
539  SUMOReal insertionPosition = myInputStorage.readFloat();
540  SUMOReal insertionSpeed = myInputStorage.readFloat();
541 
542  // find vehicleType
543  MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(vehicleTypeId);
544  if (!vehicleType) {
545  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid vehicleTypeId: '" + vehicleTypeId + "'");
546  return false;
547  }
548 
549  // find route
550  const MSRoute* route = MSRoute::dictionary(routeId);
551  if (!route) {
552  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid routeId: '" + routeId + "'");
553  return false;
554  }
555 
556  // find lane
557  MSLane* lane;
558  if (laneId != "") {
559  lane = MSLane::dictionary(laneId);
560  if (!lane) {
561  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid laneId: '" + laneId + "'");
562  return false;
563  }
564  } else {
565  lane = route->getEdges()[0]->getLanes()[0];
566  if (!lane) {
567  writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not find first lane of first edge in routeId '" + routeId + "'");
568  return false;
569  }
570  }
571 
572  if (&lane->getEdge() != *route->begin()) {
573  writeStatusCmd(CMD_STOP, RTYPE_ERR, "The route must start at the edge the lane starts at.");
574  return false;
575  }
576 
577  // build vehicle
578  SUMOVehicleParameter* vehicleParams = new SUMOVehicleParameter();
579  vehicleParams->id = vehicleId;
580  vehicleParams->depart = MSNet::getInstance()->getCurrentTimeStep() + 1;
581  MSVehicle* vehicle = static_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(vehicleParams, route, vehicleType));
582  if (vehicle == NULL) {
583  writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not build vehicle");
584  return false;
585  }
586 
587  // calculate speed
588  float clippedInsertionSpeed;
589  if (insertionSpeed < 0) {
590  clippedInsertionSpeed = (float) MIN2(lane->getMaxSpeed(), vehicle->getMaxSpeed());
591  } else {
592  clippedInsertionSpeed = (float) MIN3(lane->getMaxSpeed(), vehicle->getMaxSpeed(), insertionSpeed);
593  }
594 
595  // insert vehicle into the dictionary
596  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
597  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not add vehicle to VehicleControl");
598  return false;
599  }
600 
601  // try to emit
602  if (!lane->isInsertionSuccess(vehicle, clippedInsertionSpeed, insertionPosition, true)) {
604  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not insert vehicle");
605  return false;
606  }
607 
608  // exec callback
609  vehicle->onDepart();
610 
611  // create a reply message
613 
614  return true;
615 }
616 
617 
618 /*****************************************************************************/
619 
620 void
621 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
622  writeStatusCmd(commandId, status, description, myOutputStorage);
623 }
624 
625 
626 void
627 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
628  if (status == RTYPE_ERR) {
629  WRITE_ERROR("Answered with error to command " + toString(commandId) + ": " + description);
630  } else if (status == RTYPE_NOTIMPLEMENTED) {
631  WRITE_ERROR("Requested command not implemented (" + toString(commandId) + "): " + description);
632  }
633  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
634  outputStorage.writeUnsignedByte(commandId); // command type
635  outputStorage.writeUnsignedByte(status); // status
636  outputStorage.writeString(description); // description
637 }
638 
639 /*****************************************************************************/
640 
641 bool
643  SUMOTime beginTime = myInputStorage.readInt();
644  SUMOTime endTime = myInputStorage.readInt();
645  std::string id = myInputStorage.readString();
646  int no = myInputStorage.readUnsignedByte();
647  std::vector<int> variables;
648  for (int i = 0; i < no; ++i) {
649  variables.push_back(myInputStorage.readUnsignedByte());
650  }
651  // check subscribe/unsubscribe
652  bool ok = true;
653  if (variables.size() == 0) {
654  // try unsubscribe
655  bool found = false;
656  for (std::vector<Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
657  if ((*j).id == id && (*j).commandId == commandId) {
658  j = mySubscriptions.erase(j);
659  found = true;
660  continue;
661  }
662  ++j;
663  }
664  if (found) {
665  writeStatusCmd(commandId, RTYPE_OK, "");
666  } else {
667  writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
668  }
669  } else {
670  // process subscription
671  Subscription s(commandId, id, variables, beginTime, endTime);
672  tcpip::Storage writeInto;
673  std::string errors;
675  processSingleSubscription(s, writeInto, errors);
676  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
677  } else {
678  if (processSingleSubscription(s, writeInto, errors)) {
679  mySubscriptions.push_back(s);
681  } else {
682  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
683  }
684  }
685  myOutputStorage.writeStorage(writeInto);
686  }
687  return ok;
688 }
689 
690 
691 bool
693  std::string& errors) {
694  bool ok = true;
695  tcpip::Storage outputStorage;
696  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i) {
697  tcpip::Storage message;
698  message.writeUnsignedByte(*i);
699  message.writeString(s.id);
700  tcpip::Storage tmpOutput;
701  int getId = s.commandId - 0x30;
702  if (myExecutors.find(getId) != myExecutors.end()) {
703  ok &= myExecutors[getId](*this, message, tmpOutput);
704  } else {
705  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
706  ok = false;
707  }
708  // copy response part
709  if (ok) {
710  int length = tmpOutput.readUnsignedByte();
711  while (--length > 0) {
712  tmpOutput.readUnsignedByte();
713  }
714  int lengthLength = 1;
715  length = tmpOutput.readUnsignedByte();
716  if (length == 0) {
717  lengthLength = 5;
718  length = tmpOutput.readInt();
719  }
720  //read responseType
721  tmpOutput.readUnsignedByte();
722  int variable = tmpOutput.readUnsignedByte();
723  std::string id = tmpOutput.readString();
724  outputStorage.writeUnsignedByte(variable);
725  outputStorage.writeUnsignedByte(RTYPE_OK);
726  length -= (lengthLength + 1 + 4 + (int)id.length());
727  while (--length > 0) {
728  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
729  }
730  } else {
731  //read length
732  tmpOutput.readUnsignedByte();
733  //read cmd
734  tmpOutput.readUnsignedByte();
735  //read status
736  tmpOutput.readUnsignedByte();
737  std::string msg = tmpOutput.readString();
738  outputStorage.writeUnsignedByte(*i);
739  outputStorage.writeUnsignedByte(RTYPE_ERR);
740  outputStorage.writeUnsignedByte(TYPE_STRING);
741  outputStorage.writeString(msg);
742  errors = errors + msg;
743  }
744  }
745  writeInto.writeUnsignedByte(0); // command length -> extended
746  writeInto.writeInt((1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size());
747  writeInto.writeUnsignedByte(s.commandId + 0x10);
748  writeInto.writeString(s.id);
749  writeInto.writeUnsignedByte((int)(s.variables.size()));
750  writeInto.writeStorage(outputStorage);
751  return ok;
752 }
753 
754 void
756  if (tempMsg.size() < 254) {
757  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
758  } else {
759  outputStorage.writeUnsignedByte(0); // command length -> extended
760  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
761  }
762  outputStorage.writeStorage(tempMsg);
763 }
764 
765 }
766 
767 #endif