Example #1
0
void serviceListener(port){
	
	pthread_t thread;
	int sockfd,n,i,rc;
	struct sockaddr_in servaddr,cliaddr;
	socklen_t len;
	unsigned char buffer[500];
	unsigned char response[500] ={0};
	unsigned char command[] = {0x50,0x32,0x50};
	unsigned char ping[] = {0x0a,0x00,0x00,0x00,0x14};
	char str[INET_ADDRSTRLEN];
	int redirectPort;
	int repPos;
	struct repeater repeaterInfo;
	sqlite3_stmt *stmt;
	unsigned char SQLQUERY[200] = {0};
	fd_set fdService;
	struct timeval timeout;
	time_t timeNow;

	syslog(LOG_NOTICE,"Listener for port %i started",port);

	//Create the socket to listen to the service port
	sockfd=socket(AF_INET,SOCK_DGRAM,0);
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	servaddr.sin_port=htons(port);
	bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
	FD_ZERO(&fdService);
	
	for (;;){
		FD_SET(sockfd, &fdService);
		timeout.tv_sec = 2;
		timeout.tv_usec = 0;
		rc = select(sockfd+1, &fdService, NULL, NULL, &timeout);
		if (FD_ISSET(sockfd,&fdService)) {
			len = sizeof(cliaddr);
			memset(&buffer,0,500);
			n = recvfrom(sockfd,buffer,500,0,(struct sockaddr *)&cliaddr,&len);
			if (memcmp(buffer,command,sizeof(command)) == 0){  //See if what is received is a command or heartbeat
				inet_ntop(AF_INET, &(cliaddr.sin_addr), str, INET_ADDRSTRLEN);
				time(&timeNow);
				switch (buffer[20]){
					int rdacPos;
					case 0x10:{  //PTPP request received
					if(isDiscarded(cliaddr)) continue;
					rdacPos = setRdacRepeater(cliaddr);
					if (rdacPos == 99) continue; //too many repeaters
					if (difftime(timeNow,rdacList[rdacPos].lastPTPPConnect) < 10) continue;  //Ignore connect request
					syslog(LOG_NOTICE,"PTPP request from repeater [%s]",str);
					memcpy(response,buffer,n);
					//Assign device ID
					response[4]++;
					response[13]=0x01;
					response[n] = 0x01;
					sendto(sockfd,response,n+1,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
					syslog(LOG_NOTICE,"Assigned PTPP device 1 to repeater [%s]",str);
					time(&rdacList[rdacPos].lastPTPPConnect);
					break;}
				
					case 0x11:{  //Request to startup DMR received
					int rdacPos;
					//See if the repeater is already known in the RDAC list
					if(isDiscarded(cliaddr)) continue;
					rdacPos = findRdacRepeater(cliaddr);
					if (difftime(timeNow,rdacList[rdacPos].lastDMRConnect) < 10) continue;  //Ignore connect request
					time(&rdacList[rdacPos].lastDMRConnect);
					syslog(LOG_NOTICE,"DMR request from repeater [%s]",str);
					if (rdacPos == 99){  //If  not ignore the DMR request
						syslog(LOG_NOTICE,"DMR request from repeater not in RDAC list [%s], ignoring",str);
						continue;
					}
					//See if RDAC info from the repeater has already been received
					if (!rdacList[rdacPos].id > 0){ //If not ignore DMR request
						syslog(LOG_NOTICE,"RDAC info not received from repeater yet [%s], ignoring",str);
						continue;
					}
					//Now that we have repeater info, initialize the repeater
					repPos = initRepeater(rdacList[rdacPos]);
					if (repPos == 99) continue;   //If 99 returned, more repeaters then allowed
					memcpy(response,buffer,n);
					//Assign device ID
					response[4]++;
					response[13]=0x01;
					response[n] = 0x01;
					//cliaddr.sin_port=htons(port);
					cliaddr.sin_port=rdacList[rdacPos].address.sin_port;
					sendto(sockfd,response,n+1,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
					syslog(LOG_NOTICE,"Assigned DMR device 1 to repeater [%s - %s]",str,repeaterList[repPos].callsign);
					//Assign port number
					response[4] = 0x0b;
					unsigned char rep[] = {0x00,0xff,0x01,0x00};
					memcpy(response + 12,rep,4);
					unsigned char rport[] = {0xff,0x01,0x00,0x00};
					redirectPort = baseDmrPort + repPos; 
					rport[2] = redirectPort;
					rport[3] = redirectPort >> 8;
					memcpy(response + n,rport,4);
					if (repeaterList[repPos].dmrOnline){  //If repeater is not offline, but we still get a request, just point it back to old thread
						rdacList[repPos].rdacUpdateAttempts = 0;
						rdacList[repPos].rdacUpdated = false;
						syslog(LOG_NOTICE,"DMR request from repeater [%s - %s] already assigned a DMR port, not starting thread",str,repeaterList[repPos].callsign);
					}
					else{  //Start a new DMR thread for this repeater
						struct sockInfo *param = malloc(sizeof(struct sockInfo));
						param->address = cliaddr;
						param->port = redirectPort;
						pthread_create(&thread, NULL, dmrListener,param);
					}
					sendto(sockfd,response,n+4,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
					syslog(LOG_NOTICE,"Re-directed repeater [%s - %s] to DMR port %i",str,repeaterList[repPos].callsign,redirectPort);
					break;}

					case 0x12:{  ////Request to startup RDAC received
					int rdacPos;
					//Initialize this repeater for RDAC
					if(isDiscarded(cliaddr)) continue;
					//rdacPos = setRdacRepeater(cliaddr);
					rdacPos = findRdacRepeater(cliaddr);
					cliaddr.sin_port=rdacList[rdacPos].address.sin_port;
					if (difftime(timeNow,rdacList[rdacPos].lastRDACConnect) < 10) continue;  //Ignore connect request
					syslog(LOG_NOTICE,"RDAC request from repeater [%s]",str);
					//if (rdacPos == 99) continue;   //If 99 returned, more repeaters then allowed
					if (rdacPos == 99){
						rdacPos = setRdacRepeater(cliaddr);
						cliaddr.sin_port=htons(port);
					}
					memcpy(response,buffer,n);
					//Assign device ID
					response[4]++;
					response[13]=0x01;
					response[n] = 0x01;
					//cliaddr.sin_port=htons(port);
					sendto(sockfd,response,n+1,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
					syslog(LOG_NOTICE,"Assigned RDAC device 1 to repeater [%s]",str);
					//Assign port number
					response[4] = 0x0b;
					unsigned char rep[] = {0xff,0xff,0x01,0x00};
					memcpy(response + 12,rep,4);
					unsigned char port[] = {0xff,0x01,0x00,0x00};
					redirectPort = baseRdacPort + (rdacPos * 2);
					port[2] = redirectPort;
					port[3] = redirectPort >> 8;
					memcpy(response + n,port,4);
					if (rdacList[rdacPos].rdacOnline){  //If repeater is not offline, but we still get a request, just point it back to old thread
						syslog(LOG_NOTICE,"RDAC request from repeater [%s - %s] already assigned a RDAC port, not starting thread",str,rdacList[rdacPos].callsign);
						rdacList[rdacPos].rdacUpdateAttempts = 0;
					}
					else{  //Start a new RDAC thread for this repeater
						struct sockInfo *param = malloc(sizeof(struct sockInfo));
						param->address = cliaddr;
						param->port = redirectPort;
						pthread_create(&thread, NULL, rdacListener,param);
					}
					sendto(sockfd,response,n+4,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
					syslog(LOG_NOTICE,"Re-directed repeater [%s] to RDAC port %i",str,redirectPort);
					time(&rdacList[rdacPos].lastRDACConnect);
					break;}

				}
			}
		
			if ((memcmp(buffer+4,ping,sizeof(ping)) == 0) && repeaterList[findRepeater(cliaddr)].dmrOnline){//Is this a heartbeat from a repeater on the service port ? And do we know the repeater ?
				memcpy(response,buffer,n);
				response[12]++;
				sendto(sockfd,response,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
			}
		}
Example #2
0
void CYSFReflector::run()
{
	bool ret = m_conf.read();
	if (!ret) {
		::fprintf(stderr, "YSFRefector: cannot read the .ini file\n");
		return;
	}

	ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
	if (!ret) {
		::fprintf(stderr, "YSFReflector: unable to open the log file\n");
		return;
	}

#if !defined(_WIN32) && !defined(_WIN64)
	bool m_daemon = m_conf.getDaemon();
	if (m_daemon) {
		// Create new process
		pid_t pid = ::fork();
		if (pid == -1) {
			::LogWarning("Couldn't fork() , exiting");
			return;
		}
		else if (pid != 0)
			exit(EXIT_SUCCESS);

		// Create new session and process group
		if (::setsid() == -1) {
			::LogWarning("Couldn't setsid(), exiting");
			return;
		}

		// Set the working directory to the root directory
		if (::chdir("/") == -1) {
			::LogWarning("Couldn't cd /, exiting");
			return;
		}

		::close(STDIN_FILENO);
		::close(STDOUT_FILENO);
		::close(STDERR_FILENO);

		//If we are currently root...
		if (getuid() == 0) {
			struct passwd* user = ::getpwnam("mmdvm");
			if (user == NULL) {
				::LogError("Could not get the mmdvm user, exiting");
				return;
			}

			uid_t mmdvm_uid = user->pw_uid;
			gid_t mmdvm_gid = user->pw_gid;

			//Set user and group ID's to mmdvm:mmdvm
			if (setgid(mmdvm_gid) != 0) {
				::LogWarning("Could not set mmdvm GID, exiting");
				return;
			}

			if (setuid(mmdvm_uid) != 0) {
				::LogWarning("Could not set mmdvm UID, exiting");
				return;
			}

			//Double check it worked (AKA Paranoia) 
			if (setuid(0) != -1) {
				::LogWarning("It's possible to regain root - something is wrong!, exiting");
				return;
			}
		}
	}
#endif

	CNetwork network(m_conf.getNetworkPort(), m_conf.getName(), m_conf.getDescription(), m_conf.getNetworkDebug());

	ret = network.open();
	if (!ret)
		return;

	CStopWatch stopWatch;
	stopWatch.start();

	CTimer dumpTimer(1000U, 120U);
	dumpTimer.start();

	CTimer pollTimer(1000U, 5U);
	pollTimer.start();

	LogMessage("Starting YSFReflector-%s", VERSION);

	CTimer watchdogTimer(1000U, 0U, 1500U);

	unsigned char tag[YSF_CALLSIGN_LENGTH];
	unsigned char src[YSF_CALLSIGN_LENGTH];
	unsigned char dst[YSF_CALLSIGN_LENGTH];

	for (;;) {
		unsigned char buffer[200U];

		unsigned int len = network.readData(buffer);
		if (len > 0U) {
			if (!watchdogTimer.isRunning()) {
				::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH);

				if (::memcmp(buffer + 14U, "          ", YSF_CALLSIGN_LENGTH) != 0)
					::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
				else
					::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH);

				if (::memcmp(buffer + 24U, "          ", YSF_CALLSIGN_LENGTH) != 0)
					::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
				else
					::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH);

				LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
			} else {
				if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) {
					bool changed = false;

					if (::memcmp(buffer + 14U, "          ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
						::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
						changed = true;
					}

					if (::memcmp(buffer + 24U, "          ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
						::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
						changed = true;
					}

					if (changed)
						LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
				}
			}

			// Only accept transmission from an already accepted repeater
			if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) {
				watchdogTimer.start();

				std::string callsign = std::string((char*)(buffer + 4U), YSF_CALLSIGN_LENGTH);
				CYSFRepeater* rpt = findRepeater(callsign);
				if (rpt != NULL) {
					for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
						if ((*it)->m_callsign != callsign)
							network.writeData(buffer, (*it)->m_address, (*it)->m_port);
					}
				}

				if ((buffer[34U] & 0x01U) == 0x01U) {
					LogMessage("Received end of transmission");
					watchdogTimer.stop();
				}
			}
		}

		// Refresh/add repeaters based on their polls
		std::string callsign;
		in_addr address;
		unsigned int port;
		bool ret = network.readPoll(callsign, address, port);
		if (ret) {
			CYSFRepeater* rpt = findRepeater(callsign);
			if (rpt == NULL) {
				LogMessage("Adding %s", callsign.c_str());
				rpt = new CYSFRepeater;
				rpt->m_timer.start();
				rpt->m_callsign = callsign;
				rpt->m_address  = address;
				rpt->m_port     = port;
				m_repeaters.push_back(rpt);
				network.setCount(m_repeaters.size());
			} else {
				rpt->m_timer.start();
				rpt->m_address = address;
				rpt->m_port    = port;
			}
		}

		unsigned int ms = stopWatch.elapsed();
		stopWatch.start();

		network.clock(ms);

		pollTimer.clock(ms);
		if (pollTimer.hasExpired()) {
			for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
				network.writePoll((*it)->m_address, (*it)->m_port);
			pollTimer.start();
		}

		// Remove any repeaters that haven't reported for a while
		for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
			(*it)->m_timer.clock(ms);

		for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
			if ((*it)->m_timer.hasExpired()) {
				LogMessage("Removing %s", (*it)->m_callsign.c_str());
				m_repeaters.erase(it);
				network.setCount(m_repeaters.size());
				break;
			}
		}

		watchdogTimer.clock(ms);
		if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
			LogMessage("Network watchdog has expired");
			watchdogTimer.stop();
		}

		dumpTimer.clock(ms);
		if (dumpTimer.hasExpired()) {
			dumpRepeaters();
			dumpTimer.start();
		}

		if (ms < 5U) {
#if defined(_WIN32) || defined(_WIN64)
			::Sleep(5UL);		// 5ms
#else
			::usleep(5000);		// 5ms
#endif
		}
	}

	network.close();

	::LogFinalise();
}