From 427ab39aa51a21e3e0443a2b02c19929c9e2f60b Mon Sep 17 00:00:00 2001
From: Edileuton Henrique de Oliveira <eho09@c3sl.ufpr.br>
Date: Thu, 27 Feb 2014 10:17:23 -0300
Subject: [PATCH] Add net usage monitor to the Windows agent

Signed-off-by: Edileuton Henrique de Oliveira <eho09@c3sl.ufpr.br>
---
 windows-collect/Makefile                    |   5 +-
 windows-collect/src/collect.py              |  61 ++++++++---
 windows-collect/src/netmon/compileNetmon.py |   5 +
 windows-collect/src/netmon/netmon.py        | 109 ++++++++++++++++++++
 windows-collect/src/proinfodataAgent.py     |  46 +++++++--
 windows-installer/src/installer.nsi         |  16 +++
 6 files changed, 220 insertions(+), 22 deletions(-)
 create mode 100644 windows-collect/src/netmon/compileNetmon.py
 create mode 100644 windows-collect/src/netmon/netmon.py

diff --git a/windows-collect/Makefile b/windows-collect/Makefile
index a47b11a..abc2705 100644
--- a/windows-collect/Makefile
+++ b/windows-collect/Makefile
@@ -1,2 +1,5 @@
-all: src/compile.py src/proinfodataAgent.py src/collect.py
+all: netmon.py  src/compile.py src/proinfodataAgent.py src/collect.py
 	@cd src/ && wine ~/.wine/drive_c/Python27/python compile.py py2exe
+
+netmon.py:
+	@cd src/netmon && wine ~/.wine/drive_c/Python27/python compileNetmon.py py2exe
\ No newline at end of file
diff --git a/windows-collect/src/collect.py b/windows-collect/src/collect.py
index 5de4b19..33b2211 100644
--- a/windows-collect/src/collect.py
+++ b/windows-collect/src/collect.py
@@ -25,7 +25,12 @@ import ctypes
 import wmi
 import socket
 import struct
+import glob
 from xml.etree.ElementTree import Element, SubElement, Comment, tostring
+from datetime import timedelta, date, datetime  
+
+PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData"
+PREVIOUSPATH = PROINFODATAPATH  + "\\data\\previous"
 
 # Return the value from key/subkey in windows registry
 def getRegistryValue(key, subkey, value):
@@ -226,17 +231,47 @@ def netCollect():
     tagUse = SubElement(mainTag, 'use')
     tagUseBandUsage = SubElement(tagUse, 'bandwidth-usage', {'type':'tree'})
     
