summaryrefslogblamecommitdiffstats
path: root/LogReceiver/networkdiscovery.cpp
blob: 159321dc1ad6062dc66e94977dd9066fe9661b76 (plain) (tree)
1
2
3
4
5
6
7
8
9
                             
 

                            
                                                     

                                        

 
                                       


 
                                                                        
                                    
 
                           

                         




                                                    
                  
                                                                        


                                                                                 
                                                                       
                                                              
                                                                                
                                                         

                                                             


                       

                                                                                    
                                    


                                                                




                                                                                                         

                       
 
                                               
                                                                                          


                                              
















                                                                             

                                                            


                       

 
                                                                                               
                                                                          

 































                                                                                         
                                                               
                                                                             










                                                                                                  


                                                                                                          



                                                                                 
                                                                          


                                                   



                      
                                                                                
                              







                                                                        
                 
                      

 
                                                             






































                                                                                                                    
                                                              



                                       

 
                                                     












                                                                                

 
                                                          
                       



                                                                 


                                                                      
 
                                
                                                                                                 



                                                                
                                                

                                                                              


                                                                     

                                                                              




                                                                      
                                                     
                        
                                                           

                            


         


   
                                              

                                             

                                                  
                                       

                                                        


                                                                           


   
                                                 








                                                                                


   
                                                              


                                                 
 


                                                     
 


                                                                


         

   


                                                                       
   
                                         
                                                                                

                                                      


                                                      
                              
                           

                                             

                                                        


         


















                                                                                      
   
                                                                                

                             
                                                      


                                                       

                                               
                             





                                                                                  



                                   
                                                                   

                                
                                                                   

                                  
                                                                   

                              
                                                                   

                              
                                                                   

                                     
                                                                   

                                  
                                                                   






                                      
                                                                   

                                  
                                                                   

                                 
                                                                    







                                
                                                     

                      

                                     

         
 











                                                                                    
                                                                  












                                                                                    
                                                      
   
  
                                                          
                                                  

                                                                     
 

                                            
                                                                                                             







                                                                                       
                                                                



                                                                        
                                                  
                 
         
                                                               
                          
                                       
         
                                                  


                                            
 
  
                                                          



                                                                     
                                                                                                         

                                                    
                                                                                                                     












                                                                                            
                                                                                                                 













                                                                               





                                                                           
                                               


                                                                     

 















                                                                                    
                                                      
   
                                                  
                                                     
                            


                                                            


                             
#include "networkdiscovery.h"

#include "../common/fbgui.h"

NetworkDiscovery::NetworkDiscovery(QObject *parent) {

	server = new QLocalServer(this);
}

NetworkDiscovery::~NetworkDiscovery() {

}

void NetworkDiscovery::initAndRun(QString serverPath, QString pathToExe,
		QStringList* args) {

	_userChoice = true;
	_blocked = false;

	if (serverPath != DEFAULT_QTSOCKETADDRESS) {
		dhcpcdArguments.append("-q");
		dhcpcdArguments.append(serverPath);
	}
	if (!server->listen(serverPath)) {
		/*
		 QMessageBox::critical(this, tr("NetworkDiscovery"), tr(
		 "Unable to start the server: %1.") .arg(server->errorString()));
		 close();
		 */
		// emit signal to the gui that a critial error occoured
		QString errorInfo("Unable to start server: ");
		qDebug() << "--- \t [NetworkDiscovery::initAndRun] " + errorInfo
				<< server->errorString();
		emit
		abortBoot(errorInfo + server->errorString());
		return;
	}

	connect(server, SIGNAL(newConnection()), this, SLOT(handleNewConnection()));

	pathToDhcpcdExe = pathToExe;
	// check if the path to the customdhcpcd file is correct
	QFileInfo fInfo(pathToDhcpcdExe);
	if (!fInfo.exists()) {
		qDebug()
				<< "couldn't find customdhcpcd exe. Please check the path to this file.";
		emit
		abortBoot(
				"couldn't find customdhcpcd exe. Please check the path to this file.");
		return;
	}

	if (args != NULL && !args->isEmpty()) {
		qDebug() << "--- \t [NetworkDiscovery::initAndRun] added additional args";
		dhcpcdArguments.append(*args);
	}

	numberOfProcesses = 0;

	// start the main work:

	QList<QString> list = getListOfNetworkInterfaces();

	if (list.size() > 0) {

		//list = checkCarrierState(list);


		//dhcpcdArguments.append("-d");
		QString ifName("eth0");
		numberOfProcesses = list.size();
		runDHCPCD(list);
	} else {
		qDebug() << "list is empty. Haven't found usable interface.";
		emit
		abortBoot("Haven't found usable interface");
		return;
	}

}

