Bläddra i källkod

Testversion mit Start/Stop/Restart Interface Funktionalität.

Rind 6 år sedan
förälder
incheckning
1f5d6064bc

+ 1 - 0
.gitignore

@@ -9,5 +9,6 @@ test/
 res/
 *.ncb
 *.o
+*.txt
 *.user
 Visual Studio 2008/

+ 53 - 6
QmlTest/main.qml

@@ -17,10 +17,21 @@ Window {
          text: idItf.interfaces[2].inet.stat.ipAddress.address
      }
 
+    Text {
+         id: idIfUpDownOut
+         x: 5
+         y: 60
+         width: 630
+         height: 300
+         color: "black"
+         font.pixelSize: 14
+         text: ""
+     }
+
     NetInterfaces {
         id: idItf
 //        itfFilterName: "eth0"
-        itfFilterAF: Interface.AF_Inet
+        itfFilterAF: Interface.AF_Inet | Interface.AF_Inet6
         itfFilterMethod: Interface.IM_Static | Interface.IM_Manual
         onError:
         {
@@ -28,7 +39,27 @@ Window {
         }
         onFilteredInterfacesChanged:
         {
-            console.warn("Filtered Interfaces may have changed!");
+//            console.warn("Filtered Interfaces may have changed!");
+        }
+        onIfUpDown:
+        {
+            idIfUpDownOut.text += msg;
+//            console.log(msg);
+        }
+        onIfUpDownCompleted:
+        {
+            switch(ctx)
+            {
+            case NetInterfaces.UDC_Start:
+                console.log("IfUp completed with code " + code);
+                break;
+            case NetInterfaces.UDC_Stop:
+                console.log("IfDown completed with code " + code);
+                break;
+            case NetInterfaces.UDC_Restart:
+                console.log("IfUpDown completed with code " + code);
+                break;
+            }
         }
     }
 
@@ -36,35 +67,51 @@ Window {
         anchors.fill: parent
         onClicked:
         {
+            var ret;
+            idIfUpDownOut.text = "";
+//            idIfUpDownOut.update();
+//            return;
+
             if(idItf.filteredInterfaces.length > 0)
             {
                 idItf.filteredInterfaces[0].inet.stat.ipAddress.address = "155.18.2.156";
                 idItf.filteredInterfaces[0].inet.stat.ipAddress.b2 = 255;
-                console.log(idItf.filteredInterfaces[0].inet.stat.ipAddress.address);
+//                console.log(idItf.filteredInterfaces[0].inet.stat.ipAddress.address);
             }
             else
             {
                 console.warn("No interface found!");
             }
 
-            idItf.itfFilterMethod |= Interface.IM_Dhcp;
             idItf.itfFilterMethod &= ~Interface.IM_Manual;
+            idItf.itfFilterMethod |=  Interface.IM_Dhcp;
 
             var itfn = idItf.newInterface("test1", Interface.AF_Inet6, Interface.IM_Dhcp);
+
             itfn.af = Interface.AF_Inet;
+            itfn.method = Interface.IM_Static;
+
             itfn.inet.stat.ipAddress.address = "192.168.3.24";
             itfn.inet.stat.netMask.address = "255.255.254.0";
             itfn.inet.stat.netPrefix = 22;
-            itfn.method = Interface.IM_Static;
             itfn.inet.stat.gateway.b0 = 192;
             itfn.inet.stat.gateway.b1 = 168;
             itfn.inet.stat.gateway.b2 = 0;
             itfn.inet.stat.gateway.b3 = 1;
             itfn.inet.stat.dnsServer[0].address = "8.8.8.8";
             itfn.inet.stat.dnsServer[1].address = "8.8.4.4";
+            itfn.selCfg = Interface.SC_AllowHotplug | Interface.SC_NoAutoDown;
+            itfn.selCfg = Interface.SC_Auto | Interface.SC_NoScripts | Interface.SC_AllowHotplug;
+
+//            ret = idItf.stopInterface(idItf.interfaces[2]);
+
+            if(idItf.ifUpDownInProgress)
+                idItf.cancelStartStopInterface();
+            else
+                ret = idItf.restartInterface(idItf.interfaces[2]);
 
 //            idItf.removeInterface(itfn);
-            idItf.saveAs("/home/wrk/share/gfanet/libgfanet/res/testitf");
+//            idItf.saveAs("/home/wrk/share/gfanet/libgfanet/res/testitf");
         }
     }
 }

+ 390 - 15
libgfanet/interfaces.cpp

@@ -1,5 +1,9 @@
 #include <string.h>
 #include <regex>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <poll.h>
 #include "util.h"
 #include "interfaces.h"
 #include "../debug.h"
@@ -61,6 +65,13 @@ static const char *g_pszIncludes[] =
 
 /////////////////////////////////////////////////////////////////////////////
 
