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); }
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; }
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(); }
char* transportAddressToString_ipv6 (char *buf, const size_t len, const CckTransportAddress *address) { return inetAddressToString(buf, len, address); }