int NetworkDiscovery::replaceDefaultRoute(QString &ifName, QString &gateway, int af, int mss) {
	networkManager.replaceDefaultRoute(ifName, gateway, mss, AF_INET);
}

int NetworkDiscovery::ip4_replaceDefaultRoute(QString ifName, QString gateway, int mss) {
	networkManager.replaceDefaultRoute(ifName, gateway, mss, AF_INET);
}

int NetworkDiscovery::ip4_setManualConfiguration(QVariantMap result) {
	//QJson::Parser parser;
	//bool ok;

	//QVariantMap result = parser.parse(, &ok);
	//if(!ok) {
		// error
		//return -1;
	//}
	QList<QString> dns;
	dns.append(result["dns"].toString());
	return networkManager.ip4_setManualConfiguration(result["ifname"].toString(),
			                                  result["ipaddr"].toString(),
			                                  result["netmask"].toString(),
			                                  result["broadcast"].toString(),
			                                  result["gateway"].toString(),
			                                  0,
			                                  AF_INET,
			                                  true,
			                                  "/etc/",
			                                  dns);
}

QString NetworkDiscovery::getGatewayForInterface(QString ifName) {
	interfaceconfiguration * ifConf = _ifcMap.value(ifName);
	return ifConf->getGateway();
}

QList<QString> NetworkDiscovery::getListOfNetworkInterfaces() {
	QList<QNetworkInterface> nIList = QNetworkInterface::allInterfaces();
	QList<QString> result;

	if (nIList.size() > 0) {
		foreach(QNetworkInterface nI, nIList)
			{
				if (((!(nI.flags() & QNetworkInterface::CanBroadcast)
						|| nI.flags() & QNetworkInterface::IsLoopBack)
						|| nI.flags() & QNetworkInterface::IsPointToPoint)
						|| checkBlackList(nI.humanReadableName())) {
					continue;
				}
				if(!(nI.flags() & QNetworkInterface::IsUp)) {
					networkManager.bringInterfaceUpDown(nI.humanReadableName(), true);
				}
				if (!checkCarrierState(nI.humanReadableName())) {
					continue;
				}
				result.append(nI.humanReadableName());
				emit addInterface(nI.humanReadableName());
			}
	} else {
		qDebug() << "no interfaces found!";
	}
	return result;
}

QList<QString> NetworkDiscovery::checkCarrierState(QList<QString> &interfaces) {
	QList<QString> result;
	foreach(QString nI, interfaces)
		{
			if (checkCarrierState(nI)) {
				// everything is fine, cable is plugged,
				// go on with the next interface
				//continue;
				result.append(nI);
			}
		}
	return result;
}

bool NetworkDiscovery::checkCarrierState(QString interface) {

	qDebug() << "check carrier state for interface " << interface;
	QByteArray ba = interface.toAscii();
	const char * iface = ba.data();

	struct sysfs_class_device *class_device = sysfs_open_class_device("net",
			iface);
	struct dlist *attrlist = sysfs_get_classdev_attributes(class_device);
	if (attrlist != NULL) {
		struct sysfs_attribute *attr = NULL;
		dlist_for_each_data(attrlist, attr, struct sysfs_attribute) {
			if (strcmp("carrier", attr->name) == 0) {
				QString value(attr->value);
				bool ok = false;
				bool * pok = &ok;
				int v = value.toInt(pok);
				if (*pok) {
					if (v == 1) {
						qDebug()
								<< "carrier is 1. Cable is plugged. return true";
						return true;
					} else {
						qDebug()
								<< "carrier is 0. Cable is unplugged. return false";
						return false;
					}
				} else {
					qDebug() << "conversion error";
				}
			}
		}
	} else {
		qDebug() << "attrlist is Null";
	}
	sysfs_close_class_device(class_device);

	return true;
}

void NetworkDiscovery::runDHCPCD(QList<QString> &interfaces) {
	foreach(QString nI, interfaces)
		{
			runDHCPCD(nI);
		}
}

void NetworkDiscovery::runDHCPCD(QString interface) {
	emit updateStatusLabel(interface, "start DHCP");
	dhcpcdArguments.append(interface);
	QProcess * p = new QProcess(this);

	qDebug() << dhcpcdArguments;

	clientProcessToIfNameMap.insert(p, interface);
	qDebug() << clientProcessToIfNameMap;
	p->start(pathToDhcpcdExe, dhcpcdArguments);
	connect(p, SIGNAL(started()), this, SLOT(handleProcessStarted()));
	connect(p, SIGNAL(finished(int, QProcess::ExitStatus)), this,
			SLOT(handleProcessFinished(int, QProcess::ExitStatus)));
	dhcpcdArguments.removeLast();
}

bool NetworkDiscovery::checkConnectivity(QString ifName) {
	int metric = 0;

	// get gateway address
	QString pathToGatewayFile(DEFAULT_GATEWAY_INFO_LOCATION);
	pathToGatewayFile += ifName;
	interfaceconfiguration *ifConf = new interfaceconfiguration();
	ifConf->readConfigOutOfFile(pathToGatewayFile);
	_ifcMap.insert(ifName, ifConf);

	// replace default route
	qDebug() << networkManager.replaceDefaultRoute(ifName, ifConf->getGateway(), 0, AF_INET);

	// check connectivity via tcp connection
	QTcpSocket *tcpSocket = new QTcpSocket(this);
	tcpSocket->connectToHost(QString("209.85.148.105"), 80);
	if (!tcpSocket->waitForConnected(500)) {
		qDebug() << "no internet connection with interface" << ifName;
		qDebug() << tcpSocket->errorString();
		emit
		updateStatusLabel(ifName, "connection not possible");
		return false;
	} else {
		qDebug() << "internet: check passed! for interface" << ifName;
		emit updateStatusLabel(ifName, "connection possible");
		if (!_userChoice) {
			// blockiere jeden weiteren check
			// emite continueBoot
			_blocked = true;
			emit continueBoot(ifName, 0);
		} else {
			emit connectionEstablished(ifName);
		}
		return true;
	}
}

/**
 *
 */
void NetworkDiscovery::handleNewConnection() {
	qDebug() << "New Connection arrived";

	/*QLocalSocket **/
	client = server ->nextPendingConnection();
	clients.insert(client, client);
	connect(client, SIGNAL(disconnected()), this,
			SLOT(handleClientDisconnect()));
	connect(client, SIGNAL(readyRead()), this, SLOT(handleNewInput()));
}

/**
 *
 */
void NetworkDiscovery::handleClientDisconnect() {
	QLocalSocket* socket = qobject_cast<QLocalSocket *> (QObject::sender());

	QLocalSocket * client = clients.value(socket);

	qDebug() << "disconnect client";
	handleNewInput(client);
	client->deleteLater();
}

/**
 *
 */
void NetworkDiscovery::handleNewInput(QLocalSocket * client) {
	qDebug() << "last read before exit";
	while (client->canReadLine()) {
		QString data(client->readLine());

		data = data.trimmed();
		qDebug() << data;
		QStringList lines = data.split("\n");

		for (int i = 0; i < lines.length(); i++) {
			handleNewInputLine(client, lines.at(i));
		}
	}
}

/**
 *
 * This method is connected to the readyRead Signal of the QLocalSocket
 * client.
 * send an ACK to the client with every received message.
 */