-    for i in range(1, 289):
-        tagNetUse = SubElement(tagUseBandUsage, 'netuse', {'id':str(i)})
-        tagDate = SubElement(tagNetUse, 'date', {'value':'0001-01-01', 'type':'string'})
-        tagTime = SubElement(tagNetUse, 'time', {'value':'0:0', 'type':'string'})
-        
-        tagRx = SubElement(tagNetUse, 'rx')
-        tagPackets = SubElement(tagRx, 'packets', {'value':"0", 'type':'int'})
-        tagBytes = SubElement(tagRx, 'bytes', {'value':"0", 'type':'int'})
-        
-        tagTx = SubElement(tagNetUse, 'tx')
-        tagPackets = SubElement(tagTx, 'packets', {'value':"0", 'type':'int'})
-        tagBytes = SubElement(tagTx, 'bytes', {'value':"0", 'type':'int'})
-        	
+    # Collect network usage
+    for t in glob.glob(PREVIOUSPATH + "\\*"):
+        traffic = file(t, "r")
+        trafficDate = traffic.readline().split("\n")[0]
+        dateTmp = datetime.strptime(trafficDate, '%Y-%m-%d')
+        intervalIdOld, rxPackageOld, rxBytesOld, txPackageOld, txBytesOld = traffic.readline().split("\n")[0].split(" ")
+        if dateTmp >= datetime.now() - timedelta(days=15):
+            for line in traffic:
+
+                intervalId, rxPackageAux, rxBytesAux, txPackageAux, txBytesAux = line.split(" ")
+                txBytesAux = txBytesAux.split("\n")[0]
+                rxPackage = int(rxPackageAux) - int(rxPackageOld)
+                rxBytes = int(rxBytesAux) - int(rxBytesOld)
+                txPackage = int(txPackageAux) - int(txPackageOld)
+                txBytes = int(txBytesAux) - int(txBytesOld)
+
+                if rxBytes >= 0 and txBytes >= 0:
+                    # Since we want the mean time between the five minutes intervals,
+                    # the minute counter starts at 2 and gets 5 minutes increments.
+                    # Also the "seconds counter" is fixed at 30. So we always get
+                    # something like HH:2:30 or HH:7:30 (mean times).
+                    #
+                    # Example: if interval = 10:15~10:20  =>  mean = 10:17:30
+                    intervalId = int(intervalId) + 1
+                    trafficTime = timedelta(minutes=intervalId * 5 - 3) + timedelta(seconds=30)
+                    
+                    tagNetUse = SubElement(tagUseBandUsage, 'netuse', {'id':str(intervalId)})
+                    tagDate = SubElement(tagNetUse, 'date', {'value':trafficDate, 'type':'string'})
+                    tagTime = SubElement(tagNetUse, 'time', {'value':str(trafficTime), 'type':'string'})
+                    
+                    tagRx = SubElement(tagNetUse, 'rx')
+                    tagPackets = SubElement(tagRx, 'packets', {'value':str(rxPackage), 'type':'int'})
+                    tagBytes = SubElement(tagRx, 'bytes', {'value':str(rxBytes), 'type':'int'})
+                    
+                    tagTx = SubElement(tagNetUse, 'tx')
+                    tagPackets = SubElement(tagTx, 'packets', {'value':str(txPackage), 'type':'int'})
+                    tagBytes = SubElement(tagTx, 'bytes', {'value':str(txBytes), 'type':'int'})
+            
+                intervalIdOld, rxPackageOld, rxBytesOld, txPackageOld, txBytesOld = intervalId, rxPackageAux, rxBytesAux, txPackageAux, txBytesAux
+            traffic.close()
+        else:
+            traffic.close()
+            os.remove(t)
     return mainTag
