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)); } }
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(); }