/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvAccessCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #include #include #include #include #define epicsExportSharedSymbols #include #include #include #include using std::ostringstream; using namespace epics::pvData; namespace epics { namespace pvAccess { BlockingTCPAcceptor::BlockingTCPAcceptor( Context::shared_pointer const & context, ResponseHandler::shared_pointer const & responseHandler, int port, int receiveBufferSize) : _context(context), _responseHandler(responseHandler), _bindAddress(), _serverSocketChannel(INVALID_SOCKET), _receiveBufferSize(receiveBufferSize), _destroyed(false), _thread(*this, "TCP-acceptor", epicsThreadGetStackSize( epicsThreadStackMedium), epicsThreadPriorityMedium) { memset(&_bindAddress, 0, sizeof(_bindAddress)); _bindAddress.ia.sin_family = AF_INET; _bindAddress.ia.sin_port = htons(port); _bindAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY); initialize(); } BlockingTCPAcceptor::BlockingTCPAcceptor(Context::shared_pointer const & context, ResponseHandler::shared_pointer const & responseHandler, const osiSockAddr& addr, int receiveBufferSize) : _context(context), _responseHandler(responseHandler), _bindAddress(), _serverSocketChannel(INVALID_SOCKET), _receiveBufferSize(receiveBufferSize), _destroyed(false), _thread(*this, "TCP-acceptor", epicsThreadGetStackSize( epicsThreadStackMedium), epicsThreadPriorityMedium) { _bindAddress = addr; initialize(); } BlockingTCPAcceptor::~BlockingTCPAcceptor() { destroy(); } 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: "<close(); LOG( logLevelDebug, "Connection to PVA client %s failed to be validated, closing it.", ipAddrStr); continue; } LOG(logLevelDebug, "Serving to PVA client: %s.", ipAddrStr); }// accept succeeded else socketOpen = false; } // while } bool BlockingTCPAcceptor::validateConnection(Transport::shared_pointer const & transport, const char* address) { try { return transport->verify(5000); } catch(...) { LOG(logLevelDebug, "Validation of %s failed.", address); return false; } } void BlockingTCPAcceptor::destroy() { SOCKET sock; { Lock guard(_mutex); if(_destroyed) return; _destroyed = true; sock = _serverSocketChannel; _serverSocketChannel = INVALID_SOCKET; } if(sock!=INVALID_SOCKET) { char ipAddrStr[48]; ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr)); LOG(logLevelDebug, "Stopped accepting connections at %s.", ipAddrStr); switch(epicsSocketSystemCallInterruptMechanismQuery()) { case esscimqi_socketBothShutdownRequired: shutdown(sock, SHUT_RDWR); epicsSocketDestroy(sock); _thread.exitWait(); break; case esscimqi_socketSigAlarmRequired: LOG(logLevelError, "SigAlarm close not implemented for this target\n"); case esscimqi_socketCloseRequired: epicsSocketDestroy(sock); _thread.exitWait(); break; } } } } }