diff --git a/windows-collect/src/netmon/compileNetmon.py b/windows-collect/src/netmon/compileNetmon.py
new file mode 100644
index 0000000..f556790
--- /dev/null
+++ b/windows-collect/src/netmon/compileNetmon.py
@@ -0,0 +1,5 @@
+#coding: utf-8
+from distutils.core import setup
+import py2exe
+
+setup(console=['netmon.py'], options={"py2exe":{"dll_excludes":[ "mswsock.dll", "powrprof.dll" ]}})
diff --git a/windows-collect/src/netmon/netmon.py b/windows-collect/src/netmon/netmon.py
new file mode 100644
index 0000000..66f1ca0
--- /dev/null
+++ b/windows-collect/src/netmon/netmon.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2013 Centro de Computacao Cientifica e Software Livre
+# Departamento de Informatica - Universidade Federal do Parana - C3SL/UFPR
+#
+# This file is part of datasid
+#
+# windows-coleta is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+#coding: utf-8
+import os
+import sys
+import shutil
+import subprocess
+import re
+from datetime import date, timedelta, datetime
+
+PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData"
+PREVIOUSPATH = PROINFODATAPATH  + "\\data\\previous"
+TRAFFICPATH = PROINFODATAPATH  + "\\data\\traffic.txt"
+
+# Get the network traffic from the current day
+def getTraffic():
+	# Uses netstat command to get the net usage
+	res = subprocess.Popen(["netstat", "-e"], shell=True, stdout=subprocess.PIPE).communicate()[0]
+	bytesLine = res.splitlines()[4]
+	unicastPackagesLine = res.splitlines()[5]
+	packagesLine = res.splitlines()[6]
+
+	# Get the amount of bytes received and transmited   
+	rxBytes = re.split(" +", bytesLine)[-2]
+	txBytes = re.split(" +", bytesLine)[-1]
+
+	# Get the amount of packages received and transmited   
+	rxPackages = int(re.split(" +", unicastPackagesLine)[-2]) + int(re.split(" +", packagesLine)[-2])
+	txPackages = int(re.split(" +", unicastPackagesLine)[-1]) + int(re.split(" +", packagesLine)[-1])
+
+	return rxBytes, str(rxPackages), txBytes, str(txPackages)
+
+# Get a number identifying the current five minutes interval
+def getIntervalId( ):
+	# Get a number identifying the current five minutes interval
+	intervalId = int(datetime.now().strftime("%H")) * 12 + (int(datetime.now().strftime("%M")) / 5 + 0.5) - 1
+	# INTERVALID equal to -1 means midnight 00:00, but midnight needs
+	# to be the last id possible, so force it to 287
+	if intervalId == -1:
+		intervalId = 287
+    
+	return int(intervalId)
+    
+# Get the traffic file
+def getTrafficFile(currentDate): 
+	trafficDate = ""
+
+	# If there is no TRAFFIC (probably its the first run), then just create a
+	# new one.
+	try:
+		trafficFile = file(TRAFFICPATH, "r+")
+		trafficDate = trafficFile.readline()
+		trafficFile.seek(0, os.SEEK_END)
+	except IOError:
+		trafficFile = file(TRAFFICPATH, "w+")
+		trafficFile.write(currentDate + "\n")
+		return trafficFile
+
+	# Finally, create a new TRAFFIC (keeping the previous one as
+	# PREVIOUS_TRAFFIC) if the dates doesnt match.
+	if trafficDate.find(currentDate) == -1:
+		if not os.path.exists(PREVIOUSPATH): 
+			os.makedirs(PREVIOUSPATH)
+		trafficFile.close()     
+		shutil.copy2(TRAFFICPATH, PREVIOUSPATH + "\\traffic-" + currentDate + ".txt")
+		trafficFile = file(TRAFFICPATH, "w+")
+		trafficFile.write(currentDate + "\n")
+
+	return trafficFile
+
+# ==========================================
+#       Main program
+# ==========================================
+
+try:
+	rxBytes, rxPackages, txBytes, txPackages = getTraffic()
+	intervalId = getIntervalId()
+
+	# If it midnight (INTERVALID = 287), then consider current date as
+	# yesterday (subtract one day from current date). Thats because the
+	# data collect belongs to an interval beginning yesterday 23:55 and
+	# only ending today, at midnight.
+	if intervalId == 287:
+		currentDate = date.today() - timedelta(days=1)
+	else:
+		currentDate = date.today()
+	trafficFile = getTrafficFile(currentDate.strftime("%Y-%m-%d"))
+	trafficFile.write(str(intervalId)+ " " + rxPackages + " " + rxBytes + " " + txPackages + " " + txBytes +"\n")
+	trafficFile.close()
+except:
+      sys.exit(1)
diff --git a/windows-collect/src/proinfodataAgent.py b/windows-collect/src/proinfodataAgent.py
index c021b9a..663ed6e 100644
--- a/windows-collect/src/proinfodataAgent.py
+++ b/windows-collect/src/proinfodataAgent.py
@@ -35,6 +35,7 @@ import glob
 # ==========================================
 # TODO: Check compatibility with 64bit Windows (Program Files(x86) folder)
 PROINFODATAPATH = os.environ["ProgramFiles"] + "\\ProInfoData"
+PREVIOUSPATH = PROINFODATAPATH  + "\\data\\previous"
 URL = "http://200.17.202.187/tomcat/axis/Seed2.jws"
 # Log lifetime in days
 LOGLIFETIME = 30
@@ -153,8 +154,8 @@ def deleteOldLogs():
             os.remove(infile)
     
 # Send the collect-data.xml
-def sendData():
-    args = " --inventory --url=" + URL + " --inep=" + inep
+def sendData(option, xmlFile):
+    args = option + " --url=" + URL + " --inep=" + inep
     (phost, pport, puser, ppass) = getProxyInfo()
 
     if phost != "":
@@ -170,8 +171,8 @@ def sendData():
     return 0
 
 # Create collect-data.xml file
-def writeCollectData(collectData):
-    collectDataFile = file(PROINFODATAPATH + "\\data\\collect-data.xml", "w")
+def writeCollectData(collectData, xmlName):
+    collectDataFile = file(PROINFODATAPATH + "\\data\\" + xmlName, "w")
     collectDataFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
     collectDataFile.write(tostring(collectData))
     collectDataFile.close()
@@ -280,7 +281,7 @@ except:
 
 # Write the collect-data.xml file
 try:
-    writeCollectData(collectData)
+    writeCollectData(collectData, "collect-data.xml")
 except:
     log.write("ERROR(9): Failed to write collect-data.xml.")
     log.close()
@@ -288,17 +289,46 @@ except:
 
 # Send data
 try:
-    sendData()
+    sendData(" --inventory", "collect-data.xml")
 except clientError, e:
     log.write("ERROR(10): Failed to send data. Client returned " + str(e.code) + ".")
     log.write("Client message: " + str(e.errorMsg))
     log.close()
     sys.exit(10)