void NetworkDiscovery::handleNewInput() {
	QLocalSocket* socket = qobject_cast<QLocalSocket *> (QObject::sender());

	QLocalSocket * client = clients.value(socket);
	QString data(client->read(DHCP_MESSAGE_SIZE));
	client->write("ACK", ACK_SIZE);
	client->waitForBytesWritten();
	data = data.trimmed();
	//qDebug() << data;
	QStringList lines = data.split("\n");

	for (int i = 0; i < lines.length(); i++) {
		handleNewInputLine(client, lines.at(i));
	}
}

/**
 * This Method processes the send messages.
 *
 * This Method processes the send messages. It splits the line
 * into several components. Those components are:
 *  interface: interface name ==> indicates the process who send the message
 *  s_state: is the number representation of syslog.h LOG levels
 *  s_subState: is the number representation of the dhcp.c DHCP states (1 - 8) plus
 *    the status. h states (9 - ..)
 *  msg: is a message which can contain additional informations
 *
 * According to the s_state and s_subState we emit the changeProgressBarValue() signal
 * with different values.
 *
 * @param client
 *  the client who send the message
 *
 * @param data
 *  the message. (format <interfaceName>;<state>;<subState>;<msg> )
 */
void NetworkDiscovery::handleNewInputLine(QLocalSocket * client, QString data) {

	QString logMsg(data);
	QString interface = logMsg.section(";", 0, 0);
	QString s_state = logMsg.section(";", 1, 1);
	QString s_subState = logMsg.section(";", 2, 2);
	QString msg = logMsg.section(";", 3, 3);
	int st = s_state.trimmed().toInt();
	int sst = s_subState.trimmed().toInt();
	//qDebug() << logMsg;

	if (ifNameToClient.size() < numberOfProcesses && !ifNameToClient.contains(
			interface)) {
		ifNameToClient.insert(interface, client);
	}

	switch (st) {
	case LOG_INFO:
		switch (sst) {
		case DHCP_DISCOVER:
			emit changeProgressBarValue(interface, 10);
			break;
		case DHCP_OFFER:
			emit changeProgressBarValue(interface, 20);
			break;
		case DHCP_REQUEST:
			emit changeProgressBarValue(interface, 30);
			break;
		case DHCP_ACK:
			emit changeProgressBarValue(interface, 40);
			break;
		case DHCP_NAK:
			emit changeProgressBarValue(interface, 40);
			break;
		case DHCPCD_ARP_TEST:
			emit changeProgressBarValue(interface, 50);
			break;
		case DHCP_DECLINE:
			emit changeProgressBarValue(interface, 60);
			break;
		case DHCP_RELEASE:

			break;
		case DHCP_INFORM:
			break;
		case DHCPCD_CONFIGURE:
			emit changeProgressBarValue(interface, 70);
			break;
		case DHCPCD_WRITE:
			emit changeProgressBarValue(interface, 80);
			break;
		case DHCPCD_EXIT:
			emit changeProgressBarValue(interface, 100);
			break;
		case DHCPCD_LOG:

		default:
			break;
		}
		break;
	case LOG_ERR:
		qDebug() << "received error:" << msg;
		break;
	default:
		//qDebug() << logMsg;
		break;
	}
}

/**
 * This Method is called when a process is finished.
 *
 * This Method is called when a process is finished. This slot is connected
 * with the signal finished() of the QProcess class.
 * If the process finishes, it will be checked if the process exited normal
 * or if an unexpected error occurred. For this, we determine the sender (which is a
 * QProcess), get the corresponding interface (which is stored in a map), and check
 * the exitCode. Further actions are taken according to the exitCode check.
 * Normal exit:
 * 	emit changeProgressBar() to 100%
 *  emit updateStatusLabel() to check connection
 *  checkConnectivity() @see NetworkDiscovery::checkConnectivity()
 * Unexpected exit:
 *  emit updateStatusLabel() to process exited unexpected
 *  TODO:: the reason for the unexpected exit should be presented in the logfile.
 *
 * @param exitCode
 *
 * @param exitStatus
 *
 * @return bool
 * 	returns true: if the interface name i starts with a letter in the blacklist.
 *
 * 	returns false: else
 *
 * @see NetworkDiscovery::getListOfNetworkInterfaces()
 */