+const char *GetIfaceCfgGroupStr(CfgGroup cg)
+{
+	if(cg >= CG_Auto && cg <= CG_NoScripts)
+		return g_pszCfgGroups[cg];
+	return "";
+}
+
 const char *GetIfaceProtoStr(IfaceProtos ip)
 {
 	if(ip >= IFP_Inet && ip <= IFP_Can)
@@ -96,7 +107,7 @@ CfgGroup ParseCfgGroup(const std::vector<std::string> &v, ITF_CONFIG_GROUP &icg)
 	if(v.size() < 2)
 		return CG_Unknown;
 
-	CfgGroup g = (CfgGroup)FindStringInList(v[0], g_pszCfgGroups, _countof(g_pszCfgGroups));
+	CfgGroup g = GetIfaceCfgGroup(v[0]);
 
 	if(g > CG_Unknown)
 	{
@@ -122,6 +133,13 @@ CfgGroup ParseCfgGroup(const std::vector<std::string> &v, ITF_CONFIG_GROUP &icg)
 
 /////////////////////////////////////////////////////////////////////////////
 
+CfgGroup GetIfaceCfgGroup(const std::string &s)
+{
+	return (CfgGroup)FindStringInList(s, g_pszCfgGroups, _countof(g_pszCfgGroups));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 IfaceProtos GetIfaceProto(const std::string &s)
 {
 	return (IfaceProtos)FindStringInList(s, g_pszProtos, _countof(g_pszProtos));
@@ -154,7 +172,7 @@ IfaceHdrType ParseIfaceHeader(const std::vector<std::string> &v, ITF_IFACE_BLOCK
 		ib.cfgName	= v[1];
 
 		int nInheritIdx = 0;
-		
+
 		for(int i = 2; i < std::min((int)(vSize - 1), 5); i++)
 		{
 			if(!v[i].compare("inherits"))
@@ -193,7 +211,7 @@ IfaceHdrType ParseIfaceHeader(const std::vector<std::string> &v, ITF_IFACE_BLOCK
 bool ParseIfaceCmd(const std::vector<std::string> &v, std::vector<IFACE_COMMAND> &c)
 {
 	auto vSize = v.size();
-	
+
 	if(vSize > 1)
 	{
 		IfaceCommands cmd = GetIfaceCommand(v[0]);
@@ -207,14 +225,14 @@ bool ParseIfaceCmd(const std::vector<std::string> &v, std::vector<IFACE_COMMAND>
 			return true;
 		}
 	}
-	
+
 	return false;
 }
 
 bool ParseIfaceDesc(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
 {
 	auto vSize = v.size();
-	
+
 	if(vSize > 1)
 	{
 		if(!v[0].compare("description"))
@@ -223,7 +241,7 @@ bool ParseIfaceDesc(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
 			return true;
 		}
 	}
-	
+
 	return false;
 }
 
@@ -231,7 +249,7 @@ bool ParseIfaceParam(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
 {
 	if(ParseIfaceCmd(v, ib.cmds))
 		return true;
-	
+
 	if(ParseIfaceDesc(v, ib))
 		return true;
 
@@ -344,7 +362,7 @@ void ProcessGroupMembers(ETC_NETWORK_INTERFACES &eni)
 			}
 		}
 	}
-
+#if 0
 	for(auto iIt = eni.ibl.begin(); iIt != eni.ibl.end(); iIt++)
 	{
 		ITF_IFACE_BLOCK &ibl = *iIt;
@@ -364,6 +382,7 @@ void ProcessGroupMembers(ETC_NETWORK_INTERFACES &eni)
 			}
 		}
 	}
+#endif
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -386,7 +405,7 @@ bool ParseEtcNetworkInterfaces(ETC_NETWORK_INTERFACES &eni, const char *pszPath)
 
 	if(!pszPath)
 		pszPath = _ETC_NETWORK_INTERFACES;
-		
+
 	eni._reset();
 
 	if(ReadFile(pszPath, buf) > 0)
@@ -554,7 +573,7 @@ bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *ps
 			{
 				line = 0;
 				const ITF_IFACE_BLOCK &ib = *iti;
-				
+
 				if(!ib.inheritedFrom.empty())
 				{
 					fprintf(pf, "iface %s", ib.cfgName.c_str());
@@ -569,7 +588,7 @@ bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *ps
 						fputs(GetIfaceMethodStr(ib.method), pf);
 					}
 					fprintf(pf, " inherits %s\n", ib.inheritedFrom.c_str());
-					
+
 				}
 				else
 					fprintf(pf, "iface %s %s %s\n", ib.cfgName.c_str(), GetIfaceProtoStr(ib.proto), GetIfaceMethodStr(ib.method));
@@ -605,7 +624,7 @@ bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *ps
 						fputc('\n', pf);
 					}
 				}
-				
+
 				if(ib.unparsed.size() > 0)
 				{
 					fputs("\t# the following entries are not handled by libgfanet:\n", pf);
@@ -632,7 +651,7 @@ bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *ps
 			for(auto iti = eni.inc.begin(); iti != eni.inc.end(); iti++)
 			{
 				const ITF_INCLUDE &inc = *iti;
-				
+
 				if(inc.inc == II_File || inc.inc == II_Directory)
 				{
 					fputs(GetIncTypeStr(inc.inc), pf);
@@ -653,19 +672,375 @@ bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *ps
 	return false;
 }
 
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
 bool RemoveInterfaceBlock(ETC_NETWORK_INTERFACES &eni, unsigned long id)
 {
 	for(auto iti = eni.ibl.begin(); iti != eni.ibl.end(); iti++)
 	{
 		ITF_IFACE_BLOCK &ib = *iti;
-		
+
 		if(ib.id == id)
 		{
 			eni.ibl.erase(iti);
-			ProcessGroupMembers(eni);
+//			ProcessGroupMembers(eni);
 			return true;
 		}
 	}
 
 	return false;
 }
+
+LPITF_IFACE_BLOCK GetInterfaceBlockByID(ETC_NETWORK_INTERFACES &eni, unsigned long id)
+{
+	for(auto iti = eni.ibl.begin(); iti != eni.ibl.end(); iti++)
+	{
+		ITF_IFACE_BLOCK &ib = *iti;
+
+		if(ib.id == id)
+			return &ib;
+	}
+
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+bool AddInterfaceToCfgGroup(ETC_NETWORK_INTERFACES &eni, unsigned long id, CfgGroup cg)
+{
+	LPITF_IFACE_BLOCK pi = GetInterfaceBlockByID(eni, id);
+
+	if(!pi || (cg < CG_Auto) || (cg > CG_NoScripts))
+		return false;
+
+	const char *pszCfgName = GetIfaceCfgGroupStr(cg);
+
+	for(auto cIt = eni.cgl.begin(); cIt != eni.cgl.end(); cIt++)
+	{
+		ITF_CONFIG_GROUP &icg = *cIt;
+
+		if(!icg.cfgName.compare(pszCfgName))
+		{
+			for(auto mIt = icg.members.begin(); mIt != icg.members.end(); mIt++)
+			{
+				std::string &rName = *mIt;
+
+				if(!rName.compare(pi->cfgName))
+					return true;	// already added
+			}
+		}
+	}
+
+	ITF_CONFIG_GROUP icg;
+	icg.cfgName = pszCfgName;
+	icg.members.push_back(pi->cfgName);
+	eni.cgl.push_back(icg);
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool RemoveInterfaceFromCfgGroup(ETC_NETWORK_INTERFACES &eni, unsigned long id, CfgGroup cg)
+{
+	LPITF_IFACE_BLOCK pi = GetInterfaceBlockByID(eni, id);
+
+	if(!pi || (cg < CG_Auto) || (cg > CG_NoScripts))
+		return false;
+
+	const char *pszCfgName = GetIfaceCfgGroupStr(cg);
+
+	for(auto cIt = eni.cgl.begin(); cIt != eni.cgl.end(); )
+	{
+		ITF_CONFIG_GROUP &icg = *cIt;
+
+		if(!icg.cfgName.compare(pszCfgName))
+		{
+			RemoveStringFromVector(pi->cfgName, icg.members);
+
+			if(!icg.members.size())
+			{
+				cIt = eni.cgl.erase(cIt);
+				continue;
+			}
+		}
+
+		++cIt;
+	}
+
+	return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+CfgGroup EnumInterfaceCfgGroups(ETC_NETWORK_INTERFACES &eni, unsigned long id, PFN_ENUM_IFACE_CFG_GROUPS_CALLBACK pfnClb, void *pCtx)
+{
+	LPITF_IFACE_BLOCK pi = GetInterfaceBlockByID(eni, id);
+
+	if(!pi || !pfnClb)
+		return CG_Unknown;
+
+	for(auto cIt = eni.cgl.begin(); cIt != eni.cgl.end(); cIt++)
+	{
+		ITF_CONFIG_GROUP &icg = *cIt;
+
+		for(auto mIt = icg.members.begin(); mIt != icg.members.end(); mIt++)
+		{
+			const std::string &rName = *mIt;
+
+			if(!rName.compare(pi->cfgName))
+			{
+				(*pfnClb)(GetIfaceCfgGroup(icg.cfgName), pCtx);
+			}
+		}
+	}
+
+	return CG_Unknown;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+// http://man7.org/linux/man-pages/man3/popen.3.html
+
+#define READ			0
+#define WRITE			1
+
+static int _IfPOpen(const char *cmd, pid_t &rpid, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctx)
+{
+	pid_t pid;
+    int fd[2];
+    pipe(fd);
+
+    if((pid = fork()) == -1)
+    {
+    	if(pfnCallback)
+        	(*pfnCallback)("fork", ctx);
+        return 0;
+    }
+
+	if(pid == 0)
+    {
+		close(fd[READ]);	// Close the READ end of the pipe since the child's fd is write-only
+		dup2(fd[WRITE], 1);	// Redirect stdout to pipe
+        setpgid(pid, pid);	//Needed so negative PIDs can kill children of /bin/sh
+        execl("/bin/sh", "/bin/sh", "-c", cmd, (char*)NULL);
+        exit(0);
+	}
+	else
+	{
+		close(fd[WRITE]);	//Close the WRITE end of the pipe since parent's fd is read-only
+	}
+
+	rpid = pid;
+	return fd[READ];
+}
+
+#if 1
+static int _IfPClose(pid_t pid, int fd, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctx)
+{
+	int stat, exitcode = 0;
+	pid_t ret;
+
+	if(pfnCallback)
+	{
+		struct pollfd pfd;
+		pfd.fd = fd;
+		pfd.events = POLLIN;
+		pfd.revents = 0;
+		ssize_t nRead;
+		char szBuf[512];
+
+		while(true)
+		{
+			ret = waitpid(pid, &stat, WNOHANG);
+			bool bExited = WIFEXITED(stat);
+
+			if(ret != 0 && ret != pid)
+			{
+				if(errno == ECHILD)
+					(*pfnCallback)("IfUpDown: Process terminated!\n", ctx);
+				else
+					(*pfnCallback)("IfUpDown: Unexpected Error!\n", ctx);
+				exitcode = -1;
+				break;
+			}
+
+			while(poll(&pfd, 1, 100) > 0)
+			{
+				if(!(pfd.revents & POLLIN))
+					break;
+
+				if((nRead = read(fd, szBuf, sizeof(szBuf) - 1)) > 0)
+				{
+					szBuf[nRead] = '\0';
+					(*pfnCallback)(szBuf, ctx);
+				}
+
+				pfd.revents = 0;
+			}
+
+			if(ret == pid && bExited)
+			{
+				exitcode = WEXITSTATUS(stat);
+				break;
+			}
+		}
+	}
+	else
+	{
+		if((ret = waitpid(pid, &stat, 0)) != pid)
+		{
+			close(fd);
+			return -1;
+		}
+
+		bool bExited = WIFEXITED(stat);
+		exitcode = bExited ? WEXITSTATUS(stat) : -1;
+	}
+
+	close(fd);
+	return exitcode;
+}
+#else
+static int _IfPClose(pid_t pid, int fd, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctx)
+{
+	int stat, exitcode;
+	pid_t ret;
+
+	if((ret = waitpid(pid, &stat, 0)) != pid)
+	{
+		if(pfnCallback)
+			(*pfnCallback)("_IfPClose: Unexpected Error!", ctx);
+		close(fd);
+		return -1;
+	}
+
+	bool bExited = WIFEXITED(stat);
+	exitcode = bExited ? WEXITSTATUS(stat) : -1;
+
+	if(pfnCallback)
+	{
+		struct pollfd pfd;
+		pfd.fd = fd;
+		pfd.events = POLLIN;
+		pfd.revents = 0;
+		ssize_t nRead;
+		char szBuf[512];
+
+		while(poll(&pfd, 1, 100) > 0)
+		{
+			if(!(pfd.revents & POLLIN))
+				break;
+
+			if((nRead = read(fd, szBuf, sizeof(szBuf) - 1)) > 0)
+			{
+				szBuf[nRead] = '\0';
+				(*pfnCallback)(szBuf, ctx);
+			}
+
+			pfd.revents = 0;
+		}
+	}
+
+	close(fd);
+	return exitcode;
+}
+#endif
+
+int IfUp(const char *pszItfName, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctx)
+{
+	if(!pszItfName)
+		return -1;
+
+	char szBuf[256];
+	snprintf(szBuf, sizeof(szBuf) - 1, "/sbin/ifup %s 2>&1", pszItfName);
+	pid_t pid;
+	int fd;
+
+	if((fd = _IfPOpen(szBuf, pid, pfnCallback, ctx)))
+		return _IfPClose(pid, fd, pfnCallback, ctx);
+
+	if(pfnCallback)
+		(*pfnCallback)("ifup failed!", ctx);
+	return -1;
+}
+
+int IfDown(const char *pszItfName, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctx)
+{
+	if(!pszItfName)
+		return -1;
+
+	char szBuf[256];
+	snprintf(szBuf, sizeof(szBuf) - 1, "/sbin/ifdown %s 2>&1", pszItfName);
+	pid_t pid;
+	int fd;
+
+	if((fd = _IfPOpen(szBuf, pid, pfnCallback, ctx)))
+		return _IfPClose(pid, fd, pfnCallback, ctx);
+
+	if(pfnCallback)
+		(*pfnCallback)("ifdown failed!", ctx);
+	return -1;
+}
+
+static void * _IfUpDownAsyncProc(void *pParam)
+{
+	LPIF_UPDOWN_ASYNC_PARAMS piudap = (LPIF_UPDOWN_ASYNC_PARAMS)pParam;
+	int nRet = _IfPClose(piudap->pid, piudap->fd, piudap->pfnCallback, piudap->ctxOutput);
+	(*piudap->pfnComplete)(nRet, piudap->ctxComplete);
+	delete piudap;
+	return NULL;
+}
+
+int IfUpAsync(const char *pszItfName, pid_t &pid, PFN_IF_UPDOWN_COMPLETE pfnComplete, void *ctxComplete, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctxOutput)
+{
+	if(!pszItfName || !pfnComplete)
+		return -1;
+
+	char szBuf[256];
+	snprintf(szBuf, sizeof(szBuf) - 1, "/sbin/ifup %s 2>&1", pszItfName);
+	int fd;
+
+	if((fd = _IfPOpen(szBuf, pid, pfnCallback, ctxOutput)))
+	{
+		LPIF_UPDOWN_ASYNC_PARAMS piudap = new IF_UPDOWN_ASYNC_PARAMS;
+		piudap->fd			= fd;
+		piudap->pid			= pid;
+		piudap->pfnComplete	= pfnComplete;
+		piudap->ctxComplete	= ctxComplete;
+		piudap->pfnCallback	= pfnCallback;
+		piudap->ctxOutput	= ctxOutput;
+		pthread_t threadID;
+
+		return ::pthread_create(&threadID, NULL, &_IfUpDownAsyncProc, reinterpret_cast<void*>(piudap));
+	}
+
+	return -1;
+}
+
+int IfDownAsync(const char *pszItfName, pid_t &pid, PFN_IF_UPDOWN_COMPLETE pfnComplete, void *ctxComplete, PFN_IF_UPDOWN_OUTPUT pfnCallback, void *ctxOutput)
+{
+	if(!pszItfName || !pfnComplete)
+		return -1;
+
+	char szBuf[256];
+	snprintf(szBuf, sizeof(szBuf) - 1, "/sbin/ifdown %s 2>&1", pszItfName);
+	int fd;
+
+	if((fd = _IfPOpen(szBuf, pid, pfnCallback, ctxOutput)))
+	{
+		LPIF_UPDOWN_ASYNC_PARAMS piudap = new IF_UPDOWN_ASYNC_PARAMS;
+		piudap->fd			= fd;
+		piudap->pid			= pid;
+		piudap->pfnComplete	= pfnComplete;
+		piudap->ctxComplete	= ctxComplete;
+		piudap->pfnCallback	= pfnCallback;
+		piudap->ctxOutput	= ctxOutput;
+		pthread_t threadID;
+
+		return ::pthread_create(&threadID, NULL, &_IfUpDownAsyncProc, reinterpret_cast<void*>(piudap));
+	}
+
+	return -1;
+}

+ 27 - 4
libgfanet/interfaces.h

@@ -54,11 +54,14 @@ typedef enum CfgGroup
 	CG_AllowAuto,
 	CG_AllowHotplug,
 	CG_NoAutoDown,
-	DG_NoScripts,
+	CG_NoScripts,
 	CG_User
 }CfgGroup;
 
 CfgGroup ParseCfgGroup(const std::vector<std::string> &v, ITF_CONFIG_GROUP &icg);
+CfgGroup GetIfaceCfgGroup(const std::string &s);
+const char *GetIfaceCfgGroupStr(CfgGroup cg);
+typedef void (*PFN_ENUM_IFACE_CFG_GROUPS_CALLBACK)(CfgGroup, void*);
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -151,7 +154,6 @@ typedef struct _ITF_IFACE_BLOCK
 		inheritedFrom.clear();
 		desc.clear();
 		cmds.clear();
-		memberOf.clear();
 		unparsed.clear();
 		inet4s._reset();
 		inet4d._reset();
@@ -165,14 +167,12 @@ typedef struct _ITF_IFACE_BLOCK
 	std::string inheritedFrom;
 	std::string desc;
 	std::vector<IFACE_COMMAND> cmds;
-	std::vector<LPITF_CONFIG_GROUP> memberOf;
 	std::vector<std::string> unparsed;
 	IFACE_INET_STATIC inet4s;
 	IFACE_INET_DHCP inet4d;
 	IFACE_INET_MANUAL inet4m;
 }ITF_IFACE_BLOCK, *LPITF_IFACE_BLOCK;
 typedef const ITF_IFACE_BLOCK *LPCITF_IFACE_BLOCK;
-//typedef std::vector<ITF_IFACE_BLOCK> ITF_IFACE_BLOCK_LIST;
 typedef std::list<ITF_IFACE_BLOCK> ITF_IFACE_BLOCK_LIST;
 
 typedef enum IfaceHdrType
@@ -224,11 +224,34 @@ typedef struct _ETC_NETWORK_INTERFACES
 }ETC_NETWORK_INTERFACES, *LPETC_NETWORK_INTERFACES;
 typedef const ETC_NETWORK_INTERFACES *LPCETC_NETWORK_INTERFACES;
 
+typedef void (*PFN_IF_UPDOWN_COMPLETE)(int, void*);
+typedef void (*PFN_IF_UPDOWN_OUTPUT)(const char*, void*);
+
+typedef struct _IF_UPDOWN_ASYNC_PARAMS
+{
+	int fd;
+	pid_t pid;
+	PFN_IF_UPDOWN_COMPLETE pfnComplete;
+	void *ctxComplete;
+	PFN_IF_UPDOWN_OUTPUT pfnCallback;
+	void *ctxOutput;
+}IF_UPDOWN_ASYNC_PARAMS, *LPIF_UPDOWN_ASYNC_PARAMS;
+typedef const IF_UPDOWN_ASYNC_PARAMS *LPCIF_UPDOWN_ASYNC_PARAMS;
+
+LPITF_IFACE_BLOCK GetInterfaceBlockByID(ETC_NETWORK_INTERFACES &eni, unsigned long id);
 void ProcessIface(ETC_NETWORK_INTERFACES &eni);
 void ProcessGroupMembers(ETC_NETWORK_INTERFACES &eni);
 bool ParseEtcNetworkInterfaces(ETC_NETWORK_INTERFACES &eni, const char *pszPath = NULL);
 bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *pszPath = NULL);
 bool RemoveInterfaceBlock(ETC_NETWORK_INTERFACES &eni, unsigned long id);
+bool AddInterfaceToCfgGroup(ETC_NETWORK_INTERFACES &eni, unsigned long id, CfgGroup cg);
+bool RemoveInterfaceFromCfgGroup(ETC_NETWORK_INTERFACES &eni, unsigned long id, CfgGroup cg);
+CfgGroup EnumInterfaceCfgGroups(ETC_NETWORK_INTERFACES &eni, unsigned long id, PFN_ENUM_IFACE_CFG_GROUPS_CALLBACK pfnClb, void *pCtx);
+
+int IfUp(const char *pszItfName, PFN_IF_UPDOWN_OUTPUT pfnCallback = NULL, void *ctx = NULL);
+int IfDown(const char *pszItfName, PFN_IF_UPDOWN_OUTPUT pfnCallback = NULL, void *ctx = NULL);
+int IfUpAsync(const char *pszItfName, pid_t &pid, PFN_IF_UPDOWN_COMPLETE pfnComplete, void *ctxComplete = NULL, PFN_IF_UPDOWN_OUTPUT pfnCallback = NULL, void *ctxOutput = NULL);
+int IfDownAsync(const char *pszItfName, pid_t &pid, PFN_IF_UPDOWN_COMPLETE pfnComplete, void *ctxComplete = NULL, PFN_IF_UPDOWN_OUTPUT pfnCallback = NULL, void *ctxOutput = NULL);
 
 /////////////////////////////////////////////////////////////////////////////
 #endif	//	!defined(AGD_INTERFACES_H__0F16A7C6_9054_4BBB_8A10_EAE00ED4EE9C__INCLUDED_)

+ 0 - 0
libgfanet/gfanet.pro → libgfanet/libgfanet.pro


+ 0 - 0
qtplugin/.gitignore → libnetinterfaces/.gitignore


+ 3 - 3
qtplugin/netinterfaces.pro → libnetinterfaces/libnetinterfaces.pro

@@ -1,5 +1,5 @@
 TEMPLATE = lib
-TARGET = NetInterfaces
+TARGET = netinterfaces
 QT += sql qml
 CONFIG += qt plugin c++11
 
@@ -8,11 +8,11 @@ CONFIG(debug, debug|release) {
     QMAKE_CFLAGS -= -Os
     QMAKE_CXXFLAGS += -D_DEBUG
     QMAKE_CFLAGS += -D_DEBUG
-    QMAKE_LIBS += -lgfanetd
+    QMAKE_LIBS += -lgfanetd -lgfaipc
 }
 
 CONFIG(release, debug|release) {
-    QMAKE_LIBS += -lgfanet
+    QMAKE_LIBS += -lgfanet -lgfaipc
 }
 
 #TARGET = $$qtLibraryTarget($$TARGET)

+ 341 - 49
qtplugin/netinterfaces.cpp → libnetinterfaces/netinterfaces.cpp

@@ -1,3 +1,4 @@
+#include <signal.h>
 #include "netinterfaces.h"
 #include "../debug.h"
 
@@ -62,24 +63,28 @@ static bool _IsValidNetmask(const struct in_addr &in)
 
 /////////////////////////////////////////////////////////////////////////////
 
-NetInterfaces::NetInterfaces(QObject *pParent) : QObject(pParent)
+NetInterfaces::NetInterfaces(QObject *pParent) :	QObject(pParent),
+													m_itfFilterAF(Interface::AF_Unknown),
+													m_itfFilterMethod(Interface::IM_Unknown),
+													m_bIfUpDownInProgress(false),
+													m_ifUpDownPid(-1)
 {
 	setObjectName("NetInterfaces");
-	m_itfFilterAF		= Interface::AF_Unknown;
-	m_itfFilterMethod	= Interface::IM_Unknown;
+	m_mutex.Create(true);
 	m_itfFilterName.clear();
 }
 
 NetInterfaces::~NetInterfaces(void)
 {
 	reset();
+	m_mutex.Release();
 }
 
 void NetInterfaces::classBegin()
 {
 	if(!initialize())
 	{
-		emitError("NetInterfaces::initialize failed!");
+		reportError("NetInterfaces::initialize failed!");
 	}
 }
 
@@ -112,7 +117,7 @@ bool NetInterfaces::initialize(void)
 		for(auto it = m_eni.ibl.begin(); it != m_eni.ibl.end(); it++)
 		{
 			ITF_IFACE_BLOCK &ibl = *it;
-			m_interfaces.append(new Interface(ibl, static_cast<const NotificationSink&>(*this), this));
+			m_interfaces.append(new Interface(ibl, static_cast<NotificationSink&>(*this), this));
 		}
 
 		emit interfacesChanged();
@@ -136,13 +141,15 @@ bool NetInterfaces::saveAs(const QString &path)
 	return ::WriteEtcNetworkInterfaces(m_eni, pszPath);
 }
 
-void NetInterfaces::emitError(const char *pszFormatStr, ...) const
+void NetInterfaces::reportError(const char *pszFormatStr, ...)
 {
 	va_list args;
 	va_start(args, pszFormatStr);
 	QString qs = QString::vasprintf(pszFormatStr, args);
 	va_end (args);
+	m_mutex.Lock();
     emit error(qs);
+	m_mutex.Unlock();
 }
 
 void NetInterfaces::filterPropertyChanged(void) const
@@ -150,23 +157,40 @@ void NetInterfaces::filterPropertyChanged(void) const
 	emit filteredInterfacesChanged();
 }
 
+void NetInterfaces::selConfigChanged(Interface* pi, unsigned int cfgOld, unsigned int cfgNew)
+{
+	unsigned long id	= pi->getID();
+	unsigned int diff	= cfgOld ^ cfgNew;
+	unsigned int add	= cfgNew & diff;
+	unsigned int rem	= cfgOld & diff;
+
+	for(int mask = Interface::SC_Auto; mask < Interface::SC_Invalid; mask <<= 1)
+	{
+		if(add & mask)
+			::AddInterfaceToCfgGroup(m_eni, id, (CfgGroup)_FLAG_TO_ENUM(mask));
+
+		if(rem & mask)
+			::RemoveInterfaceFromCfgGroup(m_eni, id, (CfgGroup)_FLAG_TO_ENUM(mask));
+	}
+}
+
 Interface* NetInterfaces::newInterface(QString name, int af, int method)
 {
 	if(name.isNull() || name.isEmpty())
 	{
-		emitError("Invalid or empty interface name!");
+		reportError("Invalid or empty interface name!");
 		return NULL;
 	}
 
 	if(!_IsPowerOf2(af) || (af <= Interface::AF_Unknown) || (af >= Interface::AF_Invalid))
 	{
-		emitError("Invalid address family: %d!", af);
+		reportError("Invalid address family: %d!", af);
 		return NULL;
 	}
 
 	if(!_IsPowerOf2(method) || (method <= Interface::IM_Unknown) || (method >= Interface::IM_Invalid))
 	{
-		emitError("Invalid method: %d!", method);
+		reportError("Invalid method: %d!", method);
 		return NULL;
 	}
 
@@ -175,7 +199,7 @@ Interface* NetInterfaces::newInterface(QString name, int af, int method)
     rib.cfgName = name.toStdString();
 	rib.proto = (IfaceProtos)_FLAG_TO_ENUM(af);
 	rib.method = (IfaceMethods)_FLAG_TO_ENUM(method);
-	Interface *pi = new Interface(rib, static_cast<const NotificationSink&>(*this), this);
+	Interface *pi = new Interface(rib, static_cast<NotificationSink&>(*this), this);
 	m_interfaces.append(pi);
 	emit interfacesChanged();
 	emit filteredInterfacesChanged();
@@ -186,11 +210,21 @@ void NetInterfaces::removeInterface(Interface *pi)
 {
 	if(!pi)
 	{
-		emitError("%s: Attempt to remove invalid interface!", __FUNCTION__);
+		reportError("NetInterfaces::removeInterface: An attempt was made to remove an invalid interface!");
+		return;
+	}
+
+	m_mutex.Lock();
+	if(GetIfUpDownInProgress())
+	{
+		m_mutex.Unlock();
+		reportError("NetInterfaces::removeInterface: Interface start/stop in progress! Please try again later!");
 		return;
 	}
+	m_mutex.Unlock();
 
-    unsigned long id = pi->getID();
+    unsigned long id	= pi->getID();
+    int selCfg			= pi->getSelCfg();
 
     for(int i = 0; i < m_interfaces.count(); i++)
 	{
@@ -202,12 +236,227 @@ void NetInterfaces::removeInterface(Interface *pi)
 			emit interfacesChanged();
 			emit filteredInterfacesChanged();
 			delete pil;
+
+			for(int mask = Interface::SC_Auto; mask < Interface::SC_Invalid; mask <<= 1)
+			{
+				if(selCfg & mask)
+					::RemoveInterfaceFromCfgGroup(m_eni, id, (CfgGroup)_FLAG_TO_ENUM(mask));
+			}
+
 			::RemoveInterfaceBlock(m_eni, id);
 			break;
         }
     }
 }
 
+bool NetInterfaces::SetInterlockedIfUpDownInProgress(void)
+{
+	m_mutex.Lock();
+	if(m_bIfUpDownInProgress)
+	{
+		m_mutex.Unlock();
+		return false;
+	}
+	m_bIfUpDownInProgress = true;
+	m_mutex.Unlock();
+	return true;
+}
+
+void NetInterfaces::onIfUpDown(const char *pszMsg, void *pCtx)
+{
+	if(pCtx)
+	{
+		NetInterfaces *pThis = static_cast<NetInterfaces*>(pCtx);
+		pThis->m_mutex.Lock();
+		emit pThis->ifUpDown(pszMsg);
+		pThis->m_mutex.Unlock();
+	}
+}
+
+void NetInterfaces::onIfUpCompleted(int nExitCode, void *pCtx)
+{
+	if(pCtx)
+	{
+		LPIF_UPDOWN_CONTEXT piudc = static_cast<LPIF_UPDOWN_CONTEXT>(pCtx);
+		piudc->pThis->m_mutex.Lock();
+		emit piudc->pThis->ifUpDownCompleted(piudc->ctx, nExitCode);
+		piudc->pThis->SetIfUpDownInProgress(false);
+		piudc->pThis->SetIfUpDownPid(-1);
+		piudc->pThis->m_mutex.Unlock();
+		delete piudc;
+	}
+}
+
+void NetInterfaces::onIfDownCompleted(int nExitCode, void *pCtx)
+{
+	if(pCtx)
+	{
+		LPIF_UPDOWN_CONTEXT piudc = static_cast<LPIF_UPDOWN_CONTEXT>(pCtx);
+		piudc->pThis->m_mutex.Lock();
+		emit piudc->pThis->ifUpDownCompleted(piudc->ctx, nExitCode);
+		piudc->pThis->SetIfUpDownInProgress(false);
+		piudc->pThis->SetIfUpDownPid(-1);
+		piudc->pThis->m_mutex.Unlock();
+		delete piudc;
+	}
+}
+
+void NetInterfaces::onIfRestartCompleted(int nExitCode, void *pCtx)
+{
+	if(pCtx)
+	{
+		LPIF_UPDOWN_CONTEXT piudc = static_cast<LPIF_UPDOWN_CONTEXT>(pCtx);
+
+		if(piudc->ctx == UDC_Stop && !nExitCode) // ifdown succeeded
+		{
+			int nRet;
+			piudc->ctx = UDC_Start;
+
+			if((nRet = ::IfUpAsync(piudc->pi->getName(), piudc->pThis->m_ifUpDownPid, &NetInterfaces::onIfRestartCompleted, static_cast<void*>(piudc), &NetInterfaces::onIfUpDown, static_cast<void*>(piudc->pThis))))
+			{
+				piudc->pThis->m_mutex.Lock();
+				piudc->pThis->reportError("NetInterfaces::onIfRestartCompleted: IfUpAsync failed with code: %d", nRet);
+				emit piudc->pThis->ifUpDownCompleted(UDC_Restart, nRet);
+				piudc->pThis->SetIfUpDownPid(-1);
+				piudc->pThis->SetIfUpDownInProgress(false);
+				piudc->pThis->m_mutex.Unlock();
+				delete piudc;
+			}
+
+			return;
+		}
+
+		piudc->pThis->m_mutex.Lock();
+		emit piudc->pThis->ifUpDownCompleted(UDC_Restart, nExitCode);
+		piudc->pThis->SetIfUpDownPid(-1);
+		piudc->pThis->SetIfUpDownInProgress(false);
+		piudc->pThis->m_mutex.Unlock();
+		delete piudc;
+	}
+}
+
+bool NetInterfaces::startInterface(Interface *pi)
+{
+	if(!pi)
+	{
+		reportError("NetInterfaces::stopInterface: Invalid interface!");
+		return false;
+	}
+
+	int nRet;
+
+	if(!SetInterlockedIfUpDownInProgress())
+	{
+		reportError("NetInterfaces::startInterface: IfUp/Down already in progress!");
+		return false;
+	}
+
+	LPIF_UPDOWN_CONTEXT piudc = new IF_UPDOWN_CONTEXT;
+	piudc->pThis		= this;
+	piudc->pi			= pi;
+	piudc->ctx			= UDC_Start;
+
+	if((nRet = ::IfUpAsync(pi->getName(), m_ifUpDownPid, &NetInterfaces::onIfUpCompleted, static_cast<void*>(piudc), &NetInterfaces::onIfUpDown, static_cast<void*>(this))))
+	{
+		m_mutex.Lock();
+		reportError("NetInterfaces::startInterface: IfUpAsync failed with code: %d", nRet);
+		emit ifUpDownCompleted(UDC_Start, -3);
+		SetIfUpDownInProgress(false);
+		SetIfUpDownPid(-1);
+		m_mutex.Unlock();
+		delete piudc;
+		return false;
+	}
+
+	return true;
+}
+
+bool NetInterfaces::stopInterface(Interface *pi)
+{
+	if(!pi)
+	{
+		reportError("NetInterfaces::stopInterface: Invalid interface!");
+		return false;
+	}
+
+	int nRet;
+
+	if(!SetInterlockedIfUpDownInProgress())
+	{
+		reportError("NetInterfaces::stopInterface: IfUp/Down already in progress!");
+		return false;
+	}
+
+	LPIF_UPDOWN_CONTEXT piudc = new IF_UPDOWN_CONTEXT;
+	piudc->pThis		= this;
+	piudc->pi			= pi;
+	piudc->ctx			= UDC_Stop;
+
+	if((nRet = ::IfDownAsync(pi->getName(), m_ifUpDownPid, &NetInterfaces::onIfDownCompleted, static_cast<void*>(piudc), &NetInterfaces::onIfUpDown, static_cast<void*>(this))))
+	{
+		m_mutex.Lock();
+		reportError("NetInterfaces::stopInterface: IfDownAsync failed with code: %d", nRet);
+		emit ifUpDownCompleted(UDC_Stop, -3);
+		SetIfUpDownInProgress(false);
+		SetIfUpDownPid(-1);
+		m_mutex.Unlock();
+		delete piudc;
+		return false;
+	}
+
+	return true;
+}
+
+bool NetInterfaces::restartInterface(Interface *pi)
+{
+	if(!pi)
+	{
+		reportError("NetInterfaces::restartInterface: Invalid interface!");
+		return false;
+	}
+
+	int nRet;
+
+	if(!SetInterlockedIfUpDownInProgress())
+	{
+		reportError("NetInterfaces::restartInterface: IfUp/Down already in progress!");
+		return false;
+	}
+
+	LPIF_UPDOWN_CONTEXT piudc = new IF_UPDOWN_CONTEXT;
+	piudc->pThis		= this;
+	piudc->pi			= pi;
+	piudc->ctx			= UDC_Stop;
+
+	if((nRet = ::IfDownAsync(pi->getName(), m_ifUpDownPid, &NetInterfaces::onIfRestartCompleted, static_cast<void*>(piudc), &NetInterfaces::onIfUpDown, static_cast<void*>(this))))
+	{
+		m_mutex.Lock();
+		reportError("NetInterfaces::restartInterface: IfDownAsync failed with code: %d", nRet);
+		emit ifUpDownCompleted(UDC_Restart, -3);
+		SetIfUpDownInProgress(false);
+		SetIfUpDownPid(-1);
+		m_mutex.Unlock();
+		delete piudc;
+		return false;
+	}
+
+	return true;
+}
+
+bool NetInterfaces::cancelStartStopInterface(void)
+{
+	m_mutex.Lock();
+	pid_t pid = GetIfUpDownPid();
+	bool bCancel = GetIfUpDownInProgress() && (pid != -1);
+	if(bCancel)
+	{
+//		bCancel = !kill(-pid, SIGKILL);
+		bCancel = !system("killall -SIGTERM ifup");
+	}
+	m_mutex.Unlock();
+	return bCancel;
+}
+
 QQmlListProperty<Interface> NetInterfaces::interfaces(void)
 {
 	return QQmlListProperty<Interface>(this, m_interfaces);
@@ -260,7 +509,7 @@ void NetInterfaces::setItfFilterAF(int af)
 
 	if(af < Interface::AF_Unknown || af >= Interface::AF_Invalid)
 	{
-		emitError("Invalid address family filter: %d!", af);
+		reportError("Invalid address family filter: %d!", af);
 		return;
 	}
 
@@ -279,11 +528,9 @@ int NetInterfaces::itfFilterMethod(void) const
 
 void NetInterfaces::setItfFilterMethod(int method)
 {
-
-
 	if(method < Interface::IM_Unknown || method >= Interface::IM_Invalid)
 	{
-		emitError("Invalid method filter: %d!", method);
+		reportError("Invalid method filter: %d!", method);
 		return;
 	}
 
@@ -295,12 +542,35 @@ void NetInterfaces::setItfFilterMethod(int method)
 	}
 }
 
+int NetInterfaces::getInterfaceSelConfig(Interface &ri)
+{
+	int mask = 0;
+
+	::EnumInterfaceCfgGroups(m_eni, ri.getID(),
+		[] (CfgGroup cg, void *pCtx) -> void
+		{
+			if(cg > CG_Unknown)
+			{
+				int *m = (int*)pCtx;
+				*m |= _ENUM_TO_FLAG(cg);
+			}
+		}, &mask);
+
+	return mask;
+}
+
+bool NetInterfaces::ifUpDownInProgress(void) const
+{
+	return m_bIfUpDownInProgress;
+}
+
 /////////////////////////////////////////////////////////////////////////////
 
-Interface::Interface(ITF_IFACE_BLOCK &ifb, const NotificationSink &notifyer, QObject *pParent) : 	QObject(pParent),
-																									m_ifb(ifb),
-																									m_inet(ifb, notifyer, this),
-																									m_rNotifyer(notifyer)
+Interface::Interface(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent) : 	QObject(pParent),
+																							m_ifb(ifb),
+																							m_inet(ifb, notifyer, this),
+																							m_rNotifyer(notifyer),
+																							m_selCfg(notifyer.getInterfaceSelConfig(*this))
 {
 	setObjectName("Interface");
 }
@@ -328,7 +598,7 @@ void Interface::setAf(int af)
 {
 	if(!_IsPowerOf2(af) || (af < Interface::AF_Unknown) || (af >= Interface::AF_Invalid))
 	{
-		m_rNotifyer.emitError("Invalid address family: %d!", af);
+		m_rNotifyer.reportError("Invalid address family: %d!", af);
 		return;
 	}
 
@@ -357,7 +627,7 @@ void Interface::setMethod(int method)
 {
 	if(!_IsPowerOf2(method) || (method < Interface::IM_Unknown) || (method >= Interface::IM_Invalid))
 	{
-		m_rNotifyer.emitError("Invalid interface method: %d!", method);
+		m_rNotifyer.reportError("Invalid interface method: %d!", method);
 		return;
 	}
 
@@ -372,6 +642,28 @@ void Interface::setMethod(int method)
 	}
 }
 
+int Interface::selCfg(void) const
+{
+	return m_selCfg;
+}
+
+void Interface::setSelCfg(int cfg)
+{
+	if(cfg < SC_None || cfg >= SC_Invalid)
+	{
+		m_rNotifyer.reportError("Invalid start/selection configuration: 0x%X!", cfg);
+		return;
+	}
+
+	if(m_selCfg != cfg)
+	{
+		m_rNotifyer.selConfigChanged(this, m_selCfg, cfg);
+		m_selCfg = cfg;
+		emit selCfgChanged(cfg);
+	}
+
+}
+
 Inet* Interface::inet(void)
 {
 	return &m_inet;
@@ -379,10 +671,10 @@ Inet* Interface::inet(void)
 
 /////////////////////////////////////////////////////////////////////////////
 
-Inet::Inet(ITF_IFACE_BLOCK &ifb, const NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
-																						m_static(ifb.inet4s, notifyer, this),
-																						m_dhcp(ifb.inet4d, notifyer, this),
-																						m_rNotifyer(notifyer)
+Inet::Inet(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
+																					m_static(ifb.inet4s, notifyer, this),
+																					m_dhcp(ifb.inet4d, notifyer, this),
+																					m_rNotifyer(notifyer)
 {
 	setObjectName("Inet");
 }
@@ -403,14 +695,14 @@ Dhcp* Inet::dhcp(void)
 
 /////////////////////////////////////////////////////////////////////////////
 
-Static::Static(IFACE_INET_STATIC &itfs, const NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
-																								m_itfs(itfs),
-																								m_rNotifyer(notifyer),
-																								m_ipAddr(itfs.addr, notifyer, this),
-																								m_netmask(itfs.netmask, notifyer, this, _IsValidNetmask),
-																								m_gateway(itfs.gate, notifyer, this),
-																								m_bcastAddr(itfs.bcast, notifyer, this),
-																								m_ptpAddr(itfs.pointopoint, notifyer, this)
+Static::Static(IFACE_INET_STATIC &itfs, NotificationSink &notifyer, QObject *pParent) :	QObject(pParent),
+																						m_itfs(itfs),
+																						m_rNotifyer(notifyer),
+																						m_ipAddr(itfs.addr, notifyer, this),
+																						m_netmask(itfs.netmask, notifyer, this, _IsValidNetmask),
+																						m_gateway(itfs.gate, notifyer, this),
+																						m_bcastAddr(itfs.bcast, notifyer, this),
+																						m_ptpAddr(itfs.pointopoint, notifyer, this)
 {
 	setObjectName("Static");
 	for(size_t i = 0; i < _countof(m_itfs.namesvr); i++)
@@ -418,7 +710,7 @@ Static::Static(IFACE_INET_STATIC &itfs, const NotificationSink &notifyer, QObjec
 		IPv4Address *addr = new IPv4Address(m_itfs.namesvr[i], notifyer, this);
 		m_dnsList.append(addr);
 	}
-	
+
 	QObject::connect(&m_netmask, SIGNAL(addressChanged(const QString&)), this, SLOT(netmaskChanged(const QString&)));
 }
 
@@ -500,7 +792,7 @@ void Static::setNetPrefix(int netprefix)
 {
 	if(netprefix < 0 || netprefix > 32)
 	{
-		m_rNotifyer.emitError("Invalid net prefix: %d!", netprefix);
+		m_rNotifyer.reportError("Invalid net prefix: %d!", netprefix);
 		return;
 	}
 
@@ -525,14 +817,14 @@ void Static::netmaskChanged(const QString &mask)
 	}
 	else
 	{
-		m_rNotifyer.emitError("Invalid net mask: %s!", sa.c_str());
+		m_rNotifyer.reportError("Invalid net mask: %s!", sa.c_str());
         m_netmask.setProperty("address", QVariant("255.255.255.0"));
 	}
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-Dhcp::Dhcp(IFACE_INET_DHCP &itfd, const NotificationSink &notifyer, QObject *pParent) : QObject(pParent), m_itfd(itfd), m_rNotifyer(notifyer)
+Dhcp::Dhcp(IFACE_INET_DHCP &itfd, NotificationSink &notifyer, QObject *pParent) : QObject(pParent), m_itfd(itfd), m_rNotifyer(notifyer)
 {
 	setObjectName("Dhcp");
 }
@@ -543,10 +835,10 @@ Dhcp::~Dhcp(void)
 
 /////////////////////////////////////////////////////////////////////////////
 
-IPv4Address::IPv4Address(struct in_addr &addr, const NotificationSink &notifyer, QObject *pParent, PFN_ADDRESS_VALIDATOR pfnAddrValidator) :	QObject(pParent),
-																																				m_addr(addr),
-																																				m_pfnAddrValidator(pfnAddrValidator),
-																																				m_rNotifyer(notifyer)
+IPv4Address::IPv4Address(struct in_addr &addr, NotificationSink &notifyer, QObject *pParent, PFN_ADDRESS_VALIDATOR pfnAddrValidator) :	QObject(pParent),
+																																		m_addr(addr),
+																																		m_pfnAddrValidator(pfnAddrValidator),
+																																		m_rNotifyer(notifyer)
 {
 	setObjectName("IPv4Address");
 }
@@ -591,13 +883,13 @@ void IPv4Address::setAddress(const QString &addr)
 
 	if(!inet_aton(sa.c_str(), &newAddr))
 	{
-		m_rNotifyer.emitError("Invalid IP address: '%s'!", sa.c_str());
+		m_rNotifyer.reportError("Invalid IP address: '%s'!", sa.c_str());
 		return;
 	}
-	
+
 	if(m_pfnAddrValidator && !(*m_pfnAddrValidator)(newAddr))
 	{
-		m_rNotifyer.emitError("Invalid address: '%s'!", sa.c_str());
+		m_rNotifyer.reportError("Invalid address: '%s'!", sa.c_str());
 		return;
 	}
 
@@ -625,7 +917,7 @@ void IPv4Address::setB0(int b)
 	unsigned char *pb = (unsigned char*)&m_addr.s_addr;
 	if(!_IS_VALID_BYTE_VALUE(b))
 	{
-		m_rNotifyer.emitError("Invalid IP address byte 0: '%d'!", b);
+		m_rNotifyer.reportError("Invalid IP address byte 0: '%d'!", b);
 		return;
 	}
 	if(b == (int)pb[0])
@@ -640,7 +932,7 @@ void IPv4Address::setB1(int b)
 	unsigned char *pb = (unsigned char*)&m_addr.s_addr;
 	if(!_IS_VALID_BYTE_VALUE(b))
 	{
-		m_rNotifyer.emitError("Invalid IP address byte 1: '%d'!", b);
+		m_rNotifyer.reportError("Invalid IP address byte 1: '%d'!", b);
 		return;
 	}
 	if(b == (int)pb[1])
@@ -655,7 +947,7 @@ void IPv4Address::setB2(int b)
 	unsigned char *pb = (unsigned char*)&m_addr.s_addr;
 	if(!_IS_VALID_BYTE_VALUE(b))
 	{
-		m_rNotifyer.emitError("Invalid IP address byte 2: '%d'!", b);
+		m_rNotifyer.reportError("Invalid IP address byte 2: '%d'!", b);
 		return;
 	}
 	if(b == (int)pb[2])
@@ -670,7 +962,7 @@ void IPv4Address::setB3(int b)
 	unsigned char *pb = (unsigned char*)&m_addr.s_addr;
 	if(!_IS_VALID_BYTE_VALUE(b))
 	{
-		m_rNotifyer.emitError("Invalid IP address byte 3: '%d'!", b);
+		m_rNotifyer.reportError("Invalid IP address byte 3: '%d'!", b);
 		return;
 	}
 	if(b == (int)pb[3])

+ 94 - 13
qtplugin/netinterfaces.h → libnetinterfaces/netinterfaces.h

@@ -9,16 +9,21 @@
 #include <QList>
 #include <QQmlListProperty>
 #include <qqmlparserstatus.h>
+#include "../../gfaipc/src/mutex.h"
 #include <gfa/gfanet.h>
 
 /////////////////////////////////////////////////////////////////////////////
 // netinterfaces.h - Declarations:
 
+class Interface;
+
 class NotificationSink
 {
 public:
-	virtual void emitError(const char *pszFormatStr, ...) const	= 0;
-	virtual void filterPropertyChanged(void) const				= 0;
+	virtual void reportError(const char *pszFormatStr, ...)									= 0;
+	virtual void filterPropertyChanged(void) const											= 0;
+	virtual void selConfigChanged(Interface* pi, unsigned int cfgOld, unsigned int cfgNew)	= 0;
+	virtual int getInterfaceSelConfig(Interface &ri)										= 0;
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -36,7 +41,7 @@ class IPv4Address : public QObject
 
 
 public:
-    explicit IPv4Address(struct in_addr &addr, const NotificationSink &notifyer, QObject *pParent = 0, PFN_ADDRESS_VALIDATOR pfnAddrValidator = NULL);
+    explicit IPv4Address(struct in_addr &addr, NotificationSink &notifyer, QObject *pParent = 0, PFN_ADDRESS_VALIDATOR pfnAddrValidator = NULL);
     virtual ~IPv4Address(void);
 
 private:
@@ -62,7 +67,7 @@ signals:
 private:
 	struct in_addr &m_addr;
 	PFN_ADDRESS_VALIDATOR m_pfnAddrValidator;
-	const NotificationSink &m_rNotifyer;
+	NotificationSink &m_rNotifyer;
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -81,7 +86,7 @@ class Static : public QObject
     Q_PROPERTY(int netPrefix READ netPrefix WRITE setNetPrefix NOTIFY netPrefixChanged)
 
 public:
-    explicit Static(IFACE_INET_STATIC &itfs, const NotificationSink &notifyer, QObject *pParent = 0);
+    explicit Static(IFACE_INET_STATIC &itfs, NotificationSink &notifyer, QObject *pParent = 0);
     virtual ~Static(void);
 
 private:
@@ -108,7 +113,7 @@ signals:
 
 private:
 	IFACE_INET_STATIC &m_itfs;
-	const NotificationSink &m_rNotifyer;
+	NotificationSink &m_rNotifyer;
 	IPv4Address m_ipAddr;
 	IPv4Address m_netmask;
 	IPv4Address m_gateway;
@@ -124,12 +129,12 @@ class Dhcp : public QObject
     Q_OBJECT
 
 public:
-    explicit Dhcp(IFACE_INET_DHCP &itfd, const NotificationSink &notifyer, QObject *pParent = 0);
+    explicit Dhcp(IFACE_INET_DHCP &itfd, NotificationSink &notifyer, QObject *pParent = 0);
     virtual ~Dhcp(void);
 
 private:
 	IFACE_INET_DHCP &m_itfd;
-	const NotificationSink &m_rNotifyer;
+	NotificationSink &m_rNotifyer;
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -141,7 +146,7 @@ class Inet : public QObject
     Q_PROPERTY(Dhcp* dhcp READ dhcp CONSTANT)
 
 public:
-    explicit Inet(ITF_IFACE_BLOCK &ifb, const NotificationSink &notifyer, QObject *pParent = 0);
+    explicit Inet(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent = 0);
     virtual ~Inet(void);
 
 private:
@@ -151,7 +156,7 @@ private:
 private:
     Static m_static;
     Dhcp m_dhcp;
-	const NotificationSink &m_rNotifyer;
+	NotificationSink &m_rNotifyer;
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -164,17 +169,27 @@ class Interface : public QObject
     Q_PROPERTY(int af READ af WRITE setAf NOTIFY afChanged)
     Q_PROPERTY(QString methodName READ methodName NOTIFY methodNameChanged)
     Q_PROPERTY(int method READ method WRITE setMethod NOTIFY methodChanged)
+    Q_PROPERTY(int selCfg READ selCfg WRITE setSelCfg NOTIFY selCfgChanged)
     Q_PROPERTY(Inet* inet READ inet CONSTANT)
 
 public:
-    explicit Interface(ITF_IFACE_BLOCK &ifb, const NotificationSink &notifyer, QObject *pParent = 0);
+    explicit Interface(ITF_IFACE_BLOCK &ifb, NotificationSink &notifyer, QObject *pParent = 0);
     virtual ~Interface(void);
 
     inline const ITF_IFACE_BLOCK & getIface(void) const {
     	return m_ifb;}
+
+    inline ITF_IFACE_BLOCK & getIface(void){
+    	return m_ifb;}
     
     inline unsigned long getID(void) const {
     	return m_ifb.id;}
+    
+    inline int getSelCfg(void) const {
+	    return m_selCfg;}
+    
+    inline const char * getName(void) const {
+	    return m_ifb.cfgName.c_str();}
 
 	enum AddressFamily
 	{
@@ -204,6 +219,18 @@ public:
 	};
 	Q_ENUMS(ItfMethod)
 
+	enum SelConfig
+	{
+		SC_None			= 0,
+		SC_Auto			= 0x0001,
+		SC_AllowAuto	= 0x0002,
+		SC_AllowHotplug	= 0x0004,
+		SC_NoAutoDown	= 0x0008,
+		SC_NoScripts	= 0x0010,
+		SC_Invalid		= 0x0020
+	};
+	Q_ENUMS(SelConfig)
+
 private:
     QString name(void) const;
     QString afName(void) const;
@@ -212,6 +239,8 @@ private:
     QString methodName(void) const;
     int method(void) const;
     void setMethod(int method);
+    int selCfg(void) const;
+    void setSelCfg(int cfg);
     Inet* inet(void);
 
 signals:
@@ -219,15 +248,27 @@ signals:
 	void afChanged(int af);
 	void methodNameChanged(void);
 	void methodChanged(int method);
+	void selCfgChanged(int cfg);
 
 private:
 	ITF_IFACE_BLOCK &m_ifb;
 	Inet m_inet;
-	const NotificationSink &m_rNotifyer;
+	NotificationSink &m_rNotifyer;
+	int m_selCfg;
 };
 
 /////////////////////////////////////////////////////////////////////////////
 
+class NetInterfaces;
+
+typedef struct _IF_UPDOWN_CONTEXT
+{
+	NetInterfaces *pThis;
+	Interface *pi;
+	int ctx;
+}IF_UPDOWN_CONTEXT, *LPIF_UPDOWN_CONTEXT;
+typedef const IF_UPDOWN_CONTEXT *LPCIF_UPDOWN_CONTEXT;
+
 class NetInterfaces : public QObject, public QQmlParserStatus, public NotificationSink
 {
     Q_OBJECT
@@ -237,11 +278,20 @@ class NetInterfaces : public QObject, public QQmlParserStatus, public Notificati
     Q_PROPERTY(QString itfFilterName READ itfFilterName WRITE setItfFilterName NOTIFY itfFilterNameChanged)
     Q_PROPERTY(int itfFilterAF READ itfFilterAF WRITE setItfFilterAF NOTIFY itfFilterAFChanged)
     Q_PROPERTY(int itfFilterMethod READ itfFilterMethod WRITE setItfFilterMethod NOTIFY itfFilterMethodChanged)
+    Q_PROPERTY(bool ifUpDownInProgress READ ifUpDownInProgress CONSTANT)
 
 public:
     explicit NetInterfaces(QObject *pParent = 0);
     virtual ~NetInterfaces(void);
 
+	enum IfUpDownCtx
+	{
+		UDC_Start,
+		UDC_Stop,
+		UDC_Restart
+	};
+	Q_ENUMS(IfUpDownCtx)
+
 public:
 	Q_INVOKABLE void reset(void);
 	Q_INVOKABLE bool initialize(void);
@@ -249,11 +299,31 @@ public:
 	Q_INVOKABLE bool saveAs(const QString &path);
 	Q_INVOKABLE Interface* newInterface(QString name, int af, int method);
 	Q_INVOKABLE void removeInterface(Interface *pi);
+	Q_INVOKABLE bool startInterface(Interface *pi);
+	Q_INVOKABLE bool stopInterface(Interface *pi);
+	Q_INVOKABLE bool restartInterface(Interface *pi);
+	Q_INVOKABLE bool cancelStartStopInterface(void);
 
 	virtual void classBegin();
 	virtual void componentComplete();
-	virtual void emitError(const char *pszFormatStr, ...) const;
+	virtual void reportError(const char *pszFormatStr, ...);
 	virtual void filterPropertyChanged(void) const;
+	virtual void selConfigChanged(Interface* pi, unsigned int cfgOld, unsigned int cfgNew);
+	virtual int getInterfaceSelConfig(Interface &ri);
+	
+	inline pid_t GetIfUpDownPid(void) const {
+		return m_ifUpDownPid;}
+	
+	inline void SetIfUpDownPid(pid_t pid){
+		m_ifUpDownPid = pid;}
+	    
+	inline bool GetIfUpDownInProgress(void) const {
+		return m_bIfUpDownInProgress;}
+	    
+	inline void SetIfUpDownInProgress(bool bVal){
+		m_bIfUpDownInProgress = bVal;}
+	
+	bool SetInterlockedIfUpDownInProgress(void);
 
 signals:
 	void interfacesChanged(void) const;
@@ -262,6 +332,8 @@ signals:
 	void itfFilterAFChanged(int af) const;
 	void itfFilterMethodChanged(int method) const;
 	void error(QString msg) const;
+	void ifUpDown(QString msg) const;
+	void ifUpDownCompleted(int ctx, int code) const;
 
 private:
 	QQmlListProperty<Interface> interfaces(void);
@@ -272,6 +344,12 @@ private:
 	void setItfFilterAF(int nval);
 	int itfFilterMethod(void) const;
 	void setItfFilterMethod(int method);
+	bool ifUpDownInProgress(void) const;
+
+    static void onIfUpDown(const char *pszMsg, void *pCtx);
+    static void onIfUpCompleted(int nExitCode, void *pCtx);
+    static void onIfDownCompleted(int nExitCode, void *pCtx);
+    static void onIfRestartCompleted(int nExitCode, void *pCtx);
 
 private:
 	ETC_NETWORK_INTERFACES m_eni;
@@ -280,6 +358,9 @@ private:
 	QString m_itfFilterName;
 	int m_itfFilterAF;
 	int m_itfFilterMethod;
+	bool m_bIfUpDownInProgress;
+	pid_t m_ifUpDownPid;
+	CLocalMutex m_mutex;
 };
 
 /////////////////////////////////////////////////////////////////////////////

+ 0 - 0
qtplugin/netinterfaces_plugin.cpp → libnetinterfaces/netinterfaces_plugin.cpp


+ 0 - 0
qtplugin/netinterfaces_plugin.h → libnetinterfaces/netinterfaces_plugin.h


+ 0 - 0
qtplugin/pdump.sh → libnetinterfaces/pdump.sh


+ 1 - 1
qtplugin/qmldir → libnetinterfaces/qmldir

@@ -1,4 +1,4 @@
 module gfa.plugins.qml.net
-plugin NetInterfaces
+plugin netinterfaces
 classname NetInterfaces
 typeinfo net.qmltypes