-except:
-    log.write("ERROR(11): Failed to get the proxy information from Windows registry.")
+except Exception, e:
+    log.write("ERROR(11): " + str(e))
     log.close()
     sys.exit(11)
 
+# Collect net usage
+if os.path.isdir(PREVIOUSPATH):
+    try:
+        netCollectData = collect.netCollect()
+    except Exception, e:
+        log.write("ERROR(12): Failed to collect net usage: " + str(e))
+        log.close()
+        sys.exit(12)
+    # Write the collect-data.xml file
+    try:
+        writeCollectData(netCollectData, "network-data.xml")
+    except:
+        log.write("ERROR(13): Failed to write net-collect-data.xml.")
+        log.close()
+        sys.exit(13)
+        
+    try:
+        sendData(" --net-usage ", "network-data.xml")
+        shutil.rmtree(PREVIOUSPATH)
+    except clientError, e:
+        log.write("ERROR(10): Failed to send net usage data. Client returned " + str(e.code) + ".")
+        log.write("Client message: " + str(e.errorMsg))
+        log.close()
+        sys.exit(10)
+    except Exception, e:
+        log.write("ERROR(14): " + str(e))
+        log.close()
+        sys.exit(14)
+
 # If everything ran ok, exit with success status
 log.write("EXIT(0): Success.")
 log.close()
diff --git a/windows-installer/src/installer.nsi b/windows-installer/src/installer.nsi
index af42ba2..7cb32e9 100644
--- a/windows-installer/src/installer.nsi
+++ b/windows-installer/src/installer.nsi
@@ -33,6 +33,7 @@ Uninstall\${PRODUCT_NAME}"
 !define PRODUCT_UNINST_ROOT_KEY "HKLM"
 !define PRODUCT_UNINST_NAME "Desinstalar ${PRODUCT_NAME}"
 !define PRODUCT_TASK "$PROGRAMFILES\${PRODUCT_NAME}\bin\agent\proinfodataAgent.exe"
+!define NETMON_TASK "$PROGRAMFILES\${PRODUCT_NAME}\bin\agent\netmon.exe"
 !define MUI_FINISHPAGE_NOAUTOCLOSE
 
 SetCompressor bzip2
@@ -125,6 +126,11 @@ Function .onInit
     DetailPrint "Killing all processes called '$0'"
     KillProc::KillProcesses 
 
+    ;Kill datasidAgent.exe process
+    StrCpy $0 "netmon.exe"
+    DetailPrint "Killing all processes called '$0'"
+    KillProc::KillProcesses
+
     ;Verify if INEP exists in Windows registry
     ClearErrors
     ReadRegStr $R2 HKLM "SOFTWARE\${PRODUCT_NAME}" "INEP"
@@ -161,6 +167,11 @@ Section "SeçãoPrincipal" SEC01
     /TR $\"\$\"${PRODUCT_TASK}$\"\$\" /RU System /F"
 	Pop $R2
 
+    ;Add net monitoring task in Windows task scheduler
+    nsExec::Exec "schtasks /Create /SC MINUTE /MO 5 /TN ProinfodataNetMon \
+    /TR $\"\$\"${NETMON_TASK}$\"\$\" /RU System /F"
+    Pop $R2
+
 	File "..\COPYING"
     CreateDirectory "$INSTDIR\conf"
     CreateDirectory "$INSTDIR\data"
@@ -180,6 +191,7 @@ Section "SeçãoPrincipal" SEC01
     File "..\..\windows-collect\src\dist\library.zip"
     ;File "..\..\windows-collect\src\dist\powrprof.dll"
     File "..\..\windows-collect\src\dist\proinfodataAgent.exe"
+    File "..\..\windows-collect\src\netmon\dist\netmon.exe"
     File "..\..\windows-collect\src\dist\pyexpat.pyd"
     File "..\..\windows-collect\src\dist\python27.dll"
     File "..\..\windows-collect\src\dist\pythoncom27.dll"
@@ -278,5 +290,9 @@ Section Uninstall
 	nsExec::Exec "schtasks /Delete /TN ProinfodataAgent /F"
 	Pop $R2
 
+    ;Delete scheduled task
+    nsExec::Exec "schtasks /Delete /TN ProinfodataNetMon /F"
+    Pop $R2
+
     SetAutoClose true
 SectionEnd
-- 
GitLab