📄 netmanager.cpp~
字号:
/* netmanager.cpp * * Copyright (c) 2000, Alexander Neundorf * neundorf@kde.org * * You may distribute under the terms of the GNU General Public * License as specified in the COPYING file. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#include "config.h"#include "netmanager.h"#include "lisadefines.h"#include <iostream.h>#include <unistd.h>#include <sys/un.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <strings.h>#include <errno.h>#ifndef AF_LOCAL#define AF_LOCAL AF_UNIX#endif#include "getdebug.h"#define getDebug() getDebug()<<procId//#define getDebug() cerr<<procIdNetManager::NetManager(int& rawSocketFD, int portToUse, MyString configFile, int configStyle, int strictMode):NetScanner(rawSocketFD,strictMode)//,validator(),m_listenFD(-1),m_bcFD(-1),m_basePort(portToUse),m_pipeFD(-1),m_receiveBuffer(0),m_receivedBytes(0),m_childPid(0),m_lastUpdate(0),m_isInformed(0),m_isBeingScanned(0),m_firstRun(1),m_serverServer(0),m_servedThisPeriod(0),m_serveCount(0),m_refreshTime(60),m_initialRefreshTime(60),m_increasedRefreshTime(0),m_broadcastAddress(0),m_extraConfigFile(configFile),m_configStyle(configStyle),m_usedConfigFileName(""){ getDebug()<<"NetManager::NetManager"<<endl; m_startedAt=time(0);};NetManager::~NetManager(){ getDebug()<<"netknife destructor ..."<<endl; if (m_receiveBuffer!=0) delete [] m_receiveBuffer; ::close(m_listenFD); ::close(m_bcFD);};void NetManager::readConfig(){ m_usedConfigFileName=getConfigFileName(); if (m_usedConfigFileName.isEmpty()) { cout<<"configfile not found"<<endl; cout<<"use the command line option --help and \ntake a look at the README for more information"<<endl; exit(1); }; Config config(m_usedConfigFileName); NetManager::configure(config); NetScanner::configure(config); validator.configure(config); //after reading the new configuration we should really update m_lastUpdate=0;};void NetManager::configure(Config& config){ m_refreshTime=config.getEntry("UpdatePeriod",300); MyString tmp=stripWhiteSpace(config.getEntry("BroadcastNetwork","0.0.0.0/255.255.255.255;")); tmp=tmp+","; getDebug()<<"NetManager::readConfig: "<<tmp<<endl; MyString netAddressStr=tmp.left(tmp.find('/')); tmp=tmp.mid(tmp.find('/')+1); tmp=tmp.left(tmp.find(',')); getDebug()<<"NetManager::readConfig: broadcastNet "<<netAddressStr<<" with mask "<<tmp<<endl; int netMask=inet_addr(tmp.c_str()); int netAddress=inet_addr(netAddressStr.c_str()); m_broadcastAddress= netAddress | (~netMask); getDebug()<<"NetManager::readConfig: net "<<ios::hex<<netAddress<<" with mask "<<netMask<<" gives "<<m_broadcastAddress<<endl; //maybe this way we can avoid that all servers on the net send //their requests synchronously, since now the refreshtime isn't //always the eact value of m_refreshTime, but differs always slightly if ((m_refreshTime%SELECT_TIMEOUT)==0) m_refreshTime+=2; //some limits from half a minute to half an hour if (m_refreshTime<30) m_refreshTime=30; if (m_refreshTime>1800) m_refreshTime=1800; m_initialRefreshTime=m_refreshTime;};int NetManager::prepare(){ getDebug()<<"NetManager::prepare"<<endl; ::close(m_listenFD); ::close(m_bcFD); int result(0); if (m_strictMode) { m_listenFD=::socket(AF_LOCAL, SOCK_STREAM, 0); //m_listenFD=::socket(AF_LOCAL, SOCK_STREAM, IPPROTO_TCP); MyString socketName("/tmp/resLisa-"); socketName+=getenv("LOGNAME"); ::unlink(socketName.data()); sockaddr_un serverAddr; bzero((char*)&serverAddr, sizeof(serverAddr)); serverAddr.sun_family = AF_LOCAL; strcpy(serverAddr.sun_path,socketName.data()); ::bind(m_listenFD,(sockaddr*) &serverAddr,sizeof(serverAddr)); } else { //create a listening port and listen m_listenFD = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in serverAddress; bzero((char*)&serverAddress, sizeof(serverAddress)); serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(m_basePort); int on(1); result=setsockopt(m_listenFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (result!=0) { cout<<"NetManager::prepare: setsockopt(SO_REUSEADDR) failed"<<endl; return 0; }; result=::bind(m_listenFD, (struct sockaddr *) &serverAddress, sizeof(serverAddress)); if (result!=0) { cout<<"NetManager::prepare: bind (TCP) failed"<<endl; return 0; }; }; result=::listen(m_listenFD, 32); if (result!=0) { cout<<"NetManager::prepare: listen failed"<<endl; return 0; }; getDebug()<<"NetManager::prepare: listening on port "<<m_basePort<<"..."<<endl; return 1;};void NetManager::generateFDset(fd_set *tmpFDs){ getDebug()<<"NetManager::generateFDset"<<endl; FD_ZERO(tmpFDs); FD_SET(m_listenFD,tmpFDs); getDebug()<<"NetManager::generateFDset: adding listen FD="<<m_listenFD<<endl; for (Client* tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next()) if (tmpClient->fd()!=-1) { getDebug()<<"NetManager::generateFDset: adding client FD="<<tmpClient->fd()<<endl; FD_SET(tmpClient->fd(),tmpFDs); }; if (m_pipeFD!=-1) { getDebug()<<"NetManager::generateFDset: adding pipeFD="<<m_pipeFD<<endl; FD_SET(m_pipeFD,tmpFDs); }; if ((m_bcFD!=-1) && (!m_strictMode)) { getDebug()<<"NetManager::generateFDset: adding m_bcFD="<<m_bcFD<<endl; FD_SET(m_bcFD,tmpFDs); };};int NetManager::waitForSomethingToHappen(fd_set *tmpFDs){ getDebug()<<"NetManager::waitForSomethingToHappen for 10 seconds"<<endl; if (m_firstRun) { tv.tv_sec = 1; m_firstRun=0; } else tv.tv_sec = SELECT_TIMEOUT; tv.tv_usec = 0; //generateFDset(tmpFDs); int result=select(getMaxFD(),tmpFDs,0,0,&tv); if (result>0) return 1; else return 0;};int NetManager::getMaxFD(){ int maxFD(m_listenFD); for (Client* tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next()) if (tmpClient->fd()>maxFD) maxFD=tmpClient->fd(); if (m_pipeFD>maxFD) maxFD=m_pipeFD; if (m_bcFD>maxFD) maxFD=m_bcFD; getDebug()<<"NetManager::getMaxFD()="<<maxFD+1<<endl; return maxFD+1;};int fileReadable(const MyString& filename){ FILE *file=::fopen(filename.data(), "r"); if (file==0) return 0; fclose(file); return 1;};MyString NetManager::getConfigFileName(){ MyString tmpBase(CONFIGFILEBASENAME); if (m_strictMode) tmpBase=STRICTCONFIGFILEBASENAME; if (!m_extraConfigFile.isEmpty()) m_configStyle=EXTRACONFIGSTYLE; MyString tmpFilename; if (m_configStyle==EXTRACONFIGSTYLE) { tmpFilename=m_extraConfigFile; if (fileReadable(tmpFilename)) return tmpFilename; return ""; } else if (m_configStyle==UNIXCONFIGSTYLE) { tmpFilename=getenv("HOME"); tmpFilename+=MyString("/.")+tmpBase; if (fileReadable(tmpFilename)) return tmpFilename; tmpFilename="/etc/"; tmpFilename+=tmpBase; if (fileReadable(tmpFilename)) return tmpFilename; return ""; } else if (m_configStyle==KDE1CONFIGSTYLE) { tmpFilename=getenv("HOME"); tmpFilename+=MyString("/.kde/share/config/")+tmpBase; if (fileReadable(tmpFilename)) return tmpFilename; tmpFilename=getenv("KDEDIR"); tmpFilename+=MyString("/share/config/")+tmpBase; if (fileReadable(tmpFilename)) return tmpFilename; return ""; } else if (m_configStyle==KDE2CONFIGSTYLE) { FILE *kdeConfig=popen("kde-config --path config","r"); if (kdeConfig==0) { cout<<"could not execute kde-config, check your KDE 2 installation\n"<<endl; return ""; }; //this should be large enough char buf[4*1024]; memset(buf,0,4*1024); fgets(buf,4*1024-1,kdeConfig); pclose(kdeConfig); int length=strlen(buf); if (buf[length-1]=='\n') buf[length-1]='\0'; MyString kdeDirs(buf); while (kdeDirs.contains(':')) { MyString nextDir=kdeDirs.left(kdeDirs.find(':')); kdeDirs=kdeDirs.mid(kdeDirs.find(':')+1); nextDir=nextDir+tmpBase; getDebug()<<"trying to open "<<nextDir<<endl; if (fileReadable(nextDir)) return nextDir; }; kdeDirs=kdeDirs+tmpBase; getDebug()<<"trying to open "<<kdeDirs<<endl; if (fileReadable(kdeDirs)) return kdeDirs; return ""; } return "";};int NetManager::run(){ int continueMainLoop(1); //not forever while(continueMainLoop) { getDebug()<<"\nTCPServer::run: next loop: "<<clients.size()<<" clients"<<endl; fd_set tmpFDs; generateFDset(&tmpFDs); int result=waitForSomethingToHappen(&tmpFDs); getDebug()<<"NetManager::run: something happened..."<<endl; //timeout if (result==0) { getDebug()<<"NetManager::run: serverServer=="<<m_serverServer<<endl; getDebug()<<"NetManager::run: scanning after timeout"<<endl; scan(); } else { //a new connection ? if (FD_ISSET(m_listenFD,&tmpFDs)) { getDebug()<<"NetManager::run: on m_listenFD"<<endl; struct sockaddr_in clientAddress; ksize_t clilen(sizeof(clientAddress)); bzero((char*)&clientAddress, clilen); int connectionFD=::accept(m_listenFD,(struct sockaddr *) &clientAddress, &clilen); if ((validator.isValid(clientAddress.sin_addr.s_addr)) || (m_strictMode)) { getDebug()<<"NetManager::run: adding client"<<endl; addClient(connectionFD); m_servedThisPeriod=1; m_refreshTime=m_initialRefreshTime; m_increasedRefreshTime=0; } else { getDebug()<<"NetManager::run: kicking client"<<endl; ::close(connectionFD); }; }; checkClientsAndPipes(&tmpFDs); }; serveAndClean(); }; return 1;};void NetManager::addClient(int socketFD){ getDebug()<<"NetManager::addClient on FD="<<socketFD<<endl; if (socketFD==-1) return; Client c(this,socketFD,0); clients.append(c);};void NetManager::checkClientsAndPipes(fd_set *tmpFDs){ getDebug()<<"NetManager::checkClientsAndPipes()"<<endl; //actually the clients should not send anything for (Client *tmpClient=clients.first(); tmpClient!=0; tmpClient=clients.next()) { getDebug()<<"NetManager::checkClientsAndPipes: checking client"<<endl; if (FD_ISSET(tmpClient->fd(),tmpFDs)) { getDebug()<<"NetManager::checkClientsAndPipes: client sent something"<<endl; tmpClient->read(); }; }; //now check wether we received a broadcast //m_bcFD should always be -1 in strictMode if ((m_bcFD!=-1) && (!m_strictMode)) { getDebug()<<"NetManager::checkClientsAndPipe: checking bcFD"<<endl; //yes ! if (FD_ISSET(m_bcFD,tmpFDs)) answerBroadcast(); }; //read the stuff from the forked pipe if (m_pipeFD!=-1) { getDebug()<<"NetManager::checkClientsAndPipe: checking pipe"<<endl; if (FD_ISSET(m_pipeFD,tmpFDs)) { getDebug()<<"NetManager::checkClientsAndPipes: pipe sent something"<<endl; int result=readDataFromFD(m_pipeFD); if (result!=1) { ::close(m_pipeFD); //can I really be 100% sure that the child will quit very soon ? //::waitpid(m_childPid,0,0); //I better wait for a short moment and then continue //it's better to have possibly a zombie than a blocking server IMO timeval tv; tv.tv_sec=0; tv.tv_usec=5*10*1000;//0.05 sec ::select(0,0,0,0,&tv); ::waitpid(m_childPid,0,WNOHANG); m_pipeFD=-1; getDebug()<<"NetManager::checkClientsAndPipes: everything read from pipe from proc "<<m_childPid<<endl; processScanResults(); }; }; };};void NetManager::answerBroadcast(){ //actually we should never get here in strictMode if (m_strictMode) return; //this one is called only in checkClientsAndPipes() //if we are sure that we received something on m_bcFD //so we don't need to check here again getDebug()<<"NetManager::answerBroadcast: received BC"<<endl; struct sockaddr_in sAddr; socklen_t length(sizeof(sockaddr_in)); char buf[1024]; int result=recvfrom(m_bcFD, (void*)buf, 1024, 0, (sockaddr*)&sAddr,&length); getDebug()<<"NetManager::answerBroadcast: received succesfully"<<endl; //did recvfrom() succeed ? //our frame is exactly MYFRAMELENGTH bytes big, if the received one has a different size, //it must be something different if (result!=MYFRAMELENGTH) return; //if it has the correct size, it also must have the correct identifier MyFrameType *frame=(MyFrameType*)(void*)buf; if ((ntohl(frame->id)!=MY_ID) || ((ntohl(frame->unused1)==getpid()) && (ntohl(frame->unused2)==m_startedAt))) { getDebug()<<"NetManager::answerBroadcast: must be the same machine"<<endl; return; }; //getDebug()<<"received "<<ntohl(buf[0])<<" from "<<inet_ntoa(sAddr.sin_addr)<<hex<<" "; //getDebug()<<sAddr.sin_addr.s_addr<<" "<<ntohl(sAddr.sin_addr.s_addr)<<dec<<endl; //will we answer this request ? if (!validator.isValid(sAddr.sin_addr.s_addr)) { getDebug()<<"NetManager::answerBroadcast: invalid sender"<<endl; return; }; //create the answering socket int answerFD=::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (answerFD==-1) { getDebug()<<"NetManager::answerBroadcast: could not create answering socket"<<endl; return; }; sAddr.sin_family=AF_INET; sAddr.sin_port=htons(m_basePort+1); MyFrameType answerFrame; answerFrame.id=htonl(MY_ID); answerFrame.unused1=0; answerFrame.unused2=0; //don't care about the result getDebug()<<"NetManager::answerBroadcast: sending answer"<<endl; result=::sendto(answerFD,(void*)&answerFrame,sizeof(answerFrame),0,(sockaddr*)&sAddr,length); getDebug()<<"sent "<<result<<" byte using sendto"<<endl; ::close(answerFD); //sent answer};void NetManager::serveAndClean(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -