/********************************************************************\ Bridge between two networks Subscription to top-level server list DIS_DNS/SERVER_LIST not via AddService() ensures AddService() only called from infoHandler(), thus serialized by DIM and no Mutex is necessary. Remote procedure calls are bridged through their underlying services and commands. Oliver Grimm, June 2010 \********************************************************************/ #define SERVER_NAME "Bridge" #include "Evidence.h" #include #include const int DEFAULT_PORT = 2505; using namespace std; // Class declaration class Bridge: public DimClient, public EvidenceServer { struct Item { string Name; DimCommand *Command; DimStampedInfo *DataItem; DimService *Service; char *Data; }; vector List; DimInfo *ServerList; void infoHandler(); void commandHandler(); void AddService(string, char *, int); void RemoveService(string); public: Bridge(char *, int); ~Bridge(); }; // Constructor Bridge::Bridge(char *Name, int Port): EvidenceServer(SERVER_NAME) { // Set primary DIM network to subscribe from DimClient::setDnsNode(Name, Port); // Subsribe to top-level server list ServerList = new DimInfo((char *) "DIS_DNS/SERVER_LIST", NO_LINK, this); } // Destructor: Delete all subscriptions and services Bridge::~Bridge() { while (List.size() != 0) RemoveService(List[0].Name); delete ServerList; } // Service subscription and repeating void Bridge::infoHandler() { DimInfo *I = getInfo(); // Check if service available if (!ServiceOK(I)) return; // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) { char *Token = strtok(I->getString(), "+-!@"); while (Token != NULL) { if (*I->getString() == '-' || *I->getString() == '!') { RemoveService(string(Token)+"/SERVICE_LIST"); } else AddService(string(Token)+"/SERVICE_LIST", (char *) "C", DimSERVICE); // Skip server IP address and process ID Token = strtok(NULL, "|"); Token = strtok(NULL, "@"); } return; } // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services if (strstr(I->getName(), "/SERVICE_LIST") != NULL) { char *Format, *Name = strtok(I->getString(), "+-!|"); while (Name != NULL) { if ((Format = strtok(NULL, "\n")) != NULL) { // Check if service added or removed/unavailable if (*I->getString() == '-' || *I->getString() == '!') { if (strstr(Format, "|RPC") != NULL) { RemoveService(string(Name)+"/RpcIn"); RemoveService(string(Name)+"/RpcOut"); } else RemoveService(Name); } else { // Determine type of service if (strstr(Format, "|CMD") != NULL) { *(strstr(Format, "|CMD")) = '\0'; AddService(Name, Format, DimCOMMAND); } else if (strstr(Format, "|RPC") != NULL) { *(strstr(Format, "|RPC")) = '\0'; if (strchr(Format, ',') != NULL) { *strchr(Format, ',') = '\0'; AddService(string(Name)+"/RpcIn", Format, DimCOMMAND); AddService(string(Name)+"/RpcOut", Format+strlen(Format)+1, DimSERVICE); } } else { Format[strlen(Format)-1] = '\0'; AddService(Name, Format, DimSERVICE); } } } Name = strtok(NULL, "|"); } return; } // Identify service and repeat to secondary DNS for (int Service=0; ServicegetSize()]; memcpy(List[Service].Data, I->getData(), I->getSize()); // Set new service properties and update service List[Service].Service->setQuality(I->getQuality()); List[Service].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs()); List[Service].Service->updateService(List[Service].Data, I->getSize()); } } // Command repeating void Bridge::commandHandler() { sendCommandNB(getCommand()->getName(), getCommand()->getData(), getCommand()->getSize()); } // Service subscription void Bridge::AddService(string Name, char *Format, int Type) { // Do not forward DIS_DNS and History services if ((Name.find("DIS_DNS/") != string::npos) || (Name.find("History/") != string::npos)) return; // Check if already subscribed to this service for (int i=0; i::iterator E; for (E=List.begin(); E [port] (default port %d)\n", argv[0], DEFAULT_PORT); exit(EXIT_FAILURE); } // Static ensures calling of destructor by exit() static Bridge Class(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT); // Sleep until signal caught pause(); }