/** * Load configuration. */ void ServerContextImpl::loadConfiguration() { Configuration::shared_pointer config = getConfiguration(); // TODO for now just a simple switch int32 debugLevel = config->getPropertyAsInteger(PVACCESS_DEBUG, 0); if (debugLevel > 0) SET_LOG_LEVEL(logLevelDebug); // TODO multiple addresses _ifaceAddr.ia.sin_family = AF_INET; _ifaceAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY); _ifaceAddr.ia.sin_port = 0; config->getPropertyAsAddress("EPICS_PVAS_INTF_ADDR_LIST", &_ifaceAddr); _beaconAddressList = config->getPropertyAsString("EPICS_PVA_ADDR_LIST", _beaconAddressList); _beaconAddressList = config->getPropertyAsString("EPICS_PVAS_BEACON_ADDR_LIST", _beaconAddressList); _autoBeaconAddressList = config->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", _autoBeaconAddressList); _autoBeaconAddressList = config->getPropertyAsBoolean("EPICS_PVAS_AUTO_BEACON_ADDR_LIST", _autoBeaconAddressList); _beaconPeriod = config->getPropertyAsFloat("EPICS_PVA_BEACON_PERIOD", _beaconPeriod); _beaconPeriod = config->getPropertyAsFloat("EPICS_PVAS_BEACON_PERIOD", _beaconPeriod); _serverPort = config->getPropertyAsInteger("EPICS_PVA_SERVER_PORT", _serverPort); _serverPort = config->getPropertyAsInteger("EPICS_PVAS_SERVER_PORT", _serverPort); _ifaceAddr.ia.sin_port = htons(_serverPort); _broadcastPort = config->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", _broadcastPort); _broadcastPort = config->getPropertyAsInteger("EPICS_PVAS_BROADCAST_PORT", _broadcastPort); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVA_MAX_ARRAY_BYTES", _receiveBufferSize); _receiveBufferSize = config->getPropertyAsInteger("EPICS_PVAS_MAX_ARRAY_BYTES", _receiveBufferSize); _channelProviderNames = config->getPropertyAsString("EPICS_PVA_PROVIDER_NAMES", _channelProviderNames); _channelProviderNames = config->getPropertyAsString("EPICS_PVAS_PROVIDER_NAMES", _channelProviderNames); // // introspect network interfaces // SOCKET sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0); if (!sock) { THROW_BASE_EXCEPTION("Failed to create a socket needed to introspect network interfaces."); } if (discoverInterfaces(_ifaceList, sock, &_ifaceAddr)) { THROW_BASE_EXCEPTION("Failed to introspect network interfaces."); } else if (_ifaceList.size() == 0) { THROW_BASE_EXCEPTION("No (specified) network interface(s) available."); } epicsSocketDestroy(sock); }
void ServerContextImpl::run(int32 seconds) { if (seconds < 0) { THROW_BASE_EXCEPTION("seconds cannot be negative."); } { Lock guard(_mutex); if (_state == NOT_INITIALIZED) { THROW_BASE_EXCEPTION("Context not initialized."); } else if (_state == DESTROYED) { THROW_BASE_EXCEPTION("Context destroyed."); } else if (_state == RUNNING) { THROW_BASE_EXCEPTION("Context is already running."); } else if (_state == SHUTDOWN) { THROW_BASE_EXCEPTION("Context was shutdown."); } _state = RUNNING; } // run... _beaconEmitter->start(); //TODO review this if(seconds == 0) { _runEvent.wait(); } else { _runEvent.wait(seconds); } { Lock guard(_mutex); _state = SHUTDOWN; } }
void Properties::store() { #ifdef NO_STREAM_EXCEPTIONS _outfile->open(_fileName.c_str(),ifstream::trunc); if (_outfile->fail()) #else try { _outfile->open(_fileName.c_str(),ifstream::trunc); } catch (ofstream::failure& e) #endif { string errMsg = "Error opening file: " + string(_fileName.c_str()); THROW_BASE_EXCEPTION(errMsg.c_str()); } for (std::map<std::string,std::string>::iterator propertiesIterator = _properties.begin(); propertiesIterator != _properties.end(); propertiesIterator++ ) { #ifndef NO_STREAM_EXCEPTIONS try { #endif string line = string(propertiesIterator->first) + string("=") + string(propertiesIterator->second) + string("\n"); _outfile->write(line.c_str(),line.length()); #ifdef NO_STREAM_EXCEPTIONS if(_outfile->fail()) #else } catch (ofstream::failure& e) #endif { _outfile->close(); string errMsg = "Error writing to file: " + string(_fileName.c_str()); THROW_BASE_EXCEPTION(errMsg.c_str()); } } _outfile->close(); }
void ConfigurationProviderImpl::registerConfiguration(const string &name, Configuration::shared_pointer const & configuration) { Lock guard(_mutex); std::map<std::string,Configuration::shared_pointer>::iterator configsIter = _configs.find(name); if(configsIter != _configs.end()) { string msg = "configuration with name " + name + " already registered"; THROW_BASE_EXCEPTION(msg.c_str()); } _configs[name] = configuration; }
void ServerContextImpl::shutdown() { Lock guard(_mutex); if(_state == DESTROYED) { THROW_BASE_EXCEPTION("Context already destroyed."); } // notify to stop running... _runEvent.signal(); }
string Properties::getProperty(const string &key) { std::map<std::string,std::string>::iterator propertiesIterator = _properties.find(key); if(propertiesIterator != _properties.end()) //found in map { return string(propertiesIterator->second); } else { string errMsg = "Property not found in the map: " + key; THROW_BASE_EXCEPTION(errMsg.c_str()); } }
std::size_t SerializeHelper::readSize(ByteBuffer* buffer, DeserializableControl* control) { control->ensureData(1); int8 b = buffer->getByte(); if(b==-1) return -1; else if(b==-2) { control->ensureData(sizeof(int32)); int32 s = buffer->getInt(); if(s<0) THROW_BASE_EXCEPTION("negative size"); return s; } else return (std::size_t)(b<0 ? b+256 : b); }
void Properties::load() { _properties.clear(); #ifdef NO_STREAM_EXCEPTIONS _infile->open(_fileName.c_str(),ifstream::in); if (_infile->fail()) #else try { _infile->open(_fileName.c_str(),ifstream::in); } catch (ifstream::failure& e) #endif { string errMsg = "Error opening file: " + string(_fileName.c_str()); THROW_BASE_EXCEPTION(errMsg.c_str()); } string line; string property; string key; #ifndef NO_STREAM_EXCEPTIONS try { #endif while(!_infile->eof()) { line.erase(); std::getline(*_infile,line); #ifdef NO_STREAM_EXCEPTIONS if (_infile->fail()) { _infile->close(); if(_infile->eof()) { return; //end of file } string errMsg = "Error reading file: " + _fileName; THROW_BASE_EXCEPTION(errMsg.c_str()); } #endif //remove trailing spaces truncate(line); //empty line if(line.length() == 0) { continue; } // comment if(line[0] == '#') { continue; } //line is in format: propertyName=propertyValue size_t pos = line.find_first_of('=',0); if(pos == string::npos) //bad value (= not found) { string errMsg = "Bad property line found: " + line; THROW_BASE_EXCEPTION(errMsg.c_str()); } key = line.substr(0,pos); truncate(key); property = line.substr(pos + 1,line.length()); truncate(property); _properties[key] = property; } #ifndef NO_STREAM_EXCEPTIONS } catch (ifstream::failure& e) { _infile->close(); if(_infile->eof()) { return; //end of file } string errMsg = "Error reading file: " + _fileName; THROW_BASE_EXCEPTION(errMsg.c_str()); } #endif _infile->close(); }
int BlockingTCPAcceptor::initialize() { char ipAddrStr[48]; ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr)); int tryCount = 0; while(tryCount<2) { char strBuffer[64]; LOG(logLevelDebug, "Creating acceptor to %s.", ipAddrStr); _serverSocketChannel = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(_serverSocketChannel==INVALID_SOCKET) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); ostringstream temp; temp<<"Socket create error: "<<strBuffer; LOG(logLevelError, "%s", temp.str().c_str()); THROW_BASE_EXCEPTION(temp.str().c_str()); } else { //epicsSocketEnableAddressReuseDuringTimeWaitState(_serverSocketChannel); // try to bind int retval = ::bind(_serverSocketChannel, &_bindAddress.sa, sizeof(sockaddr)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Socket bind error: %s.", strBuffer); if(_bindAddress.ia.sin_port!=0) { // failed to bind to specified bind address, // try to get port dynamically, but only once LOG( logLevelDebug, "Configured TCP port %d is unavailable, trying to assign it dynamically.", ntohs(_bindAddress.ia.sin_port)); _bindAddress.ia.sin_port = htons(0); } else { epicsSocketDestroy(_serverSocketChannel); break; // exit while loop } } else { // if(retval<0) // bind succeeded // update bind address, if dynamically port selection was used if(ntohs(_bindAddress.ia.sin_port)==0) { osiSocklen_t sockLen = sizeof(sockaddr); // read the actual socket info retval = ::getsockname(_serverSocketChannel, &_bindAddress.sa, &sockLen); if(retval<0) { // error obtaining port number epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "getsockname error: %s", strBuffer); } else { LOG( logLevelInfo, "Using dynamically assigned TCP port %d.", ntohs(_bindAddress.ia.sin_port)); } } retval = ::listen(_serverSocketChannel, 4); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); ostringstream temp; temp<<"Socket listen error: "<<strBuffer; LOG(logLevelError, "%s", temp.str().c_str()); THROW_BASE_EXCEPTION(temp.str().c_str()); } _thread.start(); // all OK, return return ntohs(_bindAddress.ia.sin_port); } // successful bind } // successfully obtained socket tryCount++; } // while ostringstream temp; temp<<"Failed to create acceptor to "<<ipAddrStr; THROW_BASE_EXCEPTION(temp.str().c_str()); }
Transport::shared_pointer BlockingTCPConnector::connect(std::tr1::shared_ptr<ClientChannelImpl> const & client, ResponseHandler::shared_pointer const & responseHandler, osiSockAddr& address, int8 transportRevision, int16 priority) { SOCKET socket = INVALID_SOCKET; char ipAddrStr[64]; ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); Context::shared_pointer context = _context.lock(); TransportRegistry::Reservation rsvp(context->getTransportRegistry(), address, priority); // we are now blocking any connect() to this destination (address and prio) // concurrent connect() to other destination is allowed. // This prevents us from opening duplicate connections. Transport::shared_pointer transport = context->getTransportRegistry()->get(address, priority); if(transport.get()) { LOG(logLevelDebug, "Reusing existing connection to PVA server: %s.", ipAddrStr); if (transport->acquire(client)) return transport; } try { LOG(logLevelDebug, "Connecting to PVA server: %s.", ipAddrStr); socket = tryConnect(address, 3); LOG(logLevelDebug, "Socket connected to PVA server: %s.", ipAddrStr); // enable TCP_NODELAY (disable Nagle's algorithm) int optval = 1; // true int retval = ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int)); if(retval<0) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); LOG(logLevelWarn, "Error setting TCP_NODELAY: %s.", errStr); } // enable TCP_KEEPALIVE retval = ::setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int)); if(retval<0) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); LOG(logLevelWarn, "Error setting SO_KEEPALIVE: %s.", errStr); } // TODO tune buffer sizes?! Win32 defaults are 8k, which is OK // create transport // TODO introduce factory // get TCP send buffer size osiSocklen_t intLen = sizeof(int); int _socketSendBufferSize; retval = getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen); if(retval<0) { char strBuffer[64]; epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer); } // create() also adds to context connection pool _context->getTransportRegistry() transport = detail::BlockingClientTCPTransportCodec::create( context, socket, responseHandler, _receiveBufferSize, _socketSendBufferSize, client, transportRevision, _heartbeatInterval, priority); // verify if(!transport->verify(5000)) { LOG( logLevelDebug, "Connection to PVA server %s failed to be validated, closing it.", ipAddrStr); std::ostringstream temp; temp<<"Failed to verify TCP connection to '"<<ipAddrStr<<"'."; THROW_BASE_EXCEPTION(temp.str().c_str()); } LOG(logLevelDebug, "Connected to PVA server: %s.", ipAddrStr); return transport; } catch(std::exception&) { if(transport.get()) transport->close(); else if(socket!=INVALID_SOCKET) epicsSocketDestroy(socket); throw; } }
void ServerContextImpl::initialize(ChannelProviderRegistry::shared_pointer const & channelProviderRegistry) { Lock guard(_mutex); if (!channelProviderRegistry.get()) { THROW_BASE_EXCEPTION("channelProviderRegistry == NULL"); } if (_state == DESTROYED) { THROW_BASE_EXCEPTION("Context destroyed."); } else if (_state != NOT_INITIALIZED) { THROW_BASE_EXCEPTION("Context already initialized."); } _channelProviderRegistry = channelProviderRegistry; // user all providers if (_channelProviderNames == PVACCESS_ALL_PROVIDERS) { _channelProviderNames.resize(0); // VxWorks 5.5 omits clear() std::auto_ptr<ChannelProviderRegistry::stringVector_t> names = _channelProviderRegistry->getProviderNames(); for (ChannelProviderRegistry::stringVector_t::iterator iter = names->begin(); iter != names->end(); iter++) { ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(*iter); if (channelProvider) { _channelProviders.push_back(channelProvider); // compile a list if (!_channelProviderNames.empty()) _channelProviderNames += ' '; _channelProviderNames += *iter; } } } else { // split space separated names std::stringstream ss(_channelProviderNames); std::string providerName; while (std::getline(ss, providerName, ' ')) { ChannelProvider::shared_pointer channelProvider = _channelProviderRegistry->getProvider(providerName); if (channelProvider) _channelProviders.push_back(channelProvider); } } //_channelProvider = _channelProviderRegistry->getProvider(_channelProviderNames); if (_channelProviders.size() == 0) { std::string msg = "None of the specified channel providers are available: " + _channelProviderNames + "."; THROW_BASE_EXCEPTION(msg.c_str()); } internalInitialize(); _state = INITIALIZED; }