#include #include #include // ***************************************************************************** // * newCLIPService: // * This function will be called by the cdevSystem object to create an // * initial instance of the CLIPService. // ***************************************************************************** extern "C" cdevService * newCLIPService (char * name, cdevSystem * system) { return new CLIPService(name, *system); } void NULLError (int, char *, cdevRequestObject *) { } // ***************************************************************************** // * CLIPService::CLIPService : // * This is the constructor for the CLIPService. It initializes the // * underlying CLIPService by specifying that it is in the domain of // * VIRTUAL. // ***************************************************************************** CLIPService::CLIPService ( char * name, cdevSystem & system) : cdevClientService("CLIP", name, system) { system.reportError(CDEV_SEVERITY_INFO, "CLIPService", NULL, "Constructing a new CLIPService"); } // ***************************************************************************** // * CLIPService::getRequestObject : // * This is the interface that cdev objects will use to obtain a // * CLIPRequestObject object. The CLIPRequestObject // * represents a combined device and message pair that is associated // * with the CLIPService. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ***************************************************************************** int CLIPService::getRequestObject ( char * device, char * message, cdevRequestObject * &req) { req = new CLIPRequestObject (device, message, system_); return (req ? CDEV_SUCCESS : CDEV_ERROR); } // ***************************************************************************** // * CLIPService::connect : // * This mechanism will establish a new connection with a server and will // * will return a pointer to the ServerHandler. If the host and port are // * specified in the arguments, then the method will attempt to connect // * using those values without going through the CDEV Name Server. // * // * Note: This method will insert the ServerHandler into the connections // * object and will install it in the Reactor. // ***************************************************************************** ServerHandler * CLIPService::connect ( char * server, char * host, short port ) { ServerHandler * handler = NULL; // ********************************************************************* // * First attempt to locate the handler from the existing connections. // ********************************************************************* if(server && *server && (handler = connections.find(server))==NULL) { int errCode = CDEV_SUCCESS; char serverHost[255]; short serverPort; int serverStatus; int hostMatchesNS; // ************************************************************* // * Initialize these values to reflect a server that is not // * defined within the name server. // ************************************************************* *serverHost = 0; serverPort = 0; serverStatus = 2; hostMatchesNS = 0; // ************************************************************* // * Raise the error threshold to reduce noise while the service // * tries to resolve the location of the server. // ************************************************************* system_.setThreshold(100); // ************************************************************* // * In this implementation we will always attempt to resolve // * the location of the server using the name server first, to // * determine if monitoring can be installed later... // ************************************************************* cdevData input; cdevData output; cdevRequestObject & rnsReq = cdevRequestObject::attachRef("NameServer", "get"); // ***************************************************** // * Insert domain and name in the input request object // * to be sent to the CDEV Name Server. // ***************************************************** input.insert("name", server); input.insert("domain", domain); // ***************************************************** // * Query the Name Server to obtain the hostname and // * port of the specified domain and server. // ***************************************************** if(rnsReq.send(input, output)==CDEV_SUCCESS) { output.get("host", serverHost, 255); output.get("port", &serverPort); output.get("status", &serverStatus); } // ************************************************************* // * Restore the error threshold to a reasonable level. // ************************************************************* system_.setThreshold(CDEV_SEVERITY_ERROR); // ************************************************************* // * If the host and port have been specified, then use them // * rather than going through the CDEV Name Server. // ************************************************************* if(host!=NULL && *host && port>0) { if(strcmp(serverHost, host) && serverPort==port) hostMatchesNS = 1; strcpy(serverHost, host); serverPort = port; } else { if(*serverHost == 0 || serverPort<=0 || serverStatus!=0) { errCode = CDEV_ERROR; // ********************************************* // * If the hostname could not be found, report // * the error and set the return value to // * CDEV_ERROR. // ********************************************* outputError(CDEV_SEVERITY_ERROR, "CLIPService::connect", "Cannot find host for server \"%s\" in domain \"%s\"", server, domain); } else hostMatchesNS = 1; } // ************************************************************* // * If the hostname was discovered, then the errCode should be // * CDEV_SUCCESS. Attempt to connect to the server using the // * cdevReactor mechanisms. // ************************************************************* if(errCode==CDEV_SUCCESS) { cdevInetAddr addr; addr.set (serverPort, serverHost); handler = new ServerHandler(server, this); if(handler->open(addr)!=0) { outputError(CDEV_SEVERITY_ERROR, "CLIPService::connect", "Failed to connect to %s on port %i", serverHost, serverPort); delete handler; handler = NULL; } else { outputError(CDEV_SEVERITY_INFO, "CLIPService::connect", "Connected to %s on port %i", serverHost, serverPort); connections.insert(handler); // ********************************************* // * This calls the registerFd method of the // * service which will cause the FD Changed // * callbacks to be triggered. // ********************************************* registerFd(handler->getHandle(), 1); // ********************************************* // * Install a Name Server monitor to maintain // * the status of the connection. // * Note: If a monitor has already been // * installed using this informations, then the // * CDEV Name Server service should not create // * a second monitor. // * // * Note: I am using the FifoQueue associated // * with the specific server in order to // * differentiate between the various servers. // ********************************************* if(hostMatchesNS) { cdevData monData; cdevCallback monCb(nameServerCallback, (void *)getCallbackArg(server)); cdevRequestObject & monReq = cdevRequestObject::attachRef("NameServer", "monitorOn"); monData.insert("name", server); monData.insert("domain", domain); monReq.sendCallback(monData, monCb); } // ********************************************* // * Here is where a "set ClientInfo" message // * will be sent to the server to provide // * descriptive information about the client. // ********************************************* cdevData tagMap; int * tags; char ** ctags; int ntags; char * binary = NULL; size_t binaryLen = 0; cdevData::readTagTable(tags, ctags, ntags); tagMap.insert(1, tags, ntags); tagMap.insert(2, ctags, ntags); delete tags; delete ctags; handler->setTagChangeFlag(0); cdevMessageBinary packet(handler->getClientID(), 0, 0, 0, 0, CDEV_SERVER_OP, 0, 0, NULL, "set ClientInfo", &clientInfo.getClientData(), NULL, &tagMap); packet.streamOut(&binary, &binaryLen); packet.detachData(); ServerInterface::enqueue(handler, binary, binaryLen); } } } return handler; }