void BlockingUDPTransport::setMutlicastNIF(const osiSockAddr & nifAddr, bool loopback)
        {
            // set the multicast outgoing interface
            int status = ::setsockopt(_channel, IPPROTO_IP, IP_MULTICAST_IF,
                                  (char*)&nifAddr.ia.sin_addr, sizeof(struct in_addr));
            if (status)
            {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                throw std::runtime_error(
                            string("Failed to set multicast network inteface '") +
                            inetAddressToString(nifAddr, false) + "': " + errStr);
            }

            // send multicast traffic to myself too
            unsigned char mcast_loop = (loopback ? 1 : 0);
            status = ::setsockopt(_channel, IPPROTO_IP, IP_MULTICAST_LOOP,
                                (char*)&mcast_loop, sizeof(unsigned char));
            if (status)
            {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                throw std::runtime_error(
                            string("Failed to enable multicast loopback on network inteface '") +
                            inetAddressToString(nifAddr, false) + "': " + errStr);
            }

        }
        void BlockingUDPTransport::close(bool waitForThreadToComplete) {
            {
                Lock guard(_mutex);
                if(_closed.get()) return;
                _closed.set();
            }

            if (IS_LOGGABLE(logLevelDebug))
            {
                LOG(logLevelDebug,
                    "UDP socket %s closed.",
                    inetAddressToString(_bindAddress).c_str());
            }
            
            epicsSocketSystemCallInterruptMechanismQueryInfo info  =
                epicsSocketSystemCallInterruptMechanismQuery ();
            switch ( info )
            {
                case esscimqi_socketCloseRequired:
                    epicsSocketDestroy ( _channel );
                    break;
                case esscimqi_socketBothShutdownRequired:
                    {
                        /*int status =*/ ::shutdown ( _channel, SHUT_RDWR );
                        /*
                        if ( status ) {
                            char sockErrBuf[64];
                            epicsSocketConvertErrnoToString (
                                sockErrBuf, sizeof ( sockErrBuf ) );
                        LOG(logLevelDebug,
                            "UDP socket %s failed to shutdown: %s.",
                            inetAddressToString(_bindAddress).c_str(), sockErrBuf);
                        }
                        */
                        epicsSocketDestroy ( _channel );
                    }
                    break;
                case esscimqi_socketSigAlarmRequired:
                    // not supported anymore anyway
                default:
                    epicsSocketDestroy(_channel);
            }
            
            
            // wait for send thread to exit cleanly            
            if (waitForThreadToComplete)
            {
                if (!_shutdownEvent.wait(5.0))
                {
                    LOG(logLevelError,
                        "Receive thread for UDP socket %s has not exited.",
                        inetAddressToString(_bindAddress).c_str());
                }
            }
        }
    Transport::shared_pointer BlockingUDPConnector::connect(TransportClient::shared_pointer const & /*client*/,
                auto_ptr<ResponseHandler>& responseHandler, osiSockAddr& bindAddress,
                int8 transportRevision, int16 /*priority*/) {
                    
            LOG(logLevelDebug, "Creating datagram socket to: %s.",
                    inetAddressToString(bindAddress).c_str());

            SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(socket==INVALID_SOCKET) {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                LOG(logLevelError, "Error creating socket: %s.", errStr);
                return Transport::shared_pointer();
            }

            int optval = _broadcast ? 1 : 0;
            int retval = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval));
            if(retval<0)
            {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                LOG(logLevelError, "Error setting SO_BROADCAST: %s.", errStr);
                epicsSocketDestroy (socket);
                return Transport::shared_pointer();
            }
            
            /*
            IPv4 multicast addresses are defined by the leading address bits of 1110,
            originating from the classful network design of the early Internet when this
            group of addresses was designated as Class D. The Classless Inter-Domain Routing (CIDR)
            prefix of this group is 224.0.0.0/4.
            The group includes the addresses from 224.0.0.0 to 239.255.255.255.
            Address assignments from within this range are specified in RFC 5771,
            an Internet Engineering Task Force (IETF) Best Current Practice document (BCP 51).*/
            
            
            // set SO_REUSEADDR or SO_REUSEPORT, OS dependant
            if (_reuseSocket)
                epicsSocketEnableAddressUseForDatagramFanout(socket);

            retval = ::bind(socket, (sockaddr*)&(bindAddress.sa), sizeof(sockaddr));
            if(retval<0) {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                LOG(logLevelError, "Error binding socket: %s.", errStr);
                epicsSocketDestroy (socket);
                return Transport::shared_pointer();
            }

            // sockets are blocking by default
            Transport::shared_pointer transport = BlockingUDPTransport::create(_serverFlag,
                                                                               responseHandler, socket, bindAddress, transportRevision);
            return transport;
        }
        void BlockingUDPTransport::join(const osiSockAddr & mcastAddr, const osiSockAddr & nifAddr)
        {
            struct ip_mreq imreq;
            memset(&imreq, 0, sizeof(struct ip_mreq));

            imreq.imr_multiaddr.s_addr = mcastAddr.ia.sin_addr.s_addr;
            imreq.imr_interface.s_addr = nifAddr.ia.sin_addr.s_addr;

            // join multicast group on default interface
            int status = ::setsockopt(_channel, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                            (char*)&imreq, sizeof(struct ip_mreq));
            if (status)
            {
                char errStr[64];
                epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                throw std::runtime_error(
                            string("Failed to join to the multicast group '") +
                            inetAddressToString(mcastAddr) + "' on network interface '" +
                            inetAddressToString(nifAddr, false) + "': " + errStr);
            }
        }
        void BlockingUDPTransport::start() {

            string threadName = "UDP-receive " + inetAddressToString(_bindAddress);
            
            if (IS_LOGGABLE(logLevelTrace))
            {
                LOG(logLevelTrace, "Starting thread: %s.", threadName.c_str());
            }
            
            _threadId = epicsThreadCreate(threadName.c_str(),
                    epicsThreadPriorityMedium,
                    epicsThreadGetStackSize(epicsThreadStackSmall),
                    BlockingUDPTransport::threadRunner, this);
        }
