void ServerContextImpl::destroyAllTransports() { // not initialized yet if (!_transportRegistry.get()) { return; } std::auto_ptr<TransportRegistry::transportVector_t> transports = _transportRegistry->toArray(); if (transports.get() == 0) return; int size = (int)transports->size(); if (size == 0) return; LOG(logLevelInfo, "Server context still has %d transport(s) active and closing...", size); for (int i = 0; i < size; i++) { Transport::shared_pointer transport = (*transports)[i]; try { transport->close(); } catch (std::exception &e) { // do all exception safe, log in case of an error LOG(logLevelError, "Unhandled exception caught from client code at %s:%d: %s", __FILE__, __LINE__, e.what()); } catch (...) { // do all exception safe, log in case of an error LOG(logLevelError, "Unhandled exception caught from client code at %s:%d.", __FILE__, __LINE__); } } // now clear all (release) _transportRegistry->clear(); }
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; } }