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 /****************************************************************************/
17 /****************************************************************************/
18 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
19 // Copyright (C) 2007-2014 DLR (http://www.dlr.de/) and contributors
20 /****************************************************************************/
21 //
22 // This file is part of SUMO.
23 // SUMO is free software: you can redistribute it and/or modify
24 // it under the terms of the GNU General Public License as published by
25 // the Free Software Foundation, either version 3 of the License, or
26 // (at your option) any later version.
27 //
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 <foreign/tcpip/socket.h>
53 #include <foreign/tcpip/storage.h>
54 #include <utils/common/SUMOTime.h>
62 #include <utils/shapes/Polygon.h>
63 #include <utils/xml/XMLSubSys.h>
64 #include <microsim/MSNet.h>
66 #include <microsim/MSVehicle.h>
67 #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 "TraCIConstants.h"
75 #include "TraCIServer.h"
78 #include "TraCIServerAPI_Lane.h"
81 
82 #include "TraCIServerAPI_TLS.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 
91 #ifdef CHECK_MEMORY_LEAKS
92 #include <foreign/nvwa/debug_new.h>
93 #endif // CHECK_MEMORY_LEAKS
94 
95 
96 // ===========================================================================
97 // static member definitions
98 // ===========================================================================
101 
102 
103 // ===========================================================================
104 // method definitions
105 // ===========================================================================
106 TraCIServer::TraCIServer(const SUMOTime begin, const int port)
107  : mySocket(0), myTargetTime(begin), myDoingSimStep(false), myAmEmbedded(port == 0), myLaneTree(0) {
108 
109  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
110  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
111  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
112  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
113  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
114  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
115  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_PARKING] = std::vector<std::string>();
116  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_PARKING] = std::vector<std::string>();
117  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_STOP] = std::vector<std::string>();
118  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_STOP] = std::vector<std::string>();
119  MSNet::getInstance()->addVehicleStateListener(this);
120 
124 
144 
146 
147  myDoCloseConnection = false;
148 
149  // display warning if internal lanes are not used
151  WRITE_WARNING("Starting TraCI without using internal lanes!");
152  MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
153  MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
154  }
155 
156  if (!myAmEmbedded) {
157  try {
158  WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
159  mySocket = new tcpip::Socket(port);
160  mySocket->accept();
161  // When got here, a client has connected
162  } catch (tcpip::SocketException& e) {
163  throw ProcessError(e.what());
164  }
165  }
166 }
167 
168 
170  MSNet::getInstance()->removeVehicleStateListener(this);
171  if (mySocket != NULL) {
172  mySocket->close();
173  delete mySocket;
174  }
175  for (std::map<int, NamedRTree*>::const_iterator i = myObjects.begin(); i != myObjects.end(); ++i) {
176  delete(*i).second;
177  }
178  delete myLaneTree;
179 }
180 
181 
182 // ---------- Initialisation and Shutdown
183 void
184 TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
185  if (myInstance == 0) {
186  if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
187  myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")),
188  OptionsCont::getOptions().getInt("remote-port"));
189  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
190  myInstance->myExecutors[i->first] = i->second;
191  }
192  }
193  }
194 }
195 
196 
197 void
199  if (myInstance != 0) {
200  delete myInstance;
201  myInstance = 0;
202  myDoCloseConnection = true;
203  }
204 }
205 
206 
207 bool
209  return myDoCloseConnection;
210 }
211 
212 
213 void
215  myVTDControlledVehicles[v->getID()] = v;
216  v->getInfluencer().setVTDControlled(true, l, pos, edgeOffset, route);
217 }
218 
219 void
221  for (std::map<std::string, MSVehicle*>::const_iterator i = myVTDControlledVehicles.begin(); i != myVTDControlledVehicles.end(); ++i) {
222  if (MSNet::getInstance()->getVehicleControl().getVehicle((*i).first) != 0) {
223  (*i).second->getInfluencer().postProcessVTD((*i).second);
224  } else {
225  WRITE_WARNING("Vehicle '" + (*i).first + "' was removed though being controlled by VTD");
226  }
227  }
228  myVTDControlledVehicles.clear();
229 }
230 
231 
232 bool
234  return true;
235 }
236 
237 
238 // ---------- Initialisation and Shutdown
239 
240 
241 void
243  if (!myDoCloseConnection) {
244  myVehicleStateChanges[to].push_back(vehicle->getID());
245  }
246 }
247 
248 
249 void
251  if (myInstance == 0) {
252  return;
253  }
254  try {
255  if (myInstance->myAmEmbedded || step < myInstance->myTargetTime) {
256  return;
257  }
258  // Simulation should run until
259  // 1. end time reached or
260  // 2. got CMD_CLOSE or
261  // 3. Client closes socket connection
262  if (myInstance->myDoingSimStep) {
264  myInstance->myDoingSimStep = false;
265  }
266  while (!myDoCloseConnection) {
268  if (myInstance->myOutputStorage.size() > 0) {
269  // send out all answers as one storage
271  }
274  // Read a message
276  }
278  // dispatch each command
279  int cmd = myInstance->dispatchCommand();
280  if (cmd == CMD_SIMSTEP2) {
281  myInstance->myDoingSimStep = true;
282  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
283  (*i).second.clear();
284  }
285  return;
286  }
287  }
288  }
290  // send out all answers as one storage
292  }
293  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
294  (*i).second.clear();
295  }
296  } catch (std::invalid_argument& e) {
297  throw ProcessError(e.what());
298  } catch (TraCIException& e) {
299  throw ProcessError(e.what());
300  } catch (tcpip::SocketException& e) {
301  throw ProcessError(e.what());
302  }
303  if (myInstance != NULL) {
304  delete myInstance;
305  myInstance = 0;
306  myDoCloseConnection = true;
307  }
308 }
309 
310 
311 
312 
313 #ifdef HAVE_PYTHON
314 // ===========================================================================
315 // python functions (traciemb module)
316 // ===========================================================================
317 static PyObject*
318 traciemb_execute(PyObject* /* self */, PyObject* args) {
319  const char* msg;
320  int size;
321  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
322  return NULL;
323  }
324  std::string result = TraCIServer::execute(std::string(msg, size));
325  return Py_BuildValue("s#", result.c_str(), result.size());
326 }
327 
328 static PyMethodDef EmbMethods[] = {
329  {
330  "execute", traciemb_execute, METH_VARARGS,
331  "Execute the given TraCI command and return the result."
332  },
333  {NULL, NULL, 0, NULL}
334 };
335 
336 
337 std::string
338 TraCIServer::execute(std::string cmd) {
339  try {
340  if (myInstance == 0) {
341  if (!myDoCloseConnection) {
342  myInstance = new TraCIServer(string2time(OptionsCont::getOptions().getString("begin")));
343  } else {
344  return "";
345  }
346  }
349  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
351  }
353  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
354  } catch (std::invalid_argument& e) {
355  throw ProcessError(e.what());
356  } catch (TraCIException& e) {
357  throw ProcessError(e.what());
358  } catch (tcpip::SocketException& e) {
359  throw ProcessError(e.what());
360  }
361 }
362 
363 
364 void
365 TraCIServer::runEmbedded(std::string pyFile) {
366  PyObject* pName, *pModule;
367  Py_Initialize();
368  Py_InitModule("traciemb", EmbMethods);
369  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
370  PyObject* sys_path, *path;
371  char pathstr[] = "path";
372  sys_path = PySys_GetObject(pathstr);
373  if (sys_path == NULL || !PyList_Check(sys_path)) {
374  throw ProcessError("Could not access python sys.path!");
375  }
376  path = PyString_FromString(FileHelpers::getFilePath(pyFile).c_str());
377  PyList_Insert(sys_path, 0, path);
378  Py_DECREF(path);
379  FILE* pFile = fopen(pyFile.c_str(), "r");
380  if (pFile == NULL) {
381  throw ProcessError("Failed to load \"" + pyFile + "\"!");
382  }
383  PyRun_SimpleFile(pFile, pyFile.c_str());
384  fclose(pFile);
385  } else {
386  pName = PyString_FromString(pyFile.c_str());
387  /* Error checking of pName left out */
388  pModule = PyImport_Import(pName);
389  Py_DECREF(pName);
390  if (pModule == NULL) {
391  PyErr_Print();
392  throw ProcessError("Failed to load \"" + pyFile + "\"!");
393  }
394  }
395  Py_Finalize();
396 }
397 #endif
398 
399 
400 int
402  unsigned int commandStart = myInputStorage.position();
403  unsigned int commandLength = myInputStorage.readUnsignedByte();
404  if (commandLength == 0) {
405  commandLength = myInputStorage.readInt();
406  }
407 
408  int commandId = myInputStorage.readUnsignedByte();
409  bool success = false;
410  // dispatch commands
411  if (myExecutors.find(commandId) != myExecutors.end()) {
412  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
413  } else {
414  switch (commandId) {
415  case CMD_GETVERSION:
416  success = commandGetVersion();
417  break;
418  case CMD_SIMSTEP2: {
419  SUMOTime nextT = myInputStorage.readInt();
420  success = true;
421  if (nextT != 0) {
422  myTargetTime = nextT;
423  } else {
425  }
426  if (myAmEmbedded) {
427  MSNet::getInstance()->simulationStep();
429  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
430  (*i).second.clear();
431  }
432  }
433  return commandId;
434  }
435  case CMD_CLOSE:
436  success = commandCloseConnection();
437  break;
451  success = addObjectVariableSubscription(commandId, false);
452  break;
466  success = addObjectVariableSubscription(commandId, true);
467  break;
468  default:
469  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
470  }
471  }
472  if (!success) {
473  while (myInputStorage.valid_pos() && myInputStorage.position() < commandStart + commandLength) {
475  }
476  }
477  if (myInputStorage.position() != commandStart + commandLength) {
478  std::ostringstream msg;
479  msg << "Wrong position in requestMessage after dispatching command.";
480  msg << " Expected command length was " << commandLength;
481  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
482  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
483  myDoCloseConnection = true;
484  }
485  return commandId;
486 }
487 
488 
489 // ---------- Server-internal command handling
490 bool
492  std::string sumoVersion = VERSION_STRING;
493  // Prepare response
494  tcpip::Storage answerTmp;
495  answerTmp.writeInt(TRACI_VERSION);
496  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
497  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
499  // command length
500  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
501  // command type
503  // and the parameter dependant part
504  myOutputStorage.writeStorage(answerTmp);
505  return true;
506 }
507 
508 
509 bool
511  myDoCloseConnection = true;
512  // write answer
514  return true;
515 }
516 
517 
518 void
520  SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
522  int noActive = 0;
523  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
524  const Subscription& s = *i;
527  if ((s.endTime < t) || isArrivedVehicle) {
528  i = mySubscriptions.erase(i);
529  continue;
530  }
531  ++i;
532  if (s.beginTime > t) {
533  continue;
534  }
535  ++noActive;
536  }
537  myOutputStorage.writeInt(noActive);
538  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
539  const Subscription& s = *i;
540  if (s.beginTime > t) {
541  ++i;
542  continue;
543  }
544  tcpip::Storage into;
545  std::string errors;
546  bool ok = processSingleSubscription(s, into, errors);
548  if (ok) {
549  ++i;
550  } else {
551  i = mySubscriptions.erase(i);
552  }
553  }
554 }
555 
556 
557 void
558 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
559  writeStatusCmd(commandId, status, description, myOutputStorage);
560 }
561 
562 
563 void
564 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
565  if (status == RTYPE_ERR) {
566  WRITE_ERROR("Answered with error to command " + toHex(commandId, 2) + ": " + description);
567  } else if (status == RTYPE_NOTIMPLEMENTED) {
568  WRITE_ERROR("Requested command not implemented (" + toHex(commandId, 2) + "): " + description);
569  }
570  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
571  outputStorage.writeUnsignedByte(commandId); // command type
572  outputStorage.writeUnsignedByte(status); // status
573  outputStorage.writeString(description); // description
574 }
575 
576 
577 bool
578 TraCIServer::writeErrorStatusCmd(int commandId, const std::string& description, tcpip::Storage& outputStorage) {
579  writeStatusCmd(commandId, RTYPE_ERR, description, outputStorage);
580  return false;
581 }
582 
583 
584 void
586  tcpip::Storage writeInto;
587  std::string errors;
588  if (processSingleSubscription(s, writeInto, errors)) {
590  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
591  } else {
592  mySubscriptions.push_back(s);
594  }
595  } else {
596  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
597  }
598  myOutputStorage.writeStorage(writeInto);
599 }
600 
601 
602 void
603 TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
604  bool found = false;
605  for (std::vector<Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
606  if ((*j).id == id && (*j).commandId == commandId && (domain < 0 || (*j).contextDomain == domain)) {
607  j = mySubscriptions.erase(j);
608  found = true;
609  continue;
610  }
611  ++j;
612  }
613  // try unsubscribe
614  if (found) {
615  writeStatusCmd(commandId, RTYPE_OK, "");
616  } else {
617  writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
618  }
619 }
620 
621 
622 bool
623 TraCIServer::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
624  Position p;
625  switch (domain) {
628  shape.push_back(p);
629  return true;
630  }
631  break;
633  break;
635  break;
637  if (TraCIServerAPI_Lane::getShape(id, shape)) {
638  return true;
639  }
640  break;
643  shape.push_back(p);
644  return true;
645  }
646  break;
648  break;
650  break;
652  if (TraCIServerAPI_POI::getPosition(id, p)) {
653  shape.push_back(p);
654  return true;
655  }
656  return false;
658  if (TraCIServerAPI_Polygon::getShape(id, shape)) {
659  return true;
660  }
661  break;
664  shape.push_back(p);
665  return true;
666  }
667  break;
669  if (TraCIServerAPI_Edge::getShape(id, shape)) {
670  return true;
671  }
672  break;
674  return false;
676  break;
677  default:
678  break;
679  }
680  return false;
681 }
682 
683 void
684 TraCIServer::collectObjectsInRange(int domain, const PositionVector& shape, SUMOReal range, std::set<std::string>& into) {
685  // build the look-up tree if not yet existing
686  if (myObjects.find(domain) == myObjects.end()) {
687  switch (domain) {
690  break;
699  break;
702  break;
705  break;
708  break;
709  default:
710  break;
711  }
712  }
713  const Boundary b = shape.getBoxBoundary().grow(range);
714  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
715  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
716  switch (domain) {
721  Named::StoringVisitor sv(into);
722  myObjects[domain]->Search(cmin, cmax, sv);
723  }
724  break;
728  TraCIServerAPI_Lane::StoringVisitor sv(into, shape, range, domain);
729  myLaneTree->Search(cmin, cmax, sv);
730  }
731  break;
732  default:
733  break;
734  }
735 }
736 
737 
738 bool
740  std::string& errors) {
741  bool ok = true;
742  tcpip::Storage outputStorage;
743  const int getCommandId = s.contextVars ? s.contextDomain : s.commandId - 0x30;
744  std::set<std::string> objIDs;
745  if (s.contextVars) {
746  PositionVector shape;
747  if (!findObjectShape(s.commandId, s.id, shape)) {
748  return false;
749  }
750  collectObjectsInRange(s.contextDomain, shape, s.range, objIDs);
751  } else {
752  objIDs.insert(s.id);
753  }
754  const int numVars = s.contextVars && s.variables.size() == 1 && s.variables[0] == ID_LIST ? 0 : (int)s.variables.size();
755  for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
756  if (s.contextVars) {
757  outputStorage.writeString(*j);
758  }
759  if (numVars > 0) {
760  std::vector<std::vector<unsigned char> >::const_iterator k = s.parameters.begin();
761  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i, ++k) {
762  tcpip::Storage message;
763  message.writeUnsignedByte(*i);
764  message.writeString(*j);
765  message.writePacket(*k);
766  tcpip::Storage tmpOutput;
767  if (myExecutors.find(getCommandId) != myExecutors.end()) {
768  ok &= myExecutors[getCommandId](*this, message, tmpOutput);
769  } else {
770  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
771  ok = false;
772  }
773  // copy response part
774  if (ok) {
775  int length = tmpOutput.readUnsignedByte();
776  while (--length > 0) {
777  tmpOutput.readUnsignedByte();
778  }
779  int lengthLength = 1;
780  length = tmpOutput.readUnsignedByte();
781  if (length == 0) {
782  lengthLength = 5;
783  length = tmpOutput.readInt();
784  }
785  //read responseType
786  tmpOutput.readUnsignedByte();
787  int variable = tmpOutput.readUnsignedByte();
788  std::string id = tmpOutput.readString();
789  outputStorage.writeUnsignedByte(variable);
790  outputStorage.writeUnsignedByte(RTYPE_OK);
791  length -= (lengthLength + 1 + 4 + (int)id.length());
792  while (--length > 0) {
793  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
794  }
795  } else {
796  //read length
797  tmpOutput.readUnsignedByte();
798  //read cmd
799  tmpOutput.readUnsignedByte();
800  //read status
801  tmpOutput.readUnsignedByte();
802  std::string msg = tmpOutput.readString();
803  outputStorage.writeUnsignedByte(*i);
804  outputStorage.writeUnsignedByte(RTYPE_ERR);
805  outputStorage.writeUnsignedByte(TYPE_STRING);
806  outputStorage.writeString(msg);
807  errors = errors + msg;
808  }
809  }
810  }
811  }
812  unsigned int length = (1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size();
813  if (s.contextVars) {
814  length += 4;
815  }
816  writeInto.writeUnsignedByte(0); // command length -> extended
817  writeInto.writeInt(length);
818  writeInto.writeUnsignedByte(s.commandId + 0x10);
819  writeInto.writeString(s.id);
820  if (s.contextVars) {
821  writeInto.writeUnsignedByte(s.contextDomain);
822  }
823  writeInto.writeUnsignedByte(numVars);
824  if (s.contextVars) {
825  writeInto.writeInt((int)objIDs.size());
826  }
827  if (!s.contextVars || objIDs.size() != 0) {
828  writeInto.writeStorage(outputStorage);
829  }
830  return ok;
831 }
832 
833 
834 bool
835 TraCIServer::addObjectVariableSubscription(const int commandId, const bool hasContext) {
836  const SUMOTime beginTime = myInputStorage.readInt();
837  const SUMOTime endTime = myInputStorage.readInt();
838  const std::string id = myInputStorage.readString();
839  const int domain = hasContext ? myInputStorage.readUnsignedByte() : 0;
840  const SUMOReal range = hasContext ? myInputStorage.readDouble() : 0.;
841  const int num = myInputStorage.readUnsignedByte();
842  std::vector<int> variables;
843  std::vector<std::vector<unsigned char> > parameters;
844  for (int i = 0; i < num; ++i) {
845  const int varID = myInputStorage.readUnsignedByte();
846  variables.push_back(varID);
847  parameters.push_back(std::vector<unsigned char>());
848  for (int j = 0; j < myParameterSizes[varID]; j++) {
849  parameters.back().push_back(myInputStorage.readChar());
850  }
851  }
852  // check subscribe/unsubscribe
853  if (variables.size() == 0) {
854  removeSubscription(commandId, id, -1);
855  return true;
856  }
857  // process subscription
858  Subscription s(commandId, id, variables, parameters, beginTime, endTime, hasContext, domain, range);
860  return true;
861 }
862 
863 
864 void
866  if (tempMsg.size() < 254) {
867  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
868  } else {
869  outputStorage.writeUnsignedByte(0); // command length -> extended
870  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
871  }
872  outputStorage.writeStorage(tempMsg);
873 }
874 
875 
876 bool
878  if (inputStorage.readUnsignedByte() != TYPE_INTEGER) {
879  return false;
880  }
881  into = inputStorage.readInt();
882  return true;
883 }
884 
885 
886 bool
888  if (inputStorage.readUnsignedByte() != TYPE_DOUBLE) {
889  return false;
890  }
891  into = inputStorage.readDouble();
892  return true;
893 }
894 
895 
896 bool
897 TraCIServer::readTypeCheckingString(tcpip::Storage& inputStorage, std::string& into) {
898  if (inputStorage.readUnsignedByte() != TYPE_STRING) {
899  return false;
900  }
901  into = inputStorage.readString();
902  return true;
903 }
904 
905 
906 bool
907 TraCIServer::readTypeCheckingStringList(tcpip::Storage& inputStorage, std::vector<std::string>& into) {
908  if (inputStorage.readUnsignedByte() != TYPE_STRINGLIST) {
909  return false;
910  }
911  into = inputStorage.readStringList();
912  return true;
913 }
914 
915 
916 bool
918  if (inputStorage.readUnsignedByte() != TYPE_COLOR) {
919  return false;
920  }
921  unsigned char r = static_cast<unsigned char>(inputStorage.readUnsignedByte());
922  unsigned char g = static_cast<unsigned char>(inputStorage.readUnsignedByte());
923  unsigned char b = static_cast<unsigned char>(inputStorage.readUnsignedByte());
924  unsigned char a = static_cast<unsigned char>(inputStorage.readUnsignedByte());
925  into.set(r, g, b, a);
926  return true;
927 }
928 
929 
930 bool
932  if (inputStorage.readUnsignedByte() != POSITION_2D) {
933  return false;
934  }
935  SUMOReal x = inputStorage.readDouble();
936  SUMOReal y = inputStorage.readDouble();
937  into.set(x, y, 0);
938  return true;
939 }
940 
941 
942 bool
944  if (inputStorage.readUnsignedByte() != TYPE_BOUNDINGBOX) {
945  return false;
946  }
947  const SUMOReal xmin = inputStorage.readDouble();
948  const SUMOReal ymin = inputStorage.readDouble();
949  const SUMOReal xmax = inputStorage.readDouble();
950  const SUMOReal ymax = inputStorage.readDouble();
951  into.set(xmin, ymin, xmax, ymax);
952  return true;
953 }
954 
955 
956 bool
958  if (inputStorage.readUnsignedByte() != TYPE_BYTE) {
959  return false;
960  }
961  into = inputStorage.readByte();
962  return true;
963 }
964 
965 
966 bool
968  if (inputStorage.readUnsignedByte() != TYPE_UBYTE) {
969  return false;
970  }
971  into = inputStorage.readUnsignedByte();
972  return true;
973 }
974 
975 
976 bool
978  if (inputStorage.readUnsignedByte() != TYPE_POLYGON) {
979  return false;
980  }
981  into.clear();
982  unsigned int noEntries = inputStorage.readUnsignedByte();
983  PositionVector shape;
984  for (unsigned int i = 0; i < noEntries; ++i) {
985  SUMOReal x = inputStorage.readDouble();
986  SUMOReal y = inputStorage.readDouble();
987  into.push_back(Position(x, y));
988  }
989  return true;
990 }
991 
992 #endif