示例#6
0
void ServerContextImpl::printInfo(ostream& str)
{
    Lock guard(_mutex);
    str << "VERSION : " << getVersion().getVersionString() << endl \
        << "PROVIDER_NAMES : " << _channelProviderNames << endl \
        << "BEACON_ADDR_LIST : " << _beaconAddressList << endl \
        << "AUTO_BEACON_ADDR_LIST : " << _autoBeaconAddressList << endl \
        << "BEACON_PERIOD : " << _beaconPeriod << endl \
        << "BROADCAST_PORT : " << _broadcastPort << endl \
        << "SERVER_PORT : " << _serverPort << endl \
        << "RCV_BUFFER_SIZE : " << _receiveBufferSize << endl \
        << "IGNORE_ADDR_LIST: " << _ignoreAddressList << endl \
        << "INTF_ADDR_LIST : " << inetAddressToString(_ifaceAddr, false) << endl \
        << "STATE : " << ServerContextImpl::StateNames[_state] << endl;
}
示例#7
0
bool JausOpcUdpInterface::openSocket(void)
{
	double socketTimeoutSec = 0;
	unsigned char socketTTL = 0;
	std::string multicastGroupString;

	switch(this->type)
	{
		case SUBSYSTEM_INTERFACE:
			// Read Subsystem UDP Parameters
			// Port is constant per JAUS Standard
			this->portNumber = JAUS_OPC_UDP_DATA_PORT;

			// IP Address
			if(this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_IP_Address") == "")
			{
				// Cannot open specified IP Address
				ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, "No IP Address specified!");
				this->eventHandler->handleEvent(e);
				return false;
			}
			else
			{
				this->ipAddress = inetAddressGetByString((char *)this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_IP_Address").c_str());
				if(this->ipAddress == NULL)
				{
					// Cannot open specified IP Address
					char errorString[128] = {0};
					sprintf(errorString, "Could not open specified IP Address: %s", this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_IP_Address").c_str());

					ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
					this->eventHandler->handleEvent(e);
					return false;
				}
			}

			// Timeout
			if(this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_Timeout_Sec") == "")
			{
				socketTimeoutSec = OPC_UDP_DEFAULT_SUBSYSTEM_UDP_TIMEOUT_SEC;
			}
			else
			{
				socketTimeoutSec = this->configData->GetConfigDataDouble("Subsystem_Communications", "JAUS_OPC_UDP_Timeout_Sec");
			}

			// TTL
			if(this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_TTL") == "")
			{
				socketTTL = OPC_UDP_DEFAULT_SUBSYSTEM_TTL;
			}
			else
			{
				socketTTL = this->configData->GetConfigDataInt("Subsystem_Communications", "JAUS_OPC_UDP_TTL");
			}

			// Multicast
			if(this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_Multicast") == "")
			{
				this->multicast = OPC_UDP_DEFAULT_SUBSYSTEM_MULTICAST;
			}
			else
			{
				this->multicast = this->configData->GetConfigDataBool("Subsystem_Communications", "JAUS_OPC_UDP_Multicast");
			}

			if(this->multicast)
			{
				// Multicast Group
				if(this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_Multicast_Group") == "")
				{
					multicastGroupString = OPC_UDP_DEFAULT_SUBSYSTEM_MULTICAST_GROUP;
				}
				else
				{
					multicastGroupString = this->configData->GetConfigDataString("Subsystem_Communications", "JAUS_OPC_UDP_Multicast_Group");
				}
			}
			break;

		case NODE_INTERFACE:
			// Setup Node Configuration
			// Port is constant per JAUS Standard
			this->portNumber = JAUS_OPC_UDP_DATA_PORT;

			// IP Address
			if(this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_IP_Address") == "")
			{
				// Cannot open specified IP Address
				ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, "No IP Address specified!");
				this->eventHandler->handleEvent(e);
				return false;
			}
			else
			{
				this->ipAddress = inetAddressGetByString((char *)this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_IP_Address").c_str());
				if(this->ipAddress == NULL)
				{
					// Cannot open specified IP Address
					char errorString[128] = {0};
					sprintf(errorString, "Could not open specified IP Address: %s", this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_IP_Address").c_str());

					ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
					this->eventHandler->handleEvent(e);
					return false;
				}
			}

			// Timeout
			if(this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_Timeout_Sec") == "")
			{
				socketTimeoutSec = OPC_UDP_DEFAULT_NODE_UDP_TIMEOUT_SEC;
			}
			else
			{
				socketTimeoutSec = this->configData->GetConfigDataDouble("Node_Communications", "JAUS_OPC_UDP_Timeout_Sec");
			}

			// TTL
			if(this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_TTL") == "")
			{
				socketTTL = OPC_UDP_DEFAULT_NODE_TTL;
			}
			else
			{
				socketTTL = this->configData->GetConfigDataInt("Node_Communications", "JAUS_OPC_UDP_TTL");
			}

			// Multicast
			if(this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_Multicast") == "")
			{
				this->multicast = OPC_UDP_DEFAULT_NODE_MULTICAST;
			}
			else
			{
				this->multicast = this->configData->GetConfigDataBool("Node_Communications", "JAUS_OPC_UDP_Multicast");
			}

			if(this->multicast)
			{
				// Multicast Group
				if(this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_Multicast_Group") == "")
				{
					multicastGroupString = OPC_UDP_DEFAULT_NODE_MULTICAST_GROUP;
				}
				else
				{
					multicastGroupString = this->configData->GetConfigDataString("Node_Communications", "JAUS_OPC_UDP_Multicast_Group");
				}
			}
			break;

		case COMPONENT_INTERFACE:
			// Read Component Configuration
			// Port Number
			if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_Port") == "")
			{
				this->portNumber = OPC_UDP_DEFAULT_COMPONENT_UDP_PORT;
			}
			else
			{
				this->portNumber = this->configData->GetConfigDataInt("Component_Communications", "JAUS_OPC_UDP_Port");
			}

			// IP Address
			if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_IP_Address") == "")
			{
				this->ipAddress = inetAddressGetByString((char *)OPC_UDP_DEFAULT_COMPONENT_IP.c_str());
				if(this->ipAddress == NULL)
				{
					// Cannot open specified IP Address
					char errorString[128] = {0};
					sprintf(errorString, "Could not open default IP Address: %s", OPC_UDP_DEFAULT_COMPONENT_IP.c_str());

					ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
					this->eventHandler->handleEvent(e);
					return false;
				}
			}
			else
			{
				this->ipAddress = inetAddressGetByString((char *)this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_IP_Address").c_str());
				if(this->ipAddress == NULL)
				{
					// Cannot open specified IP Address
					char errorString[128] = {0};
					sprintf(errorString, "Could not open specified IP Address: %s", this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_IP_Address").c_str());

					ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
					this->eventHandler->handleEvent(e);
					return false;
				}
			}

			// Timeout
			if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_Timeout_Sec") == "")
			{
				socketTimeoutSec = OPC_UDP_DEFAULT_COMPONENT_UDP_TIMEOUT_SEC;
			}
			else
			{
				socketTimeoutSec = this->configData->GetConfigDataDouble("Component_Communications", "JAUS_OPC_UDP_Timeout_Sec");
			}

			// TTL
			if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_TTL") == "")
			{
				socketTTL = OPC_UDP_DEFAULT_COMPONENT_TTL;
			}
			else
			{
				socketTTL = this->configData->GetConfigDataInt("Component_Communications", "JAUS_OPC_UDP_TTL");
			}

			// Multicast
			if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_Multicast") == "")
			{
				this->multicast = OPC_UDP_DEFAULT_COMPONENT_MULTICAST;
			}
			else
			{
				this->multicast = this->configData->GetConfigDataBool("Component_Communications", "JAUS_OPC_UDP_Multicast");
			}

			if(this->multicast)
			{
				// Multicast Group
				if(this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_Multicast_Group") == "")
				{
					// Error. Component has no default Multicast group.
					ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, "No default Component Multicast Group and none defined.");
					this->eventHandler->handleEvent(e);

					inetAddressDestroy(this->ipAddress);
					return false;
				}
				else
				{
					multicastGroupString = this->configData->GetConfigDataString("Component_Communications", "JAUS_OPC_UDP_Multicast_Group");
				}
			}
			break;

		default:
			// Unknown type
			ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, "Unknown JudpInterface type. Cannot open socket.");
			this->eventHandler->handleEvent(e);
			return false;
	}

	// Create Socket
	this->socket = multicastSocketCreate(this->portNumber, ipAddress);
	if(!this->socket)
	{
		// Error creating our socket
		char errorString[128] = {0};
		char buf[24] = {0};

		inetAddressToBuffer(this->ipAddress, buf, 24);
		sprintf(errorString, "Could not open socket: %s:%d", buf, this->portNumber);
		ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
		this->eventHandler->handleEvent(e);

		inetAddressDestroy(this->ipAddress);
		return false;
	}
	else
	{
		this->ipAddress->value = socket->address->value;
		this->portNumber = socket->port;
	}
	inetAddressDestroy(this->ipAddress);

	// Setup Timeout
	multicastSocketSetTimeout(this->socket, socketTimeoutSec);

	// Setup TTL
	multicastSocketSetTTL(this->socket, socketTTL);

	// Setup Multicast
	if(this->multicast)
	{
		this->multicastGroup  = inetAddressGetByString((char *)multicastGroupString.c_str());
		if(multicastSocketJoinGroup(this->socket, this->multicastGroup) != 0)
		{
			// Error joining our group
			char errorString[128] = {0};
			char buf[24] = {0};

			inetAddressToString(this->multicastGroup, buf);
			sprintf(errorString, "Could not open socket: %s:%d", buf, this->portNumber);
			ErrorEvent *e = new ErrorEvent(ErrorEvent::Configuration, __FUNCTION__, __LINE__, errorString);
			this->eventHandler->handleEvent(e);
			return false;
		}

		// Setup Loopback
		multicastSocketSetLoopback(this->socket, LOOPBACK_DISABLED);

		// Setup Multicast UdpData
		multicastData.addressValue = multicastGroup->value;
		multicastData.port = this->socket->port;

		inetAddressDestroy(this->multicastGroup);
	}

	return true;
}
        void BlockingUDPTransport::processRead() {
            // This function is always called from only one thread - this
            // object's own thread.

            osiSockAddr fromAddress;
            osiSocklen_t addrStructSize = sizeof(sockaddr);
            Transport::shared_pointer thisTransport = shared_from_this();

            try {

                while(!_closed.get())
                {
                    // we poll to prevent blocking indefinitely

                    // data ready to be read
                    _receiveBuffer->clear();

                    int bytesRead = recvfrom(_channel, (char*)_receiveBuffer->getArray(),
                            _receiveBuffer->getRemaining(), 0, (sockaddr*)&fromAddress,
                            &addrStructSize);

                    if(likely(bytesRead>0)) {
                        // successfully got datagram
                        bool ignore = false;
                        if(likely(_ignoredAddresses!=0))
                        {
                            for(size_t i = 0; i <_ignoredAddresses->size(); i++)
                            {
                                if((*_ignoredAddresses)[i].ia.sin_addr.s_addr==fromAddress.ia.sin_addr.s_addr)
                                {
                                    ignore = true;
                                    break;
                                }
                            }
                        }
                        
                        if(likely(!ignore)) {
                            _receiveBuffer->setPosition(bytesRead);

                            _receiveBuffer->flip();

                            processBuffer(thisTransport, fromAddress, _receiveBuffer.get());
                        }
                    }
                    else if (unlikely(bytesRead == -1)) {
                        
                        int socketError = SOCKERRNO;
                        
                        // interrupted or timeout
                        if (socketError == SOCK_EINTR || 
                            socketError == EAGAIN ||        // no alias in libCom
                            // windows times out with this
                            socketError == SOCK_ETIMEDOUT || 
                            socketError == SOCK_EWOULDBLOCK)
                            continue;
                            
                        if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux
                            socketError == SOCK_ECONNRESET)     // or ECONNRESET in Windows
                            continue;
                                                    
                        // log a 'recvfrom' error
                        if(!_closed.get())
                        {
                            char errStr[64];
                            epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
                            LOG(logLevelError, "Socket recvfrom error: %s.", errStr);
                        }
                               
                        close(false);
                        break;
                    }

                }
            } catch(...) {
                // TODO: catch all exceptions, and act accordingly
                close(false);
            }

            if (IS_LOGGABLE(logLevelTrace))
            {
                string threadName = "UDP-receive "+inetAddressToString(_bindAddress);
                LOG(logLevelTrace, "Thread '%s' exiting.", threadName.c_str());
            }
            
            _shutdownEvent.signal();
        }
示例#9
0
char*
transportAddressToString_ipv6 (char *buf, const size_t len, const CckTransportAddress *address)
{
    return inetAddressToString(buf, len, address);
}