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 // ===========================================================================
103 TraCIServer* TraCIServer::myInstance = 0;
105 
106 
107 // ===========================================================================
108 // method definitions
109 // ===========================================================================
111  : mySocket(0), myTargetTime(0), myDoingSimStep(false), myHaveWarnedDeprecation(false), myAmEmbedded(port == 0) {
112 
113  myVehicleStateChanges[MSNet::VEHICLE_STATE_BUILT] = std::vector<std::string>();
114  myVehicleStateChanges[MSNet::VEHICLE_STATE_DEPARTED] = std::vector<std::string>();
115  myVehicleStateChanges[MSNet::VEHICLE_STATE_STARTING_TELEPORT] = std::vector<std::string>();
116  myVehicleStateChanges[MSNet::VEHICLE_STATE_ENDING_TELEPORT] = std::vector<std::string>();
117  myVehicleStateChanges[MSNet::VEHICLE_STATE_ARRIVED] = std::vector<std::string>();
118  myVehicleStateChanges[MSNet::VEHICLE_STATE_NEWROUTE] = std::vector<std::string>();
120 
141 
142  myDoCloseConnection = false;
143 
144  // display warning if internal lanes are not used
146  WRITE_WARNING("Starting TraCI without using internal lanes!");
147  MsgHandler::getWarningInstance()->inform("Vehicles will jump over junctions.", false);
148  MsgHandler::getWarningInstance()->inform("Use without option --no-internal-links to avoid unexpected behavior", false);
149  }
150 
151  if (!myAmEmbedded) {
152  try {
153  WRITE_MESSAGE("***Starting server on port " + toString(port) + " ***");
154  mySocket = new tcpip::Socket(port);
155  mySocket->accept();
156  // When got here, a client has connected
157  } catch (tcpip::SocketException& e) {
158  throw ProcessError(e.what());
159  }
160  }
161 }
162 
163 
166  if (mySocket != NULL) {
167  mySocket->close();
168  delete mySocket;
169  }
170  for (std::map<int, TraCIRTree*>::const_iterator i = myObjects.begin(); i != myObjects.end(); ++i) {
171  delete(*i).second;
172  }
173 }
174 
175 
176 // ---------- Initialisation and Shutdown
177 void
178 TraCIServer::openSocket(const std::map<int, CmdExecutor>& execs) {
179  if (myInstance == 0) {
180  if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
181  myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
182  for (std::map<int, CmdExecutor>::const_iterator i = execs.begin(); i != execs.end(); ++i) {
183  myInstance->myExecutors[i->first] = i->second;
184  }
185  }
186  }
187 }
188 
189 
190 void
192  if (myInstance != 0) {
193  delete myInstance;
194  myInstance = 0;
195  myDoCloseConnection = true;
196  }
197 }
198 
199 
200 bool
202  return myDoCloseConnection;
203 }
204 
205 
206 // ---------- Initialisation and Shutdown
207 
208 
209 void
211  if (myDoCloseConnection || OptionsCont::getOptions().getInt("remote-port") == 0) {
212  return;
213  }
214  myVehicleStateChanges[to].push_back(vehicle->getID());
215 }
216 
217 
218 void
220  try {
221  if (myInstance == 0) {
222  if (!myDoCloseConnection && OptionsCont::getOptions().getInt("remote-port") != 0) {
223  myInstance = new traci::TraCIServer(OptionsCont::getOptions().getInt("remote-port"));
224  } else {
225  return;
226  }
227  }
228  if (myInstance->myAmEmbedded || step < myInstance->myTargetTime) {
229  return;
230  }
231  // Simulation should run until
232  // 1. end time reached or
233  // 2. got CMD_CLOSE or
234  // 3. Client closes socket connection
235  if (myInstance->myDoingSimStep) {
237  myInstance->myDoingSimStep = false;
238  }
239  while (!myDoCloseConnection) {
241  if (myInstance->myOutputStorage.size() > 0) {
242  // send out all answers as one storage
244  }
247  // Read a message
249  }
251  // dispatch each command
252  int cmd = myInstance->dispatchCommand();
253  if (cmd == CMD_SIMSTEP2) {
254  myInstance->myDoingSimStep = true;
255  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
256  (*i).second.clear();
257  }
258  return;
259  }
260  }
261  }
263  // send out all answers as one storage
265  }
266  for (std::map<MSNet::VehicleState, std::vector<std::string> >::iterator i = myInstance->myVehicleStateChanges.begin(); i != myInstance->myVehicleStateChanges.end(); ++i) {
267  (*i).second.clear();
268  }
269  } catch (std::invalid_argument& e) {
270  throw ProcessError(e.what());
271  } catch (TraCIException& e) {
272  throw ProcessError(e.what());
273  } catch (tcpip::SocketException& e) {
274  throw ProcessError(e.what());
275  }
276  if (myInstance != NULL) {
277  delete myInstance;
278  myInstance = 0;
279  myDoCloseConnection = true;
280  }
281 }
282 
283 
284 
285 
286 #ifdef HAVE_PYTHON
287 // ===========================================================================
288 // python functions (traciemb module)
289 // ===========================================================================
290 static PyObject*
291 traciemb_execute(PyObject* /* self */, PyObject* args) {
292  const char* msg;
293  int size;
294  if (!PyArg_ParseTuple(args, "s#", &msg, &size)) {
295  return NULL;
296  }
297  std::string result = traci::TraCIServer::execute(std::string(msg, size));
298  return Py_BuildValue("s#", result.c_str(), result.size());
299 }
300 
301 static PyMethodDef EmbMethods[] = {
302  {
303  "execute", traciemb_execute, METH_VARARGS,
304  "Execute the given TraCI command and return the result."
305  },
306  {NULL, NULL, 0, NULL}
307 };
308 
309 
310 std::string
311 TraCIServer::execute(std::string cmd) {
312  try {
313  if (myInstance == 0) {
314  if (!myDoCloseConnection) {
316  } else {
317  return "";
318  }
319  }
322  for (std::string::iterator i = cmd.begin(); i != cmd.end(); ++i) {
324  }
326  return std::string(myInstance->myOutputStorage.begin(), myInstance->myOutputStorage.end());
327  } catch (std::invalid_argument& e) {
328  throw ProcessError(e.what());
329  } catch (TraCIException& e) {
330  throw ProcessError(e.what());
331  } catch (tcpip::SocketException& e) {
332  throw ProcessError(e.what());
333  }
334 }
335 
336 
337 void
338 TraCIServer::runEmbedded(std::string pyFile) {
339  PyObject* pName, *pModule;
340  Py_Initialize();
341  Py_InitModule("traciemb", EmbMethods);
342  if (pyFile.length() > 3 && !pyFile.compare(pyFile.length() - 3, 3, ".py")) {
343  FILE* pFile = fopen(pyFile.c_str(), "r");
344  PyRun_SimpleFile(pFile, pyFile.c_str());
345  fclose(pFile);
346  } else {
347  pName = PyString_FromString(pyFile.c_str());
348  /* Error checking of pName left out */
349  pModule = PyImport_Import(pName);
350  Py_DECREF(pName);
351  if (pModule == NULL) {
352  PyErr_Print();
353  throw ProcessError("Failed to load \"" + pyFile + "\"!");
354  }
355  }
356  Py_Finalize();
357 }
358 #endif
359 
360 
361 int
363  unsigned int commandStart = myInputStorage.position();
364  unsigned int commandLength = myInputStorage.readUnsignedByte();
365  if (commandLength == 0) {
366  commandLength = myInputStorage.readInt();
367  }
368 
369  int commandId = myInputStorage.readUnsignedByte();
370  bool success = false;
371  // dispatch commands
372  if (myExecutors.find(commandId) != myExecutors.end()) {
373  success = myExecutors[commandId](*this, myInputStorage, myOutputStorage);
374  } else {
375  switch (commandId) {
376  case CMD_GETVERSION:
377  success = commandGetVersion();
378  break;
379  case CMD_SIMSTEP2: {
380  SUMOTime nextT = myInputStorage.readInt();
381  success = true;
382  if (nextT != 0) {
383  myTargetTime = nextT;
384  } else {
386  }
387  if (myAmEmbedded) {
390  }
391  return commandId;
392  }
393  case CMD_CLOSE:
394  success = commandCloseConnection();
395  break;
396  case CMD_ADDVEHICLE:
398  WRITE_WARNING("Using old TraCI API, please update your client!");
400  }
401  success = commandAddVehicle();
402  break;
416  success = addObjectVariableSubscription(commandId);
417  break;
431  success = addObjectContextSubscription(commandId);
432  break;
433  default:
434  writeStatusCmd(commandId, RTYPE_NOTIMPLEMENTED, "Command not implemented in sumo");
435  }
436  }
437  if (!success) {
438  while (myInputStorage.valid_pos() && myInputStorage.position() < commandStart + commandLength) {
440  }
441  }
442  if (myInputStorage.position() != commandStart + commandLength) {
443  std::ostringstream msg;
444  msg << "Wrong position in requestMessage after dispatching command.";
445  msg << " Expected command length was " << commandLength;
446  msg << " but " << myInputStorage.position() - commandStart << " Bytes were read.";
447  writeStatusCmd(commandId, RTYPE_ERR, msg.str());
448  myDoCloseConnection = true;
449  }
450  return commandId;
451 }
452 
453 
454 // ---------- Server-internal command handling
455 bool
457  std::string sumoVersion = VERSION_STRING;
458  // Prepare response
459  tcpip::Storage answerTmp;
460  answerTmp.writeInt(TRACI_VERSION);
461  answerTmp.writeString(std::string("SUMO ") + sumoVersion);
462  // When we get here, the response is stored in answerTmp -> put into myOutputStorage
464  // command length
465  myOutputStorage.writeUnsignedByte(1 + 1 + static_cast<int>(answerTmp.size()));
466  // command type
468  // and the parameter dependant part
469  myOutputStorage.writeStorage(answerTmp);
470  return true;
471 }
472 
473 
474 bool
476  myDoCloseConnection = true;
477  // write answer
478  writeStatusCmd(CMD_CLOSE, RTYPE_OK, "Goodbye");
479  return true;
480 }
481 
482 
483 void
487  int noActive = 0;
488  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
489  const Subscription& s = *i;
491  if ((s.endTime < t) || isArrivedVehicle) {
492  i = mySubscriptions.erase(i);
493  continue;
494  }
495  ++i;
496  if (s.beginTime > t) {
497  continue;
498  }
499  ++noActive;
500  }
501  myOutputStorage.writeInt(noActive);
502  for (std::vector<Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end(); ++i) {
503  const Subscription& s = *i;
504  if (s.beginTime > t) {
505  continue;
506  }
507  tcpip::Storage into;
508  std::string errors;
509  processSingleSubscription(s, into, errors);
511  }
512 }
513 
514 
515 bool
517 
518  // read parameters
519  std::string vehicleId = myInputStorage.readString();
520  std::string vehicleTypeId = myInputStorage.readString();
521  std::string routeId = myInputStorage.readString();
522  std::string laneId = myInputStorage.readString();
523  SUMOReal insertionPosition = myInputStorage.readFloat();
524  SUMOReal insertionSpeed = myInputStorage.readFloat();
525 
526  // find vehicleType
527  MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(vehicleTypeId);
528  if (!vehicleType) {
529  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid vehicleTypeId: '" + vehicleTypeId + "'");
530  return false;
531  }
532 
533  // find route
534  const MSRoute* route = MSRoute::dictionary(routeId);
535  if (!route) {
536  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid routeId: '" + routeId + "'");
537  return false;
538  }
539 
540  // find lane
541  MSLane* lane;
542  if (laneId != "") {
543  lane = MSLane::dictionary(laneId);
544  if (!lane) {
545  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Invalid laneId: '" + laneId + "'");
546  return false;
547  }
548  } else {
549  lane = route->getEdges()[0]->getLanes()[0];
550  if (!lane) {
551  writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not find first lane of first edge in routeId '" + routeId + "'");
552  return false;
553  }
554  }
555 
556  if (&lane->getEdge() != *route->begin()) {
557  writeStatusCmd(CMD_STOP, RTYPE_ERR, "The route must start at the edge the lane starts at.");
558  return false;
559  }
560 
561  // build vehicle
562  SUMOVehicleParameter* vehicleParams = new SUMOVehicleParameter();
563  vehicleParams->id = vehicleId;
564  vehicleParams->depart = MSNet::getInstance()->getCurrentTimeStep() + 1;
565  MSVehicle* vehicle = static_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(vehicleParams, route, vehicleType));
566  if (vehicle == NULL) {
567  writeStatusCmd(CMD_STOP, RTYPE_ERR, "Could not build vehicle");
568  return false;
569  }
570 
571  // calculate speed
572  float clippedInsertionSpeed;
573  if (insertionSpeed < 0) {
574  clippedInsertionSpeed = (float) MIN2(lane->getVehicleMaxSpeed(vehicle), vehicle->getMaxSpeed());
575  } else {
576  clippedInsertionSpeed = (float) MIN3(lane->getVehicleMaxSpeed(vehicle), vehicle->getMaxSpeed(), insertionSpeed);
577  }
578 
579  // insert vehicle into the dictionary
580  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
581  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not add vehicle to VehicleControl");
582  return false;
583  }
584 
585  // try to emit
586  if (!lane->isInsertionSuccess(vehicle, clippedInsertionSpeed, insertionPosition, true)) {
588  writeStatusCmd(CMD_ADDVEHICLE, RTYPE_ERR, "Could not insert vehicle");
589  return false;
590  }
591 
592  // exec callback
593  vehicle->onDepart();
594 
595  // create a reply message
597 
598  return true;
599 }
600 
601 
602 void
603 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description) {
604  writeStatusCmd(commandId, status, description, myOutputStorage);
605 }
606 
607 
608 void
609 TraCIServer::writeStatusCmd(int commandId, int status, const std::string& description, tcpip::Storage& outputStorage) {
610  if (status == RTYPE_ERR) {
611  WRITE_ERROR("Answered with error to command " + toString(commandId) + ": " + description);
612  } else if (status == RTYPE_NOTIMPLEMENTED) {
613  WRITE_ERROR("Requested command not implemented (" + toString(commandId) + "): " + description);
614  }
615  outputStorage.writeUnsignedByte(1 + 1 + 1 + 4 + static_cast<int>(description.length())); // command length
616  outputStorage.writeUnsignedByte(commandId); // command type
617  outputStorage.writeUnsignedByte(status); // status
618  outputStorage.writeString(description); // description
619 }
620 
621 
622 void
624  tcpip::Storage writeInto;
625  std::string errors;
626  if (processSingleSubscription(s, writeInto, errors)) {
628  writeStatusCmd(s.commandId, RTYPE_ERR, "Subscription has ended.");
629  } else {
630  mySubscriptions.push_back(s);
632  }
633  } else {
634  writeStatusCmd(s.commandId, RTYPE_ERR, "Could not add subscription (" + errors + ").");
635  }
636  myOutputStorage.writeStorage(writeInto);
637 }
638 
639 
640 void
641 TraCIServer::removeSubscription(int commandId, const std::string& id, int domain) {
642  bool found = false;
643  for (std::vector<Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
644  if ((*j).id == id && (*j).commandId == commandId && (domain < 0 || (*j).contextDomain == domain)) {
645  j = mySubscriptions.erase(j);
646  found = true;
647  continue;
648  }
649  ++j;
650  }
651  // try unsubscribe
652  if (found) {
653  writeStatusCmd(commandId, RTYPE_OK, "");
654  } else {
655  writeStatusCmd(commandId, RTYPE_OK, "The subscription to remove was not found.");
656  }
657 }
658 
659 
660 bool
661 TraCIServer::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
662  Position p;
663  switch (domain) {
666  shape.push_back(p);
667  break;
668  }
669  return false;
671  return false;
673  return false;
675  if (TraCIServerAPI_Lane::getShape(id, shape)) {
676  break;
677  }
678  return false;
681  shape.push_back(p);
682  break;
683  }
684  return false;
686  return false;
688  return false;
690  if (TraCIServerAPI_POI::getPosition(id, p)) {
691  shape.push_back(p);
692  break;
693  }
694  return false;
696  if (TraCIServerAPI_Polygon::getShape(id, shape)) {
697  break;
698  }
699  return false;
702  shape.push_back(p);
703  break;
704  }
705  return false;
707  if (TraCIServerAPI_Edge::getShape(id, shape)) {
708  break;
709  }
710  return false;
712  return false;
714  return false;
715  default:
716  return false;
717  }
718  return true;
719 }
720 
721 void
722 TraCIServer::collectObjectsInRange(int domain, const PositionVector& shape, SUMOReal range, std::set<std::string>& into) {
723  // build the look-up tree if not yet existing
724  if (myObjects.find(domain) == myObjects.end()) {
725  switch (domain) {
728  break;
730  break;
731  case CMD_GET_TL_VARIABLE:
732  break;
735  break;
737  if (myObjects.find(CMD_GET_LANE_VARIABLE) == myObjects.end()) {
739  }
740  break;
742  break;
744  break;
747  break;
750  break;
753  break;
756  break;
758  break;
760  break;
761  default:
762  break;
763  }
764  }
765  const Boundary b = shape.getBoxBoundary().grow(range);
766  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
767  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
768  switch (domain) {
770  Named::StoringVisitor sv(into);
771  myObjects[CMD_GET_INDUCTIONLOOP_VARIABLE]->Search(cmin, cmax, sv);
772  }
773  break;
775  break;
776  case CMD_GET_TL_VARIABLE:
777  break;
778  case CMD_GET_LANE_VARIABLE: {
779  Named::StoringVisitor sv(into);
780  myObjects[CMD_GET_LANE_VARIABLE]->Search(cmin, cmax, sv);
781  if (shape.size() == 1) {
782  for (std::set<std::string>::iterator i = into.begin(); i != into.end();) {
783  const MSLane* const l = MSLane::dictionary(*i);
784  if (l->getShape().distance(shape[0]) > range) {
785  into.erase(i++);
786  } else {
787  ++i;
788  }
789  }
790  }
791  }
792  break;
794  std::set<std::string> tmp;
795  Named::StoringVisitor sv(tmp);
796  myObjects[CMD_GET_LANE_VARIABLE]->Search(cmin, cmax, sv);
797  for (std::set<std::string>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
798  MSLane* l = MSLane::dictionary(*i);
799  if (l != 0) {
800  const std::deque<MSVehicle*>& vehs = l->getVehiclesSecure();
801  for (std::deque<MSVehicle*>::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
802  if (shape.distance((*j)->getPosition()) <= range) {
803  into.insert((*j)->getID());
804  }
805  }
806  l->releaseVehicles();
807  }
808  }
809  }
810  break;
812  break;
814  break;
815  case CMD_GET_POI_VARIABLE: {
816  Named::StoringVisitor sv(into);
817  myObjects[CMD_GET_POI_VARIABLE]->Search(cmin, cmax, sv);
818  }
819  break;
821  Named::StoringVisitor sv(into);
822  myObjects[CMD_GET_POLYGON_VARIABLE]->Search(cmin, cmax, sv);
823  }
824  break;
826  Named::StoringVisitor sv(into);
827  myObjects[CMD_GET_JUNCTION_VARIABLE]->Search(cmin, cmax, sv);
828  }
829  break;
830  case CMD_GET_EDGE_VARIABLE: {
831  Named::StoringVisitor sv(into);
832  myObjects[CMD_GET_EDGE_VARIABLE]->Search(cmin, cmax, sv);
833  }
834  break;
836  break;
838  break;
839  default:
840  break;
841  }
842 }
843 
844 
845 bool
847  std::string& errors) {
848  bool ok = true;
849  tcpip::Storage outputStorage;
850  int getCommandId = s.contextVars ? s.contextDomain : s.commandId - 0x30;
851  std::set<std::string> objIDs;
852  if (s.contextVars) {
853  getCommandId = s.contextDomain;
854  PositionVector shape;
855  if (!findObjectShape(s.commandId, s.id, shape)) {
856  return false;
857  }
858  collectObjectsInRange(s.contextDomain, shape, s.range, objIDs);
859  } else {
860  getCommandId = s.commandId - 0x30;
861  objIDs.insert(s.id);
862  }
863 
864  for (std::set<std::string>::iterator j = objIDs.begin(); j != objIDs.end(); ++j) {
865  if (s.contextVars) {
866  outputStorage.writeString(*j);
867  }
868  for (std::vector<int>::const_iterator i = s.variables.begin(); i != s.variables.end(); ++i) {
869  tcpip::Storage message;
870  message.writeUnsignedByte(*i);
871  message.writeString(*j);
872  tcpip::Storage tmpOutput;
873  if (myExecutors.find(getCommandId) != myExecutors.end()) {
874  ok &= myExecutors[getCommandId](*this, message, tmpOutput);
875  } else {
876  writeStatusCmd(s.commandId, RTYPE_NOTIMPLEMENTED, "Unsupported command specified", tmpOutput);
877  ok = false;
878  }
879  // copy response part
880  if (ok) {
881  int length = tmpOutput.readUnsignedByte();
882  while (--length > 0) {
883  tmpOutput.readUnsignedByte();
884  }
885  int lengthLength = 1;
886  length = tmpOutput.readUnsignedByte();
887  if (length == 0) {
888  lengthLength = 5;
889  length = tmpOutput.readInt();
890  }
891  //read responseType
892  tmpOutput.readUnsignedByte();
893  int variable = tmpOutput.readUnsignedByte();
894  std::string id = tmpOutput.readString();
895  outputStorage.writeUnsignedByte(variable);
896  outputStorage.writeUnsignedByte(RTYPE_OK);
897  length -= (lengthLength + 1 + 4 + (int)id.length());
898  while (--length > 0) {
899  outputStorage.writeUnsignedByte(tmpOutput.readUnsignedByte());
900  }
901  } else {
902  //read length
903  tmpOutput.readUnsignedByte();
904  //read cmd
905  tmpOutput.readUnsignedByte();
906  //read status
907  tmpOutput.readUnsignedByte();
908  std::string msg = tmpOutput.readString();
909  outputStorage.writeUnsignedByte(*i);
910  outputStorage.writeUnsignedByte(RTYPE_ERR);
911  outputStorage.writeUnsignedByte(TYPE_STRING);
912  outputStorage.writeString(msg);
913  errors = errors + msg;
914  }
915  }
916  }
917  unsigned int length = (1 + 4) + 1 + (4 + (int)(s.id.length())) + 1 + (int)outputStorage.size();
918  if (s.contextVars) {
919  length += 4;
920  }
921  writeInto.writeUnsignedByte(0); // command length -> extended
922  writeInto.writeInt(length);
923  writeInto.writeUnsignedByte(s.commandId + 0x10);
924  writeInto.writeString(s.id);
925  if (s.contextVars) {
926  writeInto.writeUnsignedByte(s.contextDomain);
927  }
928  writeInto.writeUnsignedByte((int)(s.variables.size()));
929  if (s.contextVars) {
930  writeInto.writeInt((int)objIDs.size());
931  }
932  if (!s.contextVars || objIDs.size() != 0) {
933  writeInto.writeStorage(outputStorage);
934  }
935  return ok;
936 }
937 
938 
939 bool
941  SUMOTime beginTime = myInputStorage.readInt();
942  SUMOTime endTime = myInputStorage.readInt();
943  std::string id = myInputStorage.readString();
944  int no = myInputStorage.readUnsignedByte();
945  std::vector<int> variables;
946  for (int i = 0; i < no; ++i) {
947  variables.push_back(myInputStorage.readUnsignedByte());
948  }
949  // check subscribe/unsubscribe
950  if (variables.size() == 0) {
951  removeSubscription(commandId, id, -1);
952  return true;
953  }
954  // process subscription
955  Subscription s(commandId, id, variables, beginTime, endTime, false, 0, 0);
957  return true;
958 }
959 
960 
961 bool
963  SUMOTime beginTime = myInputStorage.readInt();
964  SUMOTime endTime = myInputStorage.readInt();
965  std::string id = myInputStorage.readString();
966  int domain = myInputStorage.readUnsignedByte();
968  int no = myInputStorage.readUnsignedByte();
969  std::vector<int> variables;
970  for (int i = 0; i < no; ++i) {
971  variables.push_back(myInputStorage.readUnsignedByte());
972  }
973  // check subscribe/unsubscribe
974  if (variables.size() == 0) {
975  removeSubscription(commandId, id, -1);
976  return true;
977  }
978  Subscription s(commandId, id, variables, beginTime, endTime, true, domain, range);
980  return true;
981 }
982 
983 
984 void
986  if (tempMsg.size() < 254) {
987  outputStorage.writeUnsignedByte(1 + (int)tempMsg.size()); // command length -> short
988  } else {
989  outputStorage.writeUnsignedByte(0); // command length -> extended
990  outputStorage.writeInt(1 + 4 + (int)tempMsg.size());
991  }
992  outputStorage.writeStorage(tempMsg);
993 }
994 
995 }
996 
997 #endif