void InterfaceTester::createCommands () { std::srand( clock() ); // первая команда - push int count = std::rand() % commandRange; Commands.push_back( std::make_pair( testInterface( 1 ), std::make_pair( 0, count ) ) ); int elementsNumber = 1; // создаем остальные команды for( int i = 1; i < commandNumber; ++i ) { testInterface command = testInterface( rand() % 4 ); int index1 = rand() % elementsNumber; // первый элемент - индекс // второй - элемент, если push или assign, индекс - если sum или nextPerm if( command == 1 || command == 2 ) { count = std::rand() % commandRange; } else { count = std::rand() % elementsNumber; // индексы - первый не больше второго if( command == 3 ) { if( count == elementsNumber - 1 ) count = 0; if( index1 == elementsNumber - 1) index1 = 0; } if( count < index1 ) std::swap( index1, count ); } Commands.push_back( std::make_pair( command, std::make_pair( index1, count ) ) ); // если команда - push - кол-во элементов + 1 if ( command == 1 ) ++elementsNumber; } std::cout << "Tests are ready" << std::endl; }
bool Event::checkScript(const std::string& datadir, const std::string& scriptsName, const std::string& scriptFile) { LuaScriptInterface testInterface("Test Interface"); testInterface.initState(); if(testInterface.loadFile(std::string(datadir + scriptsName + "/lib/" + scriptsName + ".lua")) == -1){ std::cout << "Warning: [Event::checkScript] Can not load " << scriptsName << " lib/" << scriptsName << ".lua" << std::endl; } if(m_scriptId != 0){ std::cout << "Failure: [Event::checkScript] scriptid = " << m_scriptId << std::endl; return false; } if(testInterface.loadFile(datadir + scriptsName + scriptFile) == -1){ std::cout << "Warning: [Event::checkScript] Can not load script. " << scriptFile << std::endl; std::cout << testInterface.getLastLuaError() << std::endl; return false; } int32_t id = testInterface.getEvent(getScriptEventName()); if(id == -1){ std::cout << "Warning: [Event::checkScript] Event " << getScriptEventName() << " not found. " << scriptFile << std::endl; return false; } return true; }
/** * Init all network transports * * @param netPath * @param rtOpts * @param ptpClock * * @return TRUE if successful */ Boolean netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock) { int temp; struct sockaddr_in addr; #ifdef PTPD_PCAP struct bpf_program program; char errbuf[PCAP_ERRBUF_SIZE]; #endif DBG("netInit\n"); #ifdef PTPD_PCAP netPath->pcapEvent = NULL; netPath->pcapGeneral = NULL; netPath->pcapEventSock = -1; netPath->pcapGeneralSock = -1; #endif netPath->generalSock = -1; netPath->eventSock = -1; #ifdef PTPD_PCAP if (rtOpts->transport == IEEE_802_3) { netPath->headerOffset = PACKET_BEGIN_ETHER; #ifdef HAVE_STRUCT_ETHER_ADDR_OCTET memcpy(netPath->etherDest.octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN); memcpy(netPath->peerEtherDest.octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN); #else memcpy(netPath->etherDest.ether_addr_octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN); memcpy(netPath->peerEtherDest.ether_addr_octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN); #endif /* HAVE_STRUCT_ETHER_ADDR_OCTET */ } else #endif netPath->headerOffset = PACKET_BEGIN_UDP; /* open sockets */ if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { PERROR("failed to initialize sockets"); return FALSE; } if(!testInterface(rtOpts->ifaceName, rtOpts)) return FALSE; netPath->interfaceInfo.addressFamily = AF_INET; /* the if is here only to get rid of an unused result warning. */ if( getInterfaceInfo(rtOpts->ifaceName, &netPath->interfaceInfo)!= 1) return FALSE; /* No HW address, we'll use the protocol address to form interfaceID -> clockID */ if( !netPath->interfaceInfo.hasHwAddress && netPath->interfaceInfo.hasAfAddress ) { uint32_t addr = netPath->interfaceInfo.afAddress.s_addr; memcpy(netPath->interfaceID, &addr, 2); memcpy(netPath->interfaceID + 4, &addr + 2, 2); /* Initialise interfaceID with hardware address */ } else { memcpy(&netPath->interfaceID, &netPath->interfaceInfo.hwAddress, sizeof(netPath->interfaceID) <= sizeof(netPath->interfaceInfo.hwAddress) ? sizeof(netPath->interfaceID) : sizeof(netPath->interfaceInfo.hwAddress) ); } DBG("Listening on IP: %s\n",inet_ntoa(netPath->interfaceInfo.afAddress)); #ifdef PTPD_PCAP if (rtOpts->pcap == TRUE) { int promisc = (rtOpts->transport == IEEE_802_3 ) ? 1 : 0; if ((netPath->pcapEvent = pcap_open_live(rtOpts->ifaceName, PACKET_SIZE, promisc, PCAP_TIMEOUT, errbuf)) == NULL) { PERROR("failed to open event pcap"); return FALSE; } if (pcap_compile(netPath->pcapEvent, &program, ( rtOpts->transport == IEEE_802_3 ) ? "ether proto 0x88f7": ( rtOpts->ip_mode != IPMODE_MULTICAST ) ? "udp port 319" : "host (224.0.1.129 or 224.0.0.107) and udp port 319" , 1, 0) < 0) { PERROR("failed to compile pcap event filter"); pcap_perror(netPath->pcapEvent, "ptpd2"); return FALSE; } if (pcap_setfilter(netPath->pcapEvent, &program) < 0) { PERROR("failed to set pcap event filter"); return FALSE; } pcap_freecode(&program); if ((netPath->pcapEventSock = pcap_get_selectable_fd(netPath->pcapEvent)) < 0) { PERROR("failed to get pcap event fd"); return FALSE; } if ((netPath->pcapGeneral = pcap_open_live(rtOpts->ifaceName, PACKET_SIZE, promisc, PCAP_TIMEOUT, errbuf)) == NULL) { PERROR("failed to open general pcap"); return FALSE; } if (rtOpts->transport != IEEE_802_3) { if (pcap_compile(netPath->pcapGeneral, &program, ( rtOpts->ip_mode != IPMODE_MULTICAST ) ? "udp port 320" : "host (224.0.1.129 or 224.0.0.107) and udp port 320" , 1, 0) < 0) { PERROR("failed to compile pcap general filter"); pcap_perror(netPath->pcapGeneral, "ptpd2"); return FALSE; } if (pcap_setfilter(netPath->pcapGeneral, &program) < 0) { PERROR("failed to set pcap general filter"); return FALSE; } pcap_freecode(&program); if ((netPath->pcapGeneralSock = pcap_get_selectable_fd(netPath->pcapGeneral)) < 0) { PERROR("failed to get pcap general fd"); return FALSE; } } } #endif #ifdef PTPD_PCAP if(rtOpts->transport == IEEE_802_3) { close(netPath->eventSock); netPath->eventSock = -1; close(netPath->generalSock); netPath->generalSock = -1; /* TX timestamp is not generated for PCAP mode and Ethernet transport */ #ifdef SO_TIMESTAMPING netPath->txTimestampFailure = TRUE; #endif /* SO_TIMESTAMPING */ } else { #endif /* save interface address for IGMP refresh */ netPath->interfaceAddr = netPath->interfaceInfo.afAddress; DBG("Local IP address used : %s \n", inet_ntoa(netPath->interfaceInfo.afAddress)); temp = 1; /* allow address reuse */ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) { DBG("failed to set socket reuse\n"); } /* bind sockets */ /* * need INADDR_ANY to allow receipt of multi-cast and uni-cast * messages */ /* why??? */ if (rtOpts->pidAsClockId) { if (inet_pton(AF_INET, DEFAULT_PTP_DOMAIN_ADDRESS, &addr.sin_addr) < 0) { PERROR("failed to convert address"); return FALSE; } } else addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; addr.sin_port = htons(PTP_EVENT_PORT); if (bind(netPath->eventSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind event socket"); return FALSE; } addr.sin_port = htons(PTP_GENERAL_PORT); if (bind(netPath->generalSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind general socket"); return FALSE; } #ifdef USE_BINDTODEVICE #ifdef linux /* * The following code makes sure that the data is only * received on the specified interface. Without this option, * it's possible to receive PTP from another interface, and * confuse the protocol. Calling bind() with the IP address * of the device instead of INADDR_ANY does not work. * * More info: * http://developerweb.net/viewtopic.php?id=6471 * http://stackoverflow.com/questions/1207746/problems-with-so-bindtodevice-linux-socket-option */ if ( rtOpts->ip_mode != IPMODE_HYBRID ) if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINDTODEVICE, rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINDTODEVICE, rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0){ PERROR("failed to call SO_BINDTODEVICE on the interface"); return FALSE; } #endif #endif /* Set socket dscp */ if(rtOpts->dscpValue) { if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_TOS, &rtOpts->dscpValue, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_TOS, &rtOpts->dscpValue, sizeof(int)) < 0) { PERROR("Failed to set socket DSCP bits"); return FALSE; } } /* send a uni-cast address if specified (useful for testing) */ if(!hostLookup(rtOpts->unicastAddress, &netPath->unicastAddr)) { netPath->unicastAddr = 0; } if(rtOpts->ip_mode != IPMODE_UNICAST) { /* init UDP Multicast on both Default and Peer addresses */ if (!netInitMulticast(netPath, rtOpts)) return FALSE; /* set socket time-to-live */ if(!netSetMulticastTTL(netPath->eventSock,rtOpts->ttl) || !netSetMulticastTTL(netPath->generalSock,rtOpts->ttl)) return FALSE; /* start tracking TTL */ netPath->ttlEvent = rtOpts->ttl; netPath->ttlGeneral = rtOpts->ttl; } #ifdef SO_TIMESTAMPING /* Reset the failure indicator when (re)starting network */ netPath->txTimestampFailure = FALSE; /* for SO_TIMESTAMPING we're receiving transmitted packets via ERRQUEUE */ temp = 0; #else /* enable loopback */ temp = 1; #endif /* make timestamps available through recvmsg() */ if (!netInitTimestamping(netPath,rtOpts)) { ERROR("Failed to enable packet time stamping\n"); return FALSE; } #ifdef SO_TIMESTAMPING /* If we failed to initialise SO_TIMESTAMPING, enable mcast loopback */ if(netPath->txTimestampFailure) temp = 1; #endif if(!netSetMulticastLoopback(netPath, temp)) { return FALSE; } #ifdef PTPD_PCAP } #endif /* Compile ACLs */ if(rtOpts->timingAclEnabled) { freeIpv4AccessList(&netPath->timingAcl); netPath->timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText, rtOpts->timingAclDenyText, rtOpts->timingAclOrder); } if(rtOpts->managementAclEnabled) { freeIpv4AccessList(&netPath->managementAcl); netPath->managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText, rtOpts->managementAclDenyText, rtOpts->managementAclOrder); } return TRUE; }
PtpClock * ptpdStartup(int argc, char **argv, Integer16 * ret, RunTimeOpts * rtOpts) { PtpClock * ptpClock; int i = 0; /* * Set the default mode for all newly created files - previously * this was not the case for log files. This adds consistency * and allows to use FILE* vs. fds everywhere */ umask(~DEFAULT_FILE_PERMS); /** * If a required setting, such as interface name, or a setting * requiring a range check is to be set via getopts_long, * the respective currentConfig dictionary entry should be set, * instead of just setting the rtOpts field. * * Config parameter evaluation priority order: * 1. Any dictionary keys set in the getopt_long loop * 2. CLI long section:key type options * 3. Config file (parsed last), merged with 2. and 3 - will be overwritten by CLI options * 4. Defaults and any rtOpts fields set in the getopt_long loop **/ /** * Load defaults. Any options set here and further inside loadCommandLineOptions() * by setting rtOpts fields, will be considered the defaults * for config file and section:key long options. */ loadDefaultSettings(rtOpts); /* initialise the config dictionary */ rtOpts->candidateConfig = dictionary_new(0); rtOpts->cliConfig = dictionary_new(0); /* parse all long section:key options and clean up argv for getopt */ loadCommandLineKeys(rtOpts->cliConfig,argc,argv); /* parse the normal short and long option, exit on error */ if (!loadCommandLineOptions(rtOpts, rtOpts->cliConfig, argc, argv, ret)) { goto fail; } /* Display startup info and argv if not called with -? or -H */ NOTIFY("%s version %s starting\n",USER_DESCRIPTION, USER_VERSION); dump_command_line_parameters(argc, argv); /* * we try to catch as many error conditions as possible, but before we call daemon(). * the exception is the lock file, as we get a new pid when we call daemon(), * so this is checked twice: once to read, second to read/write */ if(geteuid() != 0) { printf("Error: "PTPD_PROGNAME" daemon can only be run as root\n"); *ret = 1; goto fail; } /* Have we got a config file? */ if(strlen(rtOpts->configFile) > 0) { /* config file settings overwrite all others, except for empty strings */ INFO("Loading configuration file: %s\n",rtOpts->configFile); if(loadConfigFile(&rtOpts->candidateConfig, rtOpts)) { dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, "from command line"); } else { *ret = 1; dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, "from command line"); goto configcheck; } } else { dictionary_merge(rtOpts->cliConfig, rtOpts->candidateConfig, 1, "from command line"); } /** * This is where the final checking of the candidate settings container happens. * A dictionary is returned with only the known options, explicitly set to defaults * if not present. NULL is returned on any config error - parameters missing, out of range, * etc. The getopt loop in loadCommandLineOptions() only sets keys verified here. */ if( ( rtOpts->currentConfig = parseConfig(rtOpts->candidateConfig,rtOpts)) == NULL ) { *ret = 1; dictionary_del(rtOpts->candidateConfig); goto configcheck; } /* we've been told to print the lock file and exit cleanly */ if(rtOpts->printLockFile) { printf("%s\n", rtOpts->lockFile); *ret = 0; goto fail; } /* we don't need the candidate config any more */ dictionary_del(rtOpts->candidateConfig); /* Check network before going into background */ if(!testInterface(rtOpts->ifaceName, rtOpts)) { ERROR("Error: Cannot use %s interface\n",rtOpts->ifaceName); *ret = 1; goto configcheck; } configcheck: /* * We've been told to check config only - clean exit before checking locks */ if(rtOpts->checkConfigOnly) { if(*ret != 0) { printf("Configuration has errors\n"); *ret = 1; } else printf("Configuration OK\n"); return 0; } /* Previous errors - exit */ if(*ret !=0) return 0; /* First lock check, just to be user-friendly to the operator */ if(!rtOpts->ignore_daemon_lock) { if(!writeLockFile(rtOpts)) { /* check and create Lock */ ERROR("Error: file lock failed (use -L or global:ignore_lock to ignore lock file)\n"); *ret = 3; return 0; } /* check for potential conflicts when automatic lock files are used */ if(!checkOtherLocks(rtOpts)) { *ret = 3; return 0; } } /* Manage log files: stats, log, status and quality file */ restartLogging(rtOpts); /* Allocate memory after we're done with other checks but before going into daemon */ ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock)); if (!ptpClock) { PERROR("Error: Failed to allocate memory for protocol engine data"); *ret = 2; return 0; } else { DBG("allocated %d bytes for protocol engine data\n", (int)sizeof(PtpClock)); ptpClock->foreign = (ForeignMasterRecord *) calloc(rtOpts->max_foreign_records, sizeof(ForeignMasterRecord)); if (!ptpClock->foreign) { PERROR("failed to allocate memory for foreign " "master data"); *ret = 2; free(ptpClock); return 0; } else { DBG("allocated %d bytes for foreign master data\n", (int)(rtOpts->max_foreign_records * sizeof(ForeignMasterRecord))); } ptpClock->owd_filt = FilterCreate(FILTER_EXPONENTIAL_SMOOTH, "owd"); ptpClock->ofm_filt = FilterCreate(FILTER_MOVING_AVERAGE, "ofm"); } if(rtOpts->statisticsLog.logEnabled) ptpClock->resetStatisticsLog = TRUE; /* Init to 0 net buffer */ memset(ptpClock->msgIbuf, 0, PACKET_SIZE); memset(ptpClock->msgObuf, 0, PACKET_SIZE); /* Init user_description */ memset(ptpClock->user_description, 0, sizeof(ptpClock->user_description)); memcpy(ptpClock->user_description, &USER_DESCRIPTION, sizeof(USER_DESCRIPTION)); /* Init outgoing management message */ ptpClock->outgoingManageTmp.tlv = NULL; /* DAEMON */ #ifdef PTPD_NO_DAEMON if(!rtOpts->nonDaemon) { rtOpts->nonDaemon=TRUE; } #endif if(!rtOpts->nonDaemon) { /* * fork to daemon - nochdir non-zero to preserve the working directory: * allows relative paths to be used for log files, config files etc. * Always redirect stdout/err to /dev/null */ if (daemon(1,0) == -1) { PERROR("Failed to start as daemon"); *ret = 3; return 0; } INFO(" Info: Now running as a daemon\n"); /* * Wait for the parent process to terminate, but not forever. * On some systems this happened after we tried re-acquiring * the lock, so the lock would fail. Hence, we wait. */ for (i = 0; i < 1000000; i++) { /* Once we've been reaped by init, parent PID will be 1 */ if(getppid() == 1) break; usleep(1); } } /* Second lock check, to replace the contents with our own new PID and re-acquire the advisory lock */ if(!rtOpts->nonDaemon && !rtOpts->ignore_daemon_lock) { /* check and create Lock */ if(!writeLockFile(rtOpts)) { ERROR("Error: file lock failed (use -L or global:ignore_lock to ignore lock file)\n"); *ret = 3; return 0; } } #if defined(linux) && defined(HAVE_SCHED_H) /* Try binding to a single CPU core if configured to do so */ if(rtOpts->cpuNumber > -1) { cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(rtOpts->cpuNumber,&mask); if(sched_setaffinity(0, sizeof(mask), &mask) < 0) { PERROR("Could not bind to CPU core %d", rtOpts->cpuNumber); } else { INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", rtOpts->cpuNumber); } } #endif /* linux && HAVE_SCHED_H */ #ifdef HAVE_SYS_CPUSET_H /* Try binding to a single CPU core if configured to do so */ if(rtOpts->cpuNumber > -1) { cpuset_t mask; CPU_ZERO(&mask); CPU_SET(rtOpts->cpuNumber,&mask); if(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask), &mask) < 0) { PERROR("Could not bind to CPU core %d", rtOpts->cpuNumber); } else { INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", rtOpts->cpuNumber); } } #endif /* HAVE_SYS_CPUSET_H */ /* use new synchronous signal handlers */ signal(SIGINT, catchSignals); signal(SIGTERM, catchSignals); signal(SIGHUP, catchSignals); signal(SIGUSR1, catchSignals); signal(SIGUSR2, catchSignals); #if defined PTPD_SNMP /* Start SNMP subsystem */ if (rtOpts->snmp_enabled) snmpInit(rtOpts, ptpClock); #endif NOTICE(USER_DESCRIPTION" started successfully on %s using \"%s\" preset (PID %d)\n", rtOpts->ifaceName, (getPtpPreset(rtOpts->selectedPreset,rtOpts)).presetName, getpid()); ptpClock->resetStatisticsLog = TRUE; #ifdef PTPD_STATISTICS if (rtOpts->delayMSOutlierFilterEnabled) { ptpClock->delayMSRawStats = createDoubleMovingStdDev(rtOpts->delayMSOutlierFilterCapacity); strncpy(ptpClock->delayMSRawStats->identifier, "delayMS", 10); ptpClock->delayMSFiltered = createDoubleMovingMean(rtOpts->delayMSOutlierFilterCapacity); } else { ptpClock->delayMSRawStats = NULL; ptpClock->delayMSFiltered = NULL; } if (rtOpts->delaySMOutlierFilterEnabled) { ptpClock->delaySMRawStats = createDoubleMovingStdDev(rtOpts->delaySMOutlierFilterCapacity); strncpy(ptpClock->delaySMRawStats->identifier, "delaySM", 10); ptpClock->delaySMFiltered = createDoubleMovingMean(rtOpts->delaySMOutlierFilterCapacity); } else { ptpClock->delaySMRawStats = NULL; ptpClock->delaySMFiltered = NULL; } #endif *ret = 0; return ptpClock; fail: dictionary_del(rtOpts->candidateConfig); return 0; }
/** * Signal handler for HUP which tells us to swap the log file * and reload configuration file if specified * * @param sig */ void do_signal_sighup(RunTimeOpts * rtOpts, PtpClock * ptpClock) { NOTIFY("SIGHUP received\n"); #ifdef RUNTIME_DEBUG if(rtOpts->transport == UDP_IPV4 && rtOpts->ip_mode != IPMODE_UNICAST) { DBG("SIGHUP - running an ipv4 multicast based mode, re-sending IGMP joins\n"); netRefreshIGMP(&ptpClock->netPath, rtOpts, ptpClock); } #endif /* RUNTIME_DEBUG */ /* if we don't have a config file specified, we're done - just reopen log files*/ if(strlen(rtOpts->configFile) == 0) goto end; dictionary* tmpConfig = dictionary_new(0); /* Try reloading the config file */ NOTIFY("Reloading configuration file: %s\n",rtOpts->configFile); if(!loadConfigFile(&tmpConfig, rtOpts)) { dictionary_del(tmpConfig); goto end; } dictionary_merge(rtOpts->cliConfig, tmpConfig, 1, "from command line"); /* Load default config to fill in the blanks in the config file */ RunTimeOpts tmpOpts; loadDefaultSettings(&tmpOpts); /* Check the new configuration for errors, fill in the blanks from defaults */ if( ( rtOpts->candidateConfig = parseConfig(tmpConfig,&tmpOpts)) == NULL ) { WARNING("Configuration file has errors, reload aborted\n"); dictionary_del(tmpConfig); goto end; } /* Check for changes between old and new configuration */ if(compareConfig(rtOpts->candidateConfig,rtOpts->currentConfig)) { INFO("Configuration unchanged\n"); goto cleanup; } /* * Mark which subsystems have to be restarted. Most of this will be picked up by doState() * If there are errors past config correctness (such as non-existent NIC, * or lock file clashes if automatic lock files used - abort the mission */ rtOpts->restartSubsystems = checkSubsystemRestart(rtOpts->candidateConfig, rtOpts->currentConfig); /* If we're told to re-check lock files, do it: tmpOpts already has what rtOpts should */ if( (rtOpts->restartSubsystems & PTPD_CHECK_LOCKS) && tmpOpts.autoLockFile && !checkOtherLocks(&tmpOpts)) { rtOpts->restartSubsystems = -1; } /* If the network configuration has changed, check if the interface is OK */ if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) { INFO("Network configuration changed - checking interface\n"); if(!testInterface(tmpOpts.ifaceName, &tmpOpts)) { rtOpts->restartSubsystems = -1; ERROR("Error: Cannot use %s interface\n",tmpOpts.ifaceName); } } #if defined(linux) && defined(HAVE_SCHED_H) /* Changing the CPU affinity mask */ if(rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration: changing selected CPU core\n"); cpu_set_t mask; CPU_ZERO(&mask); if(tmpOpts.cpuNumber > -1) { CPU_SET(tmpOpts.cpuNumber,&mask); } else { int i; for(i = 0; i < CPU_SETSIZE; i++) { CPU_SET(i, &mask); } } if(sched_setaffinity(0, sizeof(mask), &mask) < 0) { if(tmpOpts.cpuNumber == -1) { PERROR("Could not unbind from CPU core %d", rtOpts->cpuNumber); } else { PERROR("Could bind to CPU core %d", tmpOpts.cpuNumber); } rtOpts->restartSubsystems = -1; } else { if(tmpOpts.cpuNumber > -1) INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); else INFO("Successfully unbound "PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } } #endif /* linux && HAVE_SCHED_H */ #ifdef HAVE_SYS_CPUSET_H /* Changing the CPU affinity mask */ if (rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration:" "changing selected CPU core\n"); cpuset_t mask; CPU_ZERO(&mask); if (tmpOpts.cpuNumber < 0) { if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_CPUSET, 1, sizeof(mask), &mask) < 0) PERROR("Could not get affinity."); if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask), &mask) < 0) PERROR("Could not unbind from CPU core %d", rtOpts->cpuNumber); else INFO("Successfully unbound " PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } else { CPU_SET(tmpOpts.cpuNumber,&mask); if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(mask), &mask) < 0) { PERROR("Could not bind to CPU core %d", tmpOpts.cpuNumber); rtOpts->restartSubsystems = -1; } else { INFO("Successfully bound " PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); } } } #endif if(rtOpts->restartSubsystems == -1) { ERROR("New configuration cannot be applied - aborting reload\n"); rtOpts->restartSubsystems = 0; goto cleanup; } /* Tell parseConfig to shut up - it's had its chance already */ dictionary_set(rtOpts->candidateConfig,"%quiet%:%quiet%","Y"); /** * Commit changes to rtOpts and currentConfig * (this should never fail as the config has already been checked if we're here) * However if this DOES fail, some default has been specified out of range - * this is the only situation where parse will succeed but commit not: * disable quiet mode to show what went wrong, then die. */ if (rtOpts->currentConfig) { dictionary_del(rtOpts->currentConfig); } if ( (rtOpts->currentConfig = parseConfig(rtOpts->candidateConfig,rtOpts)) == NULL) { CRITICAL("************ "PTPD_PROGNAME": parseConfig returned NULL during config commit" " - this is a BUG - report the following: \n"); dictionary_unset(rtOpts->candidateConfig,"%quiet%:%quiet%"); if ((rtOpts->currentConfig = parseConfig(rtOpts->candidateConfig,rtOpts)) == NULL) CRITICAL("*****************" PTPD_PROGNAME" shutting down **********************\n"); /* * Could be assert(), but this should be done any time this happens regardless of * compile options. Anyhow, if we're here, the daemon will no doubt segfault soon anyway */ abort(); } /* clean up */ cleanup: dictionary_del(tmpConfig); dictionary_del(rtOpts->candidateConfig); end: if(rtOpts->recordLog.logEnabled || rtOpts->eventLog.logEnabled || (rtOpts->statisticsLog.logEnabled)) INFO("Reopening log files\n"); restartLogging(rtOpts); if(rtOpts->statisticsLog.logEnabled) ptpClock->resetStatisticsLog = TRUE; }
void applyConfig(dictionary *baseConfig, RunTimeOpts *rtOpts, PtpClock *ptpClock) { Boolean reloadSuccessful = TRUE; /* Load default config to fill in the blanks in the config file */ RunTimeOpts tmpOpts; loadDefaultSettings(&tmpOpts); /* Check the new configuration for errors, fill in the blanks from defaults */ if( ( rtOpts->candidateConfig = parseConfig(CFGOP_PARSE, NULL, baseConfig, &tmpOpts)) == NULL ) { WARNING("Configuration has errors, reload aborted\n"); return; } /* Check for changes between old and new configuration */ if(compareConfig(rtOpts->candidateConfig,rtOpts->currentConfig)) { INFO("Configuration unchanged\n"); goto cleanup; } /* * Mark which subsystems have to be restarted. Most of this will be picked up by doState() * If there are errors past config correctness (such as non-existent NIC, * or lock file clashes if automatic lock files used - abort the mission */ rtOpts->restartSubsystems = checkSubsystemRestart(rtOpts->candidateConfig, rtOpts->currentConfig, rtOpts); /* If we're told to re-check lock files, do it: tmpOpts already has what rtOpts should */ if( (rtOpts->restartSubsystems & PTPD_CHECK_LOCKS) && tmpOpts.autoLockFile && !checkOtherLocks(&tmpOpts)) { reloadSuccessful = FALSE; } /* If the network configuration has changed, check if the interface is OK */ if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) { INFO("Network configuration changed - checking interface(s)\n"); if(!testInterface(tmpOpts.primaryIfaceName, &tmpOpts)) { reloadSuccessful = FALSE; ERROR("Error: Cannot use %s interface\n",tmpOpts.primaryIfaceName); } if(rtOpts->backupIfaceEnabled && !testInterface(tmpOpts.backupIfaceName, &tmpOpts)) { rtOpts->restartSubsystems = -1; ERROR("Error: Cannot use %s interface as backup\n",tmpOpts.backupIfaceName); } } #if (defined(linux) && defined(HAVE_SCHED_H)) || defined(HAVE_SYS_CPUSET_H) || defined(__QNXNTO__) /* Changing the CPU affinity mask */ if(rtOpts->restartSubsystems & PTPD_CHANGE_CPUAFFINITY) { NOTIFY("Applying CPU binding configuration: changing selected CPU core\n"); if(setCpuAffinity(tmpOpts.cpuNumber) < 0) { if(tmpOpts.cpuNumber == -1) { ERROR("Could not unbind from CPU core %d\n", rtOpts->cpuNumber); } else { ERROR("Could bind to CPU core %d\n", tmpOpts.cpuNumber); } reloadSuccessful = FALSE; } else { if(tmpOpts.cpuNumber > -1) INFO("Successfully bound "PTPD_PROGNAME" to CPU core %d\n", tmpOpts.cpuNumber); else INFO("Successfully unbound "PTPD_PROGNAME" from cpu core CPU core %d\n", rtOpts->cpuNumber); } } #endif if(!reloadSuccessful) { ERROR("New configuration cannot be applied - aborting reload\n"); rtOpts->restartSubsystems = 0; goto cleanup; } /** * Commit changes to rtOpts and currentConfig * (this should never fail as the config has already been checked if we're here) * However if this DOES fail, some default has been specified out of range - * this is the only situation where parse will succeed but commit not: * disable quiet mode to show what went wrong, then die. */ if (rtOpts->currentConfig) { dictionary_del(&rtOpts->currentConfig); } if ( (rtOpts->currentConfig = parseConfig(CFGOP_PARSE_QUIET, NULL, rtOpts->candidateConfig,rtOpts)) == NULL) { CRITICAL("************ "PTPD_PROGNAME": parseConfig returned NULL during config commit" " - this is a BUG - report the following: \n"); if ((rtOpts->currentConfig = parseConfig(CFGOP_PARSE, NULL, rtOpts->candidateConfig,rtOpts)) == NULL) CRITICAL("*****************" PTPD_PROGNAME" shutting down **********************\n"); /* * Could be assert(), but this should be done any time this happens regardless of * compile options. Anyhow, if we're here, the daemon will no doubt segfault soon anyway */ abort(); } /* clean up */ cleanup: dictionary_del(&rtOpts->candidateConfig); }