/********************************************************************\ 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. Configuraton changes are automatically tracked through ConfigChanged() Oliver Grimm, June 2010 \********************************************************************/ #define SERVER_NAME "Bridge" #include "Evidence.h" #include #include #include const int DEFAULT_PORT = 2505; using namespace std; // Class declaration class Bridge: public DimClient, public EvidenceServer { struct Item { DimCommand *Command; DimStampedInfo *DataItem; DimService *Service; char *Data; }; map Map; vector RegEx; DimInfo *ServerList; void infoHandler(); void commandHandler(); void AddService(string, char *, int); void RemoveService(string); void ConfigChanged(); void BugFix(); void Undo(); public: Bridge(); ~Bridge(); }; // Constructor (ConfigChanged() is automatically called at start-up) Bridge::Bridge(): EvidenceServer(SERVER_NAME) { // Initialise ServerList = NULL; GetConfig("cmdallow", " "); } // Destructor Bridge::~Bridge() { Undo(); } // Undo: Delete all subscriptions and regular expressions void Bridge::Undo() { while (Map.size() != 0) RemoveService((*Map.begin()).first); delete ServerList; for (int i=0; i RegEx; vector Exclude = Tokenize(ExcludeString, " \t"); for (int i=0; igetName(), "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) { // Bug fix for empty SERVICE_LIST if (strlen(I->getString()) == 0) { string Tmp(I->getName()); RemoveService(I->getName()); AddService(Tmp.c_str(), (char *) "C", DimSERVICE); return; } 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; } // Check if service known and repeat to secondary DNS if (Map.count(I->getName()) == 0) return; // Copy service data delete[] Map[I->getName()].Data; Map[I->getName()].Data = new char [I->getSize()]; memcpy(Map[I->getName()].Data, I->getData(), I->getSize()); // Set new service properties and update service Map[I->getName()].Service->setQuality(I->getQuality()); Map[I->getName()].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs()); Map[I->getName()].Service->updateService(Map[I->getName()].Data, I->getSize()); } // Command repeating (also handles requests for remote procedure calls) void Bridge::commandHandler() { // Check if client allowed to send commands vector Client = Tokenize(getClientName(), "@"); if (Client.size() == 2 && GetConfig("cmdallow").find(Client[1]) == string::npos) { Message(INFO, "Rejected command/rpc from %s (ID %d)", getClientName(), getClientId()); return; } // Send command to server sendCommandNB(getCommand()->getName(), getCommand()->getData(), getCommand()->getSize()); } // Service subscription void Bridge::AddService(string Name, char *Format, int Type) { // Check if already subscribed to this service if (Map.count(Name) != 0) return; // Should service be ignored? for (int i=0; i [port] (default port %d)\n", argv[0], DEFAULT_PORT); exit(EXIT_FAILURE); } // Set primary DIM network to subscribe from DimClient::setDnsNode(argv[1], argc>2 ? atoi(argv[2]) : DEFAULT_PORT); // Static ensures calling of destructor by exit() static Bridge Class; // Sleep until signal caught while (!Class.ExitRequest) pause(); }