/*
void NetworkDiscovery::handleProcessFinished(int exitCode,
		QProcess::ExitStatus exitStatus) {
	QProcess* p = qobject_cast<QProcess *> (QObject::sender());
	QString ifName = clientProcessToIfNameMap.value(p, "ifName");

	if (ifName.compare("ifName") == 0) {
		qDebug()
				<< "--- \t [NetworkDiscovery::handleProcessFinished] haven't found process!";
	} else {
		qDebug() << "process for interface" << ifName << "finished" << exitCode
				<< exitStatus;
		if (exitCode > 0) {
			qDebug() << "process exited unexpected";
			emit updateStatusLabel(ifName, "process exited unexpected");
		} else {
			qDebug() << "process normal exit";
			qDebug() << "check internet connection";
			emit
			changeProgressBarValue(ifName, 100);
			emit
			updateStatusLabel(ifName, "check connectivity");
			checkConnectivity(ifName);
		}
	}
	QLocalSocket *client = ifNameToClient.value(ifName, 0);
	if (client != 0) {
		handleNewInput(client);
	}
	numberOfProcesses = numberOfProcesses - 1;
	if (numberOfProcesses <= 0) {
		emit allProcessesFinished();
	}
}
*/
void NetworkDiscovery::handleProcessFinished(int exitCode,
		QProcess::ExitStatus exitStatus) {

	QProcess* p = qobject_cast<QProcess *> (QObject::sender());
	QString ifName = clientProcessToIfNameMap.value(p, "ifName");
	if (!_blocked) { //_blocked becomes true, if _userChoice is false and we found a usable interface
		if (ifName.compare("ifName") == 0) {
			qDebug()
					<< "--- \t [NetworkDiscovery::handleProcessFinished] haven't found process!";
		} else {
			qDebug() << "process for interface" << ifName << "finished"
					<< exitCode << exitStatus;
			if (exitCode > 0) {
				qDebug() << "process exited unexpected";
				emit updateStatusLabel(ifName, "process exited unexpected");
			} else {
				qDebug() << "process normal exit";
				emit changeProgressBarValue(ifName, 100);
				emit updateStatusLabel(ifName, "check connectivity");
				checkConnectivity(ifName);
			}
		}
		if (!_blocked) { //_blocked becomes true, if _userChoice is false and we found a usable interface
			QLocalSocket *client = ifNameToClient.value(ifName, 0);
			if (client != 0) {
				handleNewInput(client);
			}
			numberOfProcesses = numberOfProcesses - 1;
			if (numberOfProcesses <= 0 && _userChoice) {
				emit allProcessesFinished();
			}
		}
	} else {
		qDebug() << "already blocked";
		emit updateStatusLabel(ifName, "finished DHCP");
	}
}
/**
 * This Method is called when a process is started.
 *
 * This Method is called when a process is started.
 * It prints the message: "process started for interface: <interfaceName>".
 */
void NetworkDiscovery::handleProcessStarted() {
	QProcess* p = qobject_cast<QProcess *> (QObject::sender());
	QString ifName = clientProcessToIfNameMap.value(p, "ifName");
	qDebug() << "process started for interface:" << ifName;
}

/**
 * This Method implements a blacklist.
 *
 * This Method implements a blacklist. We check the fist character
 * of the interface name. if this letter is in the list, we return true.
 * True means, that this interface won't be put into the result list of
 * getListOfNetworkInterfaces().
 *
 * @param i
 * 	is a interface name.
 *
 * @return bool
 * 	returns true: if the interface name i starts with a letter in the blacklist.
 *
 * 	returns false: else
 *
 * @see NetworkDiscovery::getListOfNetworkInterfaces()
 */
bool NetworkDiscovery::checkBlackList(QString i) {
	if (i.startsWith("v", Qt::CaseInsensitive)) {
		return true;
	} else if (i.startsWith("d", Qt::CaseInsensitive)) {
		return true;
	} else {
		return false;
	}
}