aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--XBMC-ATV2.xcodeproj/project.pbxproj6
-rw-r--r--XBMC-IOS.xcodeproj/project.pbxproj6
-rw-r--r--XBMC.xcodeproj/project.pbxproj6
-rw-r--r--language/English/strings.po57
-rw-r--r--project/VS2010Express/XBMC.vcxproj2
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters6
-rw-r--r--system/settings/settings.xml6
-rw-r--r--xbmc/dbwrappers/mysqldataset.cpp3
-rw-r--r--xbmc/filesystem/DirectoryFactory.cpp2
-rw-r--r--xbmc/filesystem/FileFactory.cpp3
-rw-r--r--xbmc/main/main.cpp7
-rw-r--r--xbmc/network/Makefile.in1
-rw-r--r--xbmc/network/Network.cpp117
-rw-r--r--xbmc/network/Network.h6
-rw-r--r--xbmc/network/WakeOnAccess.cpp759
-rw-r--r--xbmc/network/WakeOnAccess.h82
-rw-r--r--xbmc/network/linux/NetworkLinux.cpp119
-rw-r--r--xbmc/network/linux/NetworkLinux.h5
-rw-r--r--xbmc/network/osx/ioshacks.h70
-rw-r--r--xbmc/network/windows/NetworkWin32.cpp54
-rw-r--r--xbmc/network/windows/NetworkWin32.h5
-rw-r--r--xbmc/powermanagement/PowerManager.cpp7
-rw-r--r--xbmc/settings/MediaSourceSettings.cpp3
-rw-r--r--xbmc/settings/Settings.cpp3
24 files changed, 1326 insertions, 9 deletions
diff --git a/XBMC-ATV2.xcodeproj/project.pbxproj b/XBMC-ATV2.xcodeproj/project.pbxproj
index 564ced5cef..65162866f8 100644
--- a/XBMC-ATV2.xcodeproj/project.pbxproj
+++ b/XBMC-ATV2.xcodeproj/project.pbxproj
@@ -181,6 +181,7 @@
DFA0F9551618E1CD00611CBB /* DVDOverlayCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA0F9541618E1CD00611CBB /* DVDOverlayCodec.cpp */; };
DFA6BE8713FED2A10048CC11 /* AirPlayServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA6BE8513FED2A10048CC11 /* AirPlayServer.cpp */; };
DFA6BE8A13FED2B40048CC11 /* HttpParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA6BE8813FED2B40048CC11 /* HttpParser.cpp */; };
+ DFA815A216713BC400E4E597 /* WakeOnAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA815A016713BC400E4E597 /* WakeOnAccess.cpp */; };
DFAB04C113F8385F00B70BFB /* InertialScrollingHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB04BF13F8385F00B70BFB /* InertialScrollingHandler.cpp */; };
DFAB4C0F15FCCB4300E1BAF6 /* TagLibVFSStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB4C0B15FCCB4300E1BAF6 /* TagLibVFSStream.cpp */; };
DFAB4C1015FCCB4300E1BAF6 /* TagLoaderTagLib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB4C0D15FCCB4300E1BAF6 /* TagLoaderTagLib.cpp */; };
@@ -1445,6 +1446,8 @@
DFA6BE8613FED2A10048CC11 /* AirPlayServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AirPlayServer.h; sourceTree = "<group>"; };
DFA6BE8813FED2B40048CC11 /* HttpParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpParser.cpp; sourceTree = "<group>"; };
DFA6BE8913FED2B40048CC11 /* HttpParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpParser.h; sourceTree = "<group>"; };
+ DFA815A016713BC400E4E597 /* WakeOnAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WakeOnAccess.cpp; sourceTree = "<group>"; };
+ DFA815A116713BC400E4E597 /* WakeOnAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnAccess.h; sourceTree = "<group>"; };
DFAB04BF13F8385F00B70BFB /* InertialScrollingHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InertialScrollingHandler.cpp; sourceTree = "<group>"; };
DFAB04C013F8385F00B70BFB /* InertialScrollingHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InertialScrollingHandler.h; sourceTree = "<group>"; };
DFAB4C0B15FCCB4300E1BAF6 /* TagLibVFSStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagLibVFSStream.cpp; sourceTree = "<group>"; };
@@ -5541,6 +5544,8 @@
F56C7668131EC153000AD0F6 /* TCPServer.h */,
F56C766B131EC153000AD0F6 /* UdpClient.cpp */,
F56C766C131EC153000AD0F6 /* UdpClient.h */,
+ DFA815A016713BC400E4E597 /* WakeOnAccess.cpp */,
+ DFA815A116713BC400E4E597 /* WakeOnAccess.h */,
F56C766D131EC153000AD0F6 /* WebServer.cpp */,
F56C766E131EC153000AD0F6 /* WebServer.h */,
F56C766F131EC153000AD0F6 /* Zeroconf.cpp */,
@@ -7767,6 +7772,7 @@
DFECFBFD172DA58800A43CF7 /* NetworkServices.cpp in Sources */,
F5DB701317322DF700D4DF21 /* FavouritesOperations.cpp in Sources */,
DF52568B1732C4620094A464 /* DVDDemuxCDDA.cpp in Sources */,
+ DFA815A216713BC400E4E597 /* WakeOnAccess.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/XBMC-IOS.xcodeproj/project.pbxproj b/XBMC-IOS.xcodeproj/project.pbxproj
index b7781dfb42..bd430b4b4b 100644
--- a/XBMC-IOS.xcodeproj/project.pbxproj
+++ b/XBMC-IOS.xcodeproj/project.pbxproj
@@ -187,6 +187,7 @@
DFA0F9291618E18A00611CBB /* DVDOverlayCodec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA0F9281618E18A00611CBB /* DVDOverlayCodec.cpp */; };
DFA6BE4313FECA010048CC11 /* AirPlayServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA6BE4113FECA010048CC11 /* AirPlayServer.cpp */; };
DFA6BE7713FED09C0048CC11 /* HttpParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA6BE7513FED09C0048CC11 /* HttpParser.cpp */; };
+ DFA8158E16713BA100E4E597 /* WakeOnAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA8158C16713BA100E4E597 /* WakeOnAccess.cpp */; };
DFAB04B013F8383300B70BFB /* InertialScrollingHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB04AE13F8383300B70BFB /* InertialScrollingHandler.cpp */; };
DFAB4BE615FCCA5000E1BAF6 /* TagLibVFSStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB4BE215FCCA5000E1BAF6 /* TagLibVFSStream.cpp */; };
DFAB4BE715FCCA5000E1BAF6 /* TagLoaderTagLib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB4BE415FCCA5000E1BAF6 /* TagLoaderTagLib.cpp */; };
@@ -1466,6 +1467,8 @@
DFA6BE4213FECA010048CC11 /* AirPlayServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AirPlayServer.h; sourceTree = "<group>"; };
DFA6BE7513FED09C0048CC11 /* HttpParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpParser.cpp; sourceTree = "<group>"; };
DFA6BE7613FED09C0048CC11 /* HttpParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpParser.h; sourceTree = "<group>"; };
+ DFA8158C16713BA100E4E597 /* WakeOnAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WakeOnAccess.cpp; sourceTree = "<group>"; };
+ DFA8158D16713BA100E4E597 /* WakeOnAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnAccess.h; sourceTree = "<group>"; };
DFAB04AE13F8383300B70BFB /* InertialScrollingHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InertialScrollingHandler.cpp; sourceTree = "<group>"; };
DFAB04AF13F8383300B70BFB /* InertialScrollingHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InertialScrollingHandler.h; sourceTree = "<group>"; };
DFAB4BE215FCCA5000E1BAF6 /* TagLibVFSStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagLibVFSStream.cpp; sourceTree = "<group>"; };
@@ -5943,6 +5946,8 @@
F56C864B131F42EB000AD0F6 /* TCPServer.h */,
F56C864E131F42EB000AD0F6 /* UdpClient.cpp */,
F56C864F131F42EB000AD0F6 /* UdpClient.h */,
+ DFA8158C16713BA100E4E597 /* WakeOnAccess.cpp */,
+ DFA8158D16713BA100E4E597 /* WakeOnAccess.h */,
F56C8650131F42EB000AD0F6 /* WebServer.cpp */,
F56C8651131F42EB000AD0F6 /* WebServer.h */,
F56C8652131F42EB000AD0F6 /* Zeroconf.cpp */,
@@ -7838,6 +7843,7 @@
DFECFB4F172D9D8E00A43CF7 /* NetworkServices.cpp in Sources */,
F5DB701A17322E0C00D4DF21 /* FavouritesOperations.cpp in Sources */,
DF52567A1732C43E0094A464 /* DVDDemuxCDDA.cpp in Sources */,
+ DFA8158E16713BA100E4E597 /* WakeOnAccess.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
index 2bff3c31c8..636006a780 100644
--- a/XBMC.xcodeproj/project.pbxproj
+++ b/XBMC.xcodeproj/project.pbxproj
@@ -443,6 +443,7 @@
DF93D7F61444B568007C6459 /* HDHomeRunDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF93D7F51444B568007C6459 /* HDHomeRunDirectory.cpp */; };
DF98D98C1434F47D00A6EBE1 /* SkinVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF98D98A1434F47D00A6EBE1 /* SkinVariable.cpp */; };
DF9A71EE1639C8F6005ECB2E /* HTTPFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF9A71EC1639C8F6005ECB2E /* HTTPFile.cpp */; };
+ DFA8157E16713B1200E4E597 /* WakeOnAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA8157C16713B1200E4E597 /* WakeOnAccess.cpp */; };
DFAB049813F8376700B70BFB /* InertialScrollingHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB049613F8376700B70BFB /* InertialScrollingHandler.cpp */; };
DFAF6A4F16EBAE3800D6AE12 /* RssManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAF6A4D16EBAE3800D6AE12 /* RssManager.cpp */; };
DFB02DEA16629DBA00F37752 /* PyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB02DE816629DBA00F37752 /* PyContext.cpp */; };
@@ -2021,6 +2022,8 @@
DF98D98B1434F47D00A6EBE1 /* SkinVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SkinVariable.h; sourceTree = "<group>"; };
DF9A71EC1639C8F6005ECB2E /* HTTPFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPFile.cpp; sourceTree = "<group>"; };
DF9A71ED1639C8F6005ECB2E /* HTTPFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPFile.h; sourceTree = "<group>"; };
+ DFA8157C16713B1200E4E597 /* WakeOnAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WakeOnAccess.cpp; sourceTree = "<group>"; };
+ DFA8157D16713B1200E4E597 /* WakeOnAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnAccess.h; sourceTree = "<group>"; };
DFAB049613F8376700B70BFB /* InertialScrollingHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InertialScrollingHandler.cpp; sourceTree = "<group>"; };
DFAB049713F8376700B70BFB /* InertialScrollingHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InertialScrollingHandler.h; sourceTree = "<group>"; };
DFAF6A4C16EBAE3800D6AE12 /* IRssObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRssObserver.h; sourceTree = "<group>"; };
@@ -4032,6 +4035,8 @@
432D7CF512D870D600CE4C49 /* TCPServer.h */,
E38E1E8B0D25F9FD00618676 /* UdpClient.cpp */,
E38E1E8C0D25F9FD00618676 /* UdpClient.h */,
+ DFA8157C16713B1200E4E597 /* WakeOnAccess.cpp */,
+ DFA8157D16713B1200E4E597 /* WakeOnAccess.h */,
F5A7A859112908F00059D6AA /* WebServer.cpp */,
F5A7A85A112908F00059D6AA /* WebServer.h */,
E46F7C280F77217400C25D29 /* Zeroconf.cpp */,
@@ -7836,6 +7841,7 @@
DFECFB4C172D9D6D00A43CF7 /* NetworkServices.cpp in Sources */,
F5DB700217322DBB00D4DF21 /* FavouritesOperations.cpp in Sources */,
DF52566D1732C1890094A464 /* DVDDemuxCDDA.cpp in Sources */,
+ DFA8157E16713B1200E4E597 /* WakeOnAccess.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/language/English/strings.po b/language/English/strings.po
index c3df8dca71..2575de8e9b 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -4822,7 +4822,62 @@ msgctxt "#13025"
msgid "Joystick unplugged"
msgstr ""
-#empty strings from id 13026 to 13049
+#: system/settings/settings.xml
+msgctxt "#13026"
+msgid "Try to wake remote servers on access"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13027"
+msgid "Wake on Lan (%s)"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13028"
+msgid "Waiting for network to connect..."
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13029"
+msgid "Failed to execute Wake on Lan!"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13030"
+msgid "Waiting for server to wake up..."
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13031"
+msgid "Extended wait for server to wake up..."
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13032"
+msgid "Waiting for services to launch..."
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13033"
+msgid "MAC Discovery"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13034"
+msgid "Updated for %s"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13035"
+msgid "Found for %s"
+msgstr ""
+
+#: xbmc/network/WakeOnAccess.cpp
+msgctxt "#13036"
+msgid "Failed for %s"
+msgstr ""
+
+#empty strings from id 13037 to 13049
msgctxt "#13050"
msgid "Running low on battery"
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index d0cad18bf6..5a40df6b47 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -848,6 +848,7 @@
<ClCompile Include="..\..\xbmc\network\upnp\UPnPRenderer.cpp" />
<ClCompile Include="..\..\xbmc\network\upnp\UPnPServer.cpp" />
<ClCompile Include="..\..\xbmc\network\upnp\UPnPSettings.cpp" />
+ <ClCompile Include="..\..\xbmc\network\WakeOnAccess.cpp" />
<ClCompile Include="..\..\xbmc\network\WebServer.cpp" />
<ClCompile Include="..\..\xbmc\network\websocket\WebSocket.cpp" />
<ClCompile Include="..\..\xbmc\network\websocket\WebSocketManager.cpp" />
@@ -1175,6 +1176,7 @@
<ClInclude Include="..\..\xbmc\network\upnp\UPnPPlayer.h" />
<ClInclude Include="..\..\xbmc\network\upnp\UPnPRenderer.h" />
<ClInclude Include="..\..\xbmc\network\upnp\UPnPServer.h" />
+ <ClInclude Include="..\..\xbmc\network\WakeOnAccess.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocket.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocketManager.h" />
<ClInclude Include="..\..\xbmc\network\websocket\WebSocketV13.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 2d42f5507d..556a4f552b 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -1324,6 +1324,9 @@
<ClCompile Include="..\..\xbmc\network\UdpClient.cpp">
<Filter>network</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\network\WakeOnAccess.cpp">
+ <Filter>network</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\network\WebServer.cpp">
<Filter>network</Filter>
</ClCompile>
@@ -4255,6 +4258,9 @@
<ClInclude Include="..\..\xbmc\network\UdpClient.h">
<Filter>network</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\network\WakeOnAccess.h">
+ <Filter>network</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\network\WebServer.h">
<Filter>network</Filter>
</ClInclude>
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index f5284e806b..488a3c8d00 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2230,6 +2230,12 @@
<control type="spinner" format="string" />
</setting>
</group>
+ <group id="2">
+ <setting id="powermanagement.wakeonaccess" type="boolean" label="13026" help="">
+ <level>1</level>
+ <default>false</default>
+ </setting>
+ </group>
</category>
<category id="debug" label="14092" help="">
<group id="1">
diff --git a/xbmc/dbwrappers/mysqldataset.cpp b/xbmc/dbwrappers/mysqldataset.cpp
index d4cd15320d..07f387506b 100644
--- a/xbmc/dbwrappers/mysqldataset.cpp
+++ b/xbmc/dbwrappers/mysqldataset.cpp
@@ -24,6 +24,7 @@
#include "utils/log.h"
#include "system.h" // for GetLastError()
+#include "network/WakeOnAccess.h"
#ifdef HAS_MYSQL
#include "mysqldataset.h"
@@ -119,6 +120,8 @@ int MysqlDatabase::connect(bool create_new) {
if (conn == NULL)
conn = mysql_init(conn);
+ CWakeOnAccess::Get().WakeUpHost(host, "MySQL : " + db);
+
// establish connection with just user credentials
if (mysql_real_connect(conn, host.c_str(),login.c_str(),passwd.c_str(), NULL, atoi(port.c_str()),NULL,0) != NULL)
{
diff --git a/xbmc/filesystem/DirectoryFactory.cpp b/xbmc/filesystem/DirectoryFactory.cpp
index 73c3c3edb0..df35e16e61 100644
--- a/xbmc/filesystem/DirectoryFactory.cpp
+++ b/xbmc/filesystem/DirectoryFactory.cpp
@@ -43,6 +43,7 @@
#include "Application.h"
#include "addons/Addon.h"
#include "utils/log.h"
+#include "network/WakeOnAccess.h"
#ifdef HAS_FILESYSTEM_SMB
#ifdef _WIN32
@@ -123,6 +124,7 @@ using namespace XFILE;
IDirectory* CDirectoryFactory::Create(const CStdString& strPath)
{
CURL url(strPath);
+ CWakeOnAccess::Get().WakeUpHost(url);
CFileItem item(strPath, false);
IFileDirectory* pDir=CFileDirectoryFactory::Create(strPath, &item);
diff --git a/xbmc/filesystem/FileFactory.cpp b/xbmc/filesystem/FileFactory.cpp
index 40f4180fa9..40331a8964 100644
--- a/xbmc/filesystem/FileFactory.cpp
+++ b/xbmc/filesystem/FileFactory.cpp
@@ -95,6 +95,7 @@
#include "Application.h"
#include "URL.h"
#include "utils/log.h"
+#include "network/WakeOnAccess.h"
using namespace XFILE;
@@ -114,6 +115,8 @@ IFile* CFileFactory::CreateLoader(const CStdString& strFileName)
IFile* CFileFactory::CreateLoader(const CURL& url)
{
+ CWakeOnAccess::Get().WakeUpHost(url);
+
CStdString strProtocol = url.GetProtocol();
strProtocol.MakeLower();
diff --git a/xbmc/main/main.cpp b/xbmc/main/main.cpp
index 9376a1673e..89af7f0877 100644
--- a/xbmc/main/main.cpp
+++ b/xbmc/main/main.cpp
@@ -65,13 +65,6 @@ int main(int argc, char* argv[])
if (setrlimit(RLIMIT_CORE, &rlim) == -1)
CLog::Log(LOGDEBUG, "Failed to set core size limit (%s)", strerror(errno));
#endif
- // Prevent child processes from becoming zombies on exit if not waited upon. See also Util::Command
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
-
- sa.sa_flags = SA_NOCLDWAIT;
- sa.sa_handler = SIG_IGN;
- sigaction(SIGCHLD, &sa, NULL);
#endif
setlocale(LC_NUMERIC, "C");
g_advancedSettings.Initialize();
diff --git a/xbmc/network/Makefile.in b/xbmc/network/Makefile.in
index bf9bed9330..c80651c4eb 100644
--- a/xbmc/network/Makefile.in
+++ b/xbmc/network/Makefile.in
@@ -10,6 +10,7 @@ SRCS = cddb.cpp \
Socket.cpp \
TCPServer.cpp \
UdpClient.cpp \
+ WakeOnAccess.cpp \
WebServer.cpp \
ZeroconfBrowser.cpp \
Zeroconf.cpp \
diff --git a/xbmc/network/Network.cpp b/xbmc/network/Network.cpp
index 8beca4803b..2a1d6bebd4 100644
--- a/xbmc/network/Network.cpp
+++ b/xbmc/network/Network.cpp
@@ -268,3 +268,120 @@ bool CNetwork::WakeOnLan(const char* mac)
CLog::Log(LOGINFO, "%s - Magic packet send to '%s'", __FUNCTION__, mac);
return true;
}
+
+// ping helper
+static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, struct timeval& timeOut, bool tryRead)
+{
+ // set non-blocking
+#ifdef _MSC_VER
+ u_long nonblocking = 1;
+ int result = ioctlsocket(soc, FIONBIO, &nonblocking);
+#else
+ int result = fcntl(soc, F_SETFL, fcntl(soc, F_GETFL) | O_NONBLOCK);
+#endif
+
+ if (result != 0)
+ return "set non-blocking option failed";
+
+ result = connect(soc, (struct sockaddr *)&addr, sizeof(addr)); // non-blocking connect, will fail ..
+
+ if (result < 0)
+ {
+#ifdef _MSC_VER
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+#else
+ if (errno != EINPROGRESS)
+#endif
+ return "unexpected connect fail";
+
+ { // wait for connect to complete
+ fd_set wset;
+ FD_ZERO(&wset);
+ FD_SET(soc, &wset);
+
+ result = select(FD_SETSIZE, 0, &wset, 0, &timeOut);
+ }
+
+ if (result < 0)
+ return "select fail";
+
+ if (result == 0) // timeout
+ return ""; // no error
+
+ { // verify socket connection state
+ int err_code = -1;
+ socklen_t code_len = sizeof (err_code);
+
+ result = getsockopt(soc, SOL_SOCKET, SO_ERROR, (char*) &err_code, &code_len);
+
+ if (result != 0)
+ return "getsockopt fail";
+
+ if (err_code != 0)
+ return ""; // no error, just not connected
+ }
+ }
+
+ if (tryRead)
+ {
+ fd_set rset;
+ FD_ZERO(&rset);
+ FD_SET(soc, &rset);
+
+ result = select(FD_SETSIZE, &rset, 0, 0, &timeOut);
+
+ if (result > 0)
+ {
+ char message [32];
+
+ result = recv(soc, message, sizeof(message), 0);
+ }
+
+ if (result == 0)
+ return ""; // no reply yet
+
+ if (result < 0)
+ return "recv fail";
+ }
+
+ return 0; // success
+}
+
+bool CNetwork::PingHost(unsigned long ipaddr, unsigned short port, unsigned int timeOutMs, bool readability_check)
+{
+ if (port == 0) // use icmp ping
+ return PingHost (ipaddr, timeOutMs);
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = ipaddr;
+
+ SOCKET soc = socket(AF_INET, SOCK_STREAM, 0);
+
+ const char* err_msg = "invalid socket";
+
+ if (soc != INVALID_SOCKET)
+ {
+ struct timeval tmout;
+ tmout.tv_sec = timeOutMs / 1000;
+ tmout.tv_usec = (timeOutMs % 1000) * 1000;
+
+ err_msg = ConnectHostPort (soc, addr, tmout, readability_check);
+
+ (void) closesocket (soc);
+ }
+
+ if (err_msg && *err_msg)
+ {
+#ifdef _MSC_VER
+ CStdString sock_err = WUSysMsg(WSAGetLastError());
+#else
+ CStdString sock_err = strerror(errno);
+#endif
+
+ CLog::Log(LOGERROR, "%s(%s:%d) - %s (%s)", __FUNCTION__, inet_ntoa(addr.sin_addr), port, err_msg, sock_err.c_str());
+ }
+
+ return err_msg == 0;
+}
diff --git a/xbmc/network/Network.h b/xbmc/network/Network.h
index 3500b70aaf..e608407dc8 100644
--- a/xbmc/network/Network.h
+++ b/xbmc/network/Network.h
@@ -63,6 +63,8 @@ public:
virtual CStdString GetMacAddress(void) = 0;
virtual void GetMacAddressRaw(char rawMac[6]) = 0;
+ virtual bool GetHostMacAddress(unsigned long host, CStdString& mac) = 0;
+
virtual CStdString GetCurrentIPAddress() = 0;
virtual CStdString GetCurrentNetmask() = 0;
virtual CStdString GetCurrentDefaultGateway(void) = 0;
@@ -109,6 +111,10 @@ public:
// Return true if the magic packet was send
bool WakeOnLan(const char *mac);
+ // Return true if host replies to ping
+ bool PingHost(unsigned long host, unsigned short port, unsigned int timeout_ms = 2000, bool readability_check = false);
+ virtual bool PingHost(unsigned long host, unsigned int timeout_ms = 2000) = 0;
+
// Get/set the nameserver(s)
virtual std::vector<CStdString> GetNameServers(void) = 0;
virtual void SetNameServers(std::vector<CStdString> nameServers) = 0;
diff --git a/xbmc/network/WakeOnAccess.cpp b/xbmc/network/WakeOnAccess.cpp
new file mode 100644
index 0000000000..8f39a70b78
--- /dev/null
+++ b/xbmc/network/WakeOnAccess.cpp
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program 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, 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 XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <limits.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "system.h"
+#include "network/Network.h"
+#include "Application.h"
+#include "DNSNameCache.h"
+#include "dialogs/GUIDialogProgress.h"
+#include "dialogs/GUIDialogKaiToast.h"
+#include "filesystem/SpecialProtocol.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/Settings.h"
+#include "settings/MediaSourceSettings.h"
+#include "utils/JobManager.h"
+#include "utils/log.h"
+#include "utils/XMLUtils.h"
+
+#include "WakeOnAccess.h"
+
+using namespace std;
+
+#define DEFAULT_NETWORK_INIT_SEC (20) // wait 20 sec for network after startup or resume
+#define DEFAULT_NETWORK_SETTLE_MS (500) // require 500ms of consistent network availability before trusting it
+
+#define DEFAULT_TIMEOUT_SEC (5*60) // at least 5 minutes between each magic packets
+#define DEFAULT_WAIT_FOR_ONLINE_SEC_1 (40) // wait at 40 seconds after sending magic packet
+#define DEFAULT_WAIT_FOR_ONLINE_SEC_2 (40) // same for extended wait
+#define DEFAULT_WAIT_FOR_SERVICES_SEC (5) // wait 5 seconds after host go online to launch file sharing deamons
+
+static int GetTotalSeconds(const CDateTimeSpan& ts)
+{
+ int hours = ts.GetHours() + ts.GetDays() * 24;
+ int minutes = ts.GetMinutes() + hours * 60;
+ return ts.GetSeconds() + minutes * 60;
+}
+
+static unsigned long HostToIP(const CStdString& host)
+{
+ CStdString ip;
+ CDNSNameCache::Lookup(host, ip);
+ return inet_addr(ip.c_str());
+}
+
+CWakeOnAccess::WakeUpEntry::WakeUpEntry (bool isAwake)
+ : timeout (0, 0, 0, DEFAULT_TIMEOUT_SEC)
+ , wait_online1_sec(DEFAULT_WAIT_FOR_ONLINE_SEC_1)
+ , wait_online2_sec(DEFAULT_WAIT_FOR_ONLINE_SEC_2)
+ , wait_services_sec(DEFAULT_WAIT_FOR_SERVICES_SEC)
+ , ping_port(0), ping_mode(0)
+{
+ nextWake = CDateTime::GetCurrentDateTime();
+
+ if (isAwake)
+ nextWake += timeout;
+}
+
+//**
+
+class CMACDiscoveryJob : public CJob
+{
+public:
+ CMACDiscoveryJob(const CStdString& host) : m_host(host) {}
+
+ virtual bool DoWork();
+
+ const CStdString& GetMAC() const { return m_macAddres; }
+ const CStdString& GetHost() const { return m_host; }
+
+private:
+ CStdString m_macAddres;
+ CStdString m_host;
+};
+
+bool CMACDiscoveryJob::DoWork()
+{
+ unsigned long ipAddress = HostToIP(m_host);
+
+ if (ipAddress == INADDR_NONE)
+ {
+ CLog::Log(LOGERROR, "%s - can't determine ip of '%s'", __FUNCTION__, m_host.c_str());
+ return false;
+ }
+
+ vector<CNetworkInterface*>& ifaces = g_application.getNetwork().GetInterfaceList();
+ for (vector<CNetworkInterface*>::const_iterator it = ifaces.begin(); it != ifaces.end(); ++it)
+ {
+ if ((*it)->GetHostMacAddress(ipAddress, m_macAddres))
+ return true;
+ }
+
+ return false;
+}
+
+//**
+
+class WaitCondition
+{
+public:
+ virtual bool SuccessWaiting () const { return false; }
+};
+
+//
+
+class NestDetect
+{
+public:
+ NestDetect() : m_gui_thread (g_application.IsCurrentThread())
+ {
+ if (m_gui_thread)
+ ++m_nest;
+ }
+ ~NestDetect()
+ {
+ if (m_gui_thread)
+ m_nest--;
+ }
+ static int Level()
+ {
+ return m_nest;
+ }
+ bool IsNested() const
+ {
+ return m_gui_thread && m_nest > 1;
+ }
+
+private:
+ static int m_nest;
+ const bool m_gui_thread;
+};
+int NestDetect::m_nest = 0;
+
+//
+
+class ProgressDialogHelper
+{
+public:
+ ProgressDialogHelper (const CStdString& heading) : m_dialog(0)
+ {
+ if (g_application.IsCurrentThread())
+ m_dialog = (CGUIDialogProgress*) g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
+
+ if (m_dialog)
+ {
+ m_dialog->SetHeading (heading);
+ m_dialog->SetLine(0, "");
+ m_dialog->SetLine(1, "");
+ m_dialog->SetLine(2, "");
+
+ int nest_level = NestDetect::Level();
+ if (nest_level > 1)
+ {
+ CStdString nest;
+ nest.Format("Nesting:%d", nest_level);
+ m_dialog->SetLine(2, nest);
+ }
+ }
+ }
+ ~ProgressDialogHelper ()
+ {
+ if (m_dialog)
+ m_dialog->Close();
+ }
+
+ bool HasDialog() const { return m_dialog != 0; }
+
+ enum wait_result { TimedOut, Canceled, Success };
+
+ wait_result ShowAndWait (const WaitCondition& waitObj, unsigned timeOutSec, const CStdString& line1)
+ {
+ unsigned timeOutMs = timeOutSec * 1000;
+
+ if (m_dialog)
+ {
+ m_dialog->SetLine(1, line1);
+
+ m_dialog->SetPercentage(1); // avoid flickering by starting at 1% ..
+ }
+
+ XbmcThreads::EndTime end_time (timeOutMs);
+
+ while (!end_time.IsTimePast())
+ {
+ if (waitObj.SuccessWaiting())
+ return Success;
+
+ if (m_dialog)
+ {
+ if (!m_dialog->IsActive())
+ m_dialog->StartModal();
+
+ if (m_dialog->IsCanceled())
+ return Canceled;
+
+ m_dialog->Progress();
+
+ unsigned ms_passed = timeOutMs - end_time.MillisLeft();
+
+ int percentage = (ms_passed * 100) / timeOutMs;
+ m_dialog->SetPercentage(max(percentage, 1)); // avoid flickering , keep minimum 1%
+ }
+
+ Sleep (m_dialog ? 20 : 200);
+ }
+
+ return TimedOut;
+ }
+
+private:
+ CGUIDialogProgress* m_dialog;
+};
+
+class NetworkStartWaiter : public WaitCondition
+{
+public:
+ NetworkStartWaiter (unsigned settle_time_ms) : m_settle_time_ms (settle_time_ms)
+ {
+ }
+ virtual bool SuccessWaiting () const
+ {
+ CNetworkInterface* iface = g_application.getNetwork().GetFirstConnectedInterface();
+
+ bool online = iface && iface->IsEnabled();
+
+ if (!online) // setup endtime so we dont return true until network is consistently connected
+ m_end.Set (m_settle_time_ms);
+
+ return online && m_end.IsTimePast();
+ }
+private:
+ mutable XbmcThreads::EndTime m_end;
+ unsigned m_settle_time_ms;
+};
+
+class PingResponseWaiter : public WaitCondition, private IJobCallback
+{
+public:
+ PingResponseWaiter (bool async, const CWakeOnAccess::WakeUpEntry& server)
+ : m_server(server), m_jobId(0), m_hostOnline(false)
+ {
+ if (async)
+ {
+ CJob* job = new CHostProberJob(server);
+ m_jobId = CJobManager::GetInstance().AddJob(job, this);
+ }
+ }
+ ~PingResponseWaiter()
+ {
+ CJobManager::GetInstance().CancelJob(m_jobId);
+ }
+ virtual bool SuccessWaiting () const
+ {
+ return m_jobId ? m_hostOnline : Ping(m_server);
+ }
+
+ virtual void OnJobComplete(unsigned int jobID, bool success, CJob *job)
+ {
+ m_hostOnline = success;
+ }
+
+ static bool Ping (const CWakeOnAccess::WakeUpEntry& server)
+ {
+ ULONG dst_ip = HostToIP(server.host);
+
+ return g_application.getNetwork().PingHost(dst_ip, server.ping_port, 2000, server.ping_mode & 1);
+ }
+
+private:
+ class CHostProberJob : public CJob
+ {
+ public:
+ CHostProberJob(const CWakeOnAccess::WakeUpEntry& server) : m_server (server) {}
+
+ virtual bool DoWork()
+ {
+ while (!ShouldCancel(0,0))
+ {
+ if (PingResponseWaiter::Ping(m_server))
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ const CWakeOnAccess::WakeUpEntry& m_server;
+ };
+
+ const CWakeOnAccess::WakeUpEntry& m_server;
+ unsigned int m_jobId;
+ bool m_hostOnline;
+};
+
+//
+
+CWakeOnAccess::CWakeOnAccess()
+ : m_netinit_sec(DEFAULT_NETWORK_INIT_SEC) // wait for network to connect
+ , m_netsettle_ms(DEFAULT_NETWORK_SETTLE_MS) // wait for network to settle
+ , m_enabled(false)
+{
+}
+
+CWakeOnAccess &CWakeOnAccess::Get()
+{
+ static CWakeOnAccess sWakeOnAccess;
+ return sWakeOnAccess;
+}
+
+void CWakeOnAccess::WakeUpHost(const CURL& url)
+{
+ CStdString hostName = url.GetHostName();
+
+ if (!hostName.IsEmpty())
+ WakeUpHost (hostName, url.Get());
+}
+
+void CWakeOnAccess::WakeUpHost (const CStdString& hostName, const string& customMessage)
+{
+ if (!IsEnabled())
+ return; // bail if feature is turned off
+
+ WakeUpEntry server;
+
+ if (FindOrTouchHostEntry(hostName, server))
+ {
+ CLog::Log(LOGNOTICE,"WakeOnAccess [%s] trigged by accessing : %s", hostName.c_str(), customMessage.c_str());
+
+ NestDetect nesting ; // detect recursive calls on gui thread..
+
+ if (nesting.IsNested()) // we might get in trouble if it gets called back in loop
+ CLog::Log(LOGWARNING,"WakeOnAccess recursively called on gui-thread [%d]", NestDetect::Level());
+
+ WakeUpHost(server);
+
+ TouchHostEntry(hostName);
+ }
+}
+
+#define LOCALIZED(id) g_localizeStrings.Get(id)
+
+void CWakeOnAccess::WakeUpHost(const WakeUpEntry& server)
+{
+ CStdString heading = LOCALIZED(13027);
+ heading.Format (heading, server.host);
+
+ ProgressDialogHelper dlg (heading);
+
+ {
+ NetworkStartWaiter waitObj (m_netsettle_ms); // wait until network connected before sending wake-on-lan
+
+ if (dlg.ShowAndWait (waitObj, m_netinit_sec, LOCALIZED(13028)) != ProgressDialogHelper::Success)
+ {
+ CLog::Log(LOGNOTICE,"WakeOnAccess timeout/cancel while waiting for network");
+ return; // timedout or canceled
+ }
+ }
+
+ {
+ ULONG dst_ip = HostToIP(server.host);
+
+ if (g_application.getNetwork().PingHost(dst_ip, server.ping_port, 500)) // quick ping with short timeout to not block too long
+ {
+ CLog::Log(LOGNOTICE,"WakeOnAccess success exit, server already running");
+ return;
+ }
+ }
+
+ if (!g_application.getNetwork().WakeOnLan(server.mac.c_str()))
+ {
+ CLog::Log(LOGERROR,"WakeOnAccess failed to send. (Is it blocked by firewall?)");
+
+ if (g_application.IsCurrentThread() || !g_application.IsPlaying())
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, heading, LOCALIZED(13029));
+ return;
+ }
+
+ {
+ PingResponseWaiter waitObj (dlg.HasDialog(), server); // wait for ping response ..
+
+ ProgressDialogHelper::wait_result
+ result = dlg.ShowAndWait (waitObj, server.wait_online1_sec, LOCALIZED(13030));
+
+ if (result == ProgressDialogHelper::TimedOut)
+ result = dlg.ShowAndWait (waitObj, server.wait_online2_sec, LOCALIZED(13031));
+
+ if (result != ProgressDialogHelper::Success)
+ {
+ CLog::Log(LOGNOTICE,"WakeOnAccess timeout/cancel while waiting for response");
+ return; // timedout or canceled
+ }
+ }
+
+ {
+ WaitCondition waitObj ; // wait uninteruptable fixed time for services ..
+
+ dlg.ShowAndWait (waitObj, server.wait_services_sec, LOCALIZED(13032));
+
+ CLog::Log(LOGNOTICE,"WakeOnAccess sequence completed, server started");
+ }
+}
+
+bool CWakeOnAccess::FindOrTouchHostEntry (const CStdString& hostName, WakeUpEntry& result)
+{
+ CSingleLock lock (m_entrylist_protect);
+
+ bool need_wakeup = false;
+
+ for (EntriesVector::iterator i = m_entries.begin();i != m_entries.end(); ++i)
+ {
+ WakeUpEntry& server = *i;
+
+ if (hostName.Equals(server.host.c_str()))
+ {
+ CDateTime now = CDateTime::GetCurrentDateTime();
+
+ if (now > server.nextWake)
+ {
+ result = server;
+ need_wakeup = true;
+ }
+ else // 'touch' next wakeup time
+ {
+ server.nextWake = now + server.timeout;
+ }
+
+ break;
+ }
+ }
+
+ return need_wakeup;
+}
+
+void CWakeOnAccess::TouchHostEntry (const CStdString& hostName)
+{
+ CSingleLock lock (m_entrylist_protect);
+
+ for (EntriesVector::iterator i = m_entries.begin();i != m_entries.end(); ++i)
+ {
+ WakeUpEntry& server = *i;
+
+ if (hostName.Equals(server.host.c_str()))
+ {
+ server.nextWake = CDateTime::GetCurrentDateTime() + server.timeout;
+ return;
+ }
+ }
+}
+
+static void AddHost (const CStdString& host, vector<string>& hosts)
+{
+ for (vector<string>::const_iterator it = hosts.begin(); it != hosts.end(); ++it)
+ if (host.Equals((*it).c_str()))
+ return; // allready there ..
+
+ if (!host.IsEmpty())
+ hosts.push_back(host);
+}
+
+static void AddHostFromDatabase(const DatabaseSettings& setting, vector<string>& hosts)
+{
+ if (setting.type.Equals("mysql"))
+ AddHost(setting.host, hosts);
+}
+
+void CWakeOnAccess::QueueMACDiscoveryForHost(const CStdString& host)
+{
+ if (IsEnabled())
+ CJobManager::GetInstance().AddJob(new CMACDiscoveryJob(host), this);
+}
+
+static void AddHostsFromMediaSource(const CMediaSource& source, std::vector<std::string>& hosts)
+{
+ for (CStdStringArray::const_iterator it = source.vecPaths.begin() ; it != source.vecPaths.end(); it++)
+ {
+ CURL url = *it;
+
+ AddHost (url.GetHostName(), hosts);
+ }
+}
+
+static void AddHostsFromVecSource(const VECSOURCES& sources, vector<string>& hosts)
+{
+ for (VECSOURCES::const_iterator it = sources.begin(); it != sources.end(); it++)
+ AddHostsFromMediaSource(*it, hosts);
+}
+
+static void AddHostsFromVecSource(const VECSOURCES* sources, vector<string>& hosts)
+{
+ if (sources)
+ AddHostsFromVecSource(*sources, hosts);
+}
+
+void CWakeOnAccess::QueueMACDiscoveryForAllRemotes()
+{
+ vector<string> hosts;
+
+ // add media sources
+ CMediaSourceSettings& ms = CMediaSourceSettings::Get();
+
+ AddHostsFromVecSource(ms.GetSources("video"), hosts);
+ AddHostsFromVecSource(ms.GetSources("music"), hosts);
+ AddHostsFromVecSource(ms.GetSources("files"), hosts);
+ AddHostsFromVecSource(ms.GetSources("pictures"), hosts);
+ AddHostsFromVecSource(ms.GetSources("programs"), hosts);
+
+ // add mysql servers
+ AddHostFromDatabase(g_advancedSettings.m_databaseVideo, hosts);
+ AddHostFromDatabase(g_advancedSettings.m_databaseMusic, hosts);
+ AddHostFromDatabase(g_advancedSettings.m_databaseEpg, hosts);
+ AddHostFromDatabase(g_advancedSettings.m_databaseTV, hosts);
+
+ // add from path substitutions ..
+ for (CAdvancedSettings::StringMapping::iterator i = g_advancedSettings.m_pathSubstitutions.begin(); i != g_advancedSettings.m_pathSubstitutions.end(); ++i)
+ {
+ CURL url = i->second;
+
+ AddHost (url.GetHostName(), hosts);
+ }
+
+ for (vector<string>::const_iterator it = hosts.begin(); it != hosts.end(); it++)
+ QueueMACDiscoveryForHost(*it);
+}
+
+void CWakeOnAccess::SaveMACDiscoveryResult(const CStdString& host, const CStdString& mac)
+{
+ CLog::Log(LOGNOTICE, "%s - Mac discovered for host '%s' -> '%s'", __FUNCTION__, host.c_str(), mac.c_str());
+
+ CStdString heading = LOCALIZED(13033);
+
+ for (EntriesVector::iterator i = m_entries.begin(); i != m_entries.end(); ++i)
+ {
+ if (host.Equals(i->host.c_str()))
+ {
+ CLog::Log(LOGDEBUG, "%s - Update existing entry for host '%s'", __FUNCTION__, host.c_str());
+ if (!mac.Equals(i->mac.c_str()))
+ {
+ if (IsEnabled()) // show notification only if we have general feature enabled
+ {
+ CStdString message = LOCALIZED(13034);
+ message.Format(message, host);
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, heading, message, 4000, true, 3000);
+ }
+
+ i->mac = mac;
+ SaveToXML();
+ }
+
+ return;
+ }
+ }
+
+ // not found entry to update - create using default values
+ WakeUpEntry entry (true);
+ entry.host = host;
+ entry.mac = mac;
+ m_entries.push_back(entry);
+
+ CLog::Log(LOGDEBUG, "%s - Create new entry for host '%s'", __FUNCTION__, host.c_str());
+ if (IsEnabled()) // show notification only if we have general feature enabled
+ {
+ CStdString message = LOCALIZED(13035);
+ message.Format(message, host);
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, heading, message, 4000, true, 3000);
+ }
+
+ SaveToXML();
+}
+
+void CWakeOnAccess::OnJobComplete(unsigned int jobID, bool success, CJob *job)
+{
+ CMACDiscoveryJob* discoverJob = (CMACDiscoveryJob*)job;
+
+ const CStdString& host = discoverJob->GetHost();
+ const CStdString& mac = discoverJob->GetMAC();
+
+ if (success)
+ {
+ CSingleLock lock (m_entrylist_protect);
+
+ SaveMACDiscoveryResult(host, mac);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "%s - Mac discovery failed for host '%s'", __FUNCTION__, host.c_str());
+
+ if (IsEnabled())
+ {
+ CStdString heading = LOCALIZED(13033);
+ CStdString message = LOCALIZED(13036);
+ message.Format(message, host);
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, heading, message, 4000, true, 3000);
+ }
+ }
+}
+
+CStdString CWakeOnAccess::GetSettingFile()
+{
+ return CSpecialProtocol::TranslatePath("special://masterprofile/wakeonlan.xml");
+}
+
+void CWakeOnAccess::OnSettingsLoaded()
+{
+ CSingleLock lock (m_entrylist_protect);
+
+ LoadFromXML();
+}
+
+void CWakeOnAccess::OnSettingsSaved() const
+{
+ bool enabled = CSettings::Get().GetBool("powermanagement.wakeonaccess");
+
+ if (enabled != IsEnabled())
+ {
+ CWakeOnAccess& woa = CWakeOnAccess::Get();
+
+ woa.SetEnabled(enabled);
+
+ if (enabled)
+ woa.QueueMACDiscoveryForAllRemotes();
+ }
+}
+
+void CWakeOnAccess::LoadFromXML()
+{
+ bool enabled = CSettings::Get().GetBool("powermanagement.wakeonaccess");
+ SetEnabled(enabled);
+
+ CXBMCTinyXML xmlDoc;
+ if (!xmlDoc.LoadFile(GetSettingFile()))
+ {
+ CLog::Log(LOGNOTICE, "%s - unable to load:%s", __FUNCTION__, GetSettingFile().c_str());
+ return;
+ }
+
+ TiXmlElement* pRootElement = xmlDoc.RootElement();
+ if (strcmpi(pRootElement->Value(), "onaccesswakeup"))
+ {
+ CLog::Log(LOGERROR, "%s - XML file %s doesnt contain <onaccesswakeup>", __FUNCTION__, GetSettingFile().c_str());
+ return;
+ }
+
+ m_entries.clear();
+
+ CLog::Log(LOGNOTICE,"WakeOnAccess - Load settings :");
+
+ int tmp;
+ if (XMLUtils::GetInt(pRootElement, "netinittimeout", tmp, 0, 5 * 60))
+ m_netinit_sec = tmp;
+ CLog::Log(LOGNOTICE," -Network init timeout : [%d] sec", m_netinit_sec);
+
+ if (XMLUtils::GetInt(pRootElement, "netsettletime", tmp, 0, 5 * 1000))
+ m_netsettle_ms = tmp;
+ CLog::Log(LOGNOTICE," -Network settle time : [%d] ms", m_netsettle_ms);
+
+ const TiXmlNode* pWakeUp = pRootElement->FirstChildElement("wakeup");
+ while (pWakeUp)
+ {
+ WakeUpEntry entry;
+
+ CStdString strtmp;
+ if (XMLUtils::GetString(pWakeUp, "host", strtmp))
+ entry.host = strtmp;
+
+ if (XMLUtils::GetString(pWakeUp, "mac", strtmp))
+ entry.mac = strtmp;
+
+ if (entry.host.empty())
+ CLog::Log(LOGERROR, "%s - Missing <host> tag or it's empty", __FUNCTION__);
+ else if (entry.mac.empty())
+ CLog::Log(LOGERROR, "%s - Missing <mac> tag or it's empty", __FUNCTION__);
+ else
+ {
+ if (XMLUtils::GetInt(pWakeUp, "pingport", tmp, 0, USHRT_MAX))
+ entry.ping_port = (unsigned short) tmp;
+
+ if (XMLUtils::GetInt(pWakeUp, "pingmode", tmp, 0, USHRT_MAX))
+ entry.ping_mode = (unsigned short) tmp;
+
+ if (XMLUtils::GetInt(pWakeUp, "timeout", tmp, 10, 12 * 60 * 60))
+ entry.timeout.SetDateTimeSpan (0, 0, 0, tmp);
+
+ if (XMLUtils::GetInt(pWakeUp, "waitonline", tmp, 0, 10 * 60)) // max 10 minutes
+ entry.wait_online1_sec = tmp;
+
+ if (XMLUtils::GetInt(pWakeUp, "waitonline2", tmp, 0, 10 * 60)) // max 10 minutes
+ entry.wait_online2_sec = tmp;
+
+ if (XMLUtils::GetInt(pWakeUp, "waitservices", tmp, 0, 5 * 60)) // max 5 minutes
+ entry.wait_services_sec = tmp;
+
+ CLog::Log(LOGNOTICE," Registering wakeup entry:");
+ CLog::Log(LOGNOTICE," HostName : %s", entry.host.c_str());
+ CLog::Log(LOGNOTICE," MacAddress : %s", entry.mac.c_str());
+ CLog::Log(LOGNOTICE," PingPort : %d", entry.ping_port);
+ CLog::Log(LOGNOTICE," PingMode : %d", entry.ping_mode);
+ CLog::Log(LOGNOTICE," Timeout : %d (sec)", GetTotalSeconds(entry.timeout));
+ CLog::Log(LOGNOTICE," WaitForOnline : %d (sec)", entry.wait_online1_sec);
+ CLog::Log(LOGNOTICE," WaitForOnlineEx : %d (sec)", entry.wait_online2_sec);
+ CLog::Log(LOGNOTICE," WaitForServices : %d (sec)", entry.wait_services_sec);
+
+ m_entries.push_back(entry);
+ }
+
+ pWakeUp = pWakeUp->NextSiblingElement("wakeup"); // get next one
+ }
+}
+
+void CWakeOnAccess::SaveToXML()
+{
+ CXBMCTinyXML xmlDoc;
+ TiXmlElement xmlRootElement("onaccesswakeup");
+ TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
+ if (!pRoot) return;
+
+ XMLUtils::SetInt(pRoot, "netinittimeout", m_netinit_sec);
+ XMLUtils::SetInt(pRoot, "netsettletime", m_netsettle_ms);
+
+ for (EntriesVector::const_iterator i = m_entries.begin(); i != m_entries.end(); ++i)
+ {
+ TiXmlElement xmlSetting("wakeup");
+ TiXmlNode* pWakeUpNode = pRoot->InsertEndChild(xmlSetting);
+ if (pWakeUpNode)
+ {
+ XMLUtils::SetString(pWakeUpNode, "host", i->host);
+ XMLUtils::SetString(pWakeUpNode, "mac", i->mac);
+ XMLUtils::SetInt(pWakeUpNode, "pingport", i->ping_port);
+ XMLUtils::SetInt(pWakeUpNode, "pingmode", i->ping_mode);
+ XMLUtils::SetInt(pWakeUpNode, "timeout", GetTotalSeconds(i->timeout));
+ XMLUtils::SetInt(pWakeUpNode, "waitonline", i->wait_online1_sec);
+ XMLUtils::SetInt(pWakeUpNode, "waitonline2", i->wait_online2_sec);
+ XMLUtils::SetInt(pWakeUpNode, "waitservices", i->wait_services_sec);
+ }
+ }
+
+ xmlDoc.SaveFile(GetSettingFile());
+}
diff --git a/xbmc/network/WakeOnAccess.h b/xbmc/network/WakeOnAccess.h
new file mode 100644
index 0000000000..7f9cdc5a63
--- /dev/null
+++ b/xbmc/network/WakeOnAccess.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program 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, 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 XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "URL.h"
+#include "XBDateTime.h"
+#include "utils/Job.h"
+#include "settings/ISettingsHandler.h"
+
+class CWakeOnAccess : private IJobCallback, public ISettingsHandler
+{
+public:
+ static CWakeOnAccess &Get();
+
+ void WakeUpHost (const CURL& fileUrl);
+ void WakeUpHost (const CStdString& hostName, const std::string& customMessage);
+
+ void QueueMACDiscoveryForAllRemotes();
+
+ virtual void OnJobComplete(unsigned int jobID, bool success, CJob *job);
+ virtual void OnSettingsLoaded();
+ virtual void OnSettingsSaved() const;
+
+ // struct to keep per host settings
+ struct WakeUpEntry
+ {
+ WakeUpEntry (bool isAwake = false);
+
+ std::string host;
+ std::string mac;
+ CDateTimeSpan timeout;
+ unsigned int wait_online1_sec; // initial wait
+ unsigned int wait_online2_sec; // extended wait
+ unsigned int wait_services_sec;
+
+ unsigned short ping_port; // where to ping
+ unsigned short ping_mode; // how to ping
+
+ CDateTime nextWake;
+ };
+
+private:
+ CWakeOnAccess();
+ CStdString GetSettingFile();
+ void LoadFromXML();
+ void SaveToXML();
+
+ void SetEnabled(bool enabled) { m_enabled = enabled; }
+ bool IsEnabled() const { return m_enabled; }
+
+ void QueueMACDiscoveryForHost(const CStdString& host);
+ void SaveMACDiscoveryResult(const CStdString& host, const CStdString& mac);
+
+ typedef std::vector<WakeUpEntry> EntriesVector;
+ EntriesVector m_entries;
+ CCriticalSection m_entrylist_protect;
+ bool FindOrTouchHostEntry (const CStdString& hostName, WakeUpEntry& server);
+ void TouchHostEntry (const CStdString& hostName);
+
+ unsigned int m_netinit_sec, m_netsettle_ms; //time to wait for network connection
+
+ bool m_enabled;
+
+ void WakeUpHost(const WakeUpEntry& server);
+};
diff --git a/xbmc/network/linux/NetworkLinux.cpp b/xbmc/network/linux/NetworkLinux.cpp
index 013095798b..8908052f65 100644
--- a/xbmc/network/linux/NetworkLinux.cpp
+++ b/xbmc/network/linux/NetworkLinux.cpp
@@ -37,6 +37,13 @@
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_dl.h>
+#if defined(TARGET_DARWIN_OSX)
+ #include <net/if_types.h>
+ #include <net/route.h>
+ #include <netinet/if_ether.h>
+#else //IOS
+ #include "network/osx/ioshacks.h"
+#endif
#include <ifaddrs.h>
#elif defined(TARGET_FREEBSD)
#include <sys/sockio.h>
@@ -520,6 +527,118 @@ void CNetworkLinux::SetNameServers(std::vector<CStdString> nameServers)
#endif
}
+bool CNetworkLinux::PingHost(unsigned long remote_ip, unsigned int timeout_ms)
+{
+ char cmd_line [64];
+
+ struct in_addr host_ip;
+ host_ip.s_addr = remote_ip;
+
+ sprintf(cmd_line, "ping -c 1 -w %d %s", timeout_ms / 1000 + (timeout_ms % 1000) != 0, inet_ntoa(host_ip));
+
+ int status = system (cmd_line);
+
+ int result = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+
+ // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ;
+ // 0 reply
+ // 1 no reply
+ // else some error
+
+ if (result < 0 || result > 1)
+ CLog::Log(LOGERROR, "Ping fail : status = %d, errno = %d : '%s'", status, errno, cmd_line);
+
+ return result == 0;
+}
+
+#if defined TARGET_DARWIN
+bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
+{
+ bool ret = false;
+ size_t needed;
+ char *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_inarp *sin;
+ struct sockaddr_dl *sdl;
+ int mib[6];
+
+ mac = "";
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &needed, NULL, 0) == 0)
+ {
+ if (buf = (char*)malloc(needed))
+ {
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0) == 0)
+ {
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen)
+ {
+
+ rtm = (struct rt_msghdr *)next;
+ sin = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin + 1);
+
+ if (host_ip != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
+ continue;
+
+ u_char *cp = (u_char*)LLADDR(sdl);
+
+ mac.Format("%02X:%02X:%02X:%02X:%02X:%02X",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ ret = true;
+ break;
+ }
+ }
+ free(buf);
+ }
+ }
+ return ret;
+}
+#else
+bool CNetworkInterfaceLinux::GetHostMacAddress(unsigned long host_ip, CStdString& mac)
+{
+ struct arpreq areq;
+ struct sockaddr_in* sin;
+
+ memset(&areq, 0x0, sizeof(areq));
+
+ sin = (struct sockaddr_in *) &areq.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = host_ip;
+
+ sin = (struct sockaddr_in *) &areq.arp_ha;
+ sin->sin_family = ARPHRD_ETHER;
+
+ strncpy(areq.arp_dev, m_interfaceName.c_str(), sizeof(areq.arp_dev));
+ areq.arp_dev[sizeof(areq.arp_dev)-1] = '\0';
+
+ int result = ioctl (m_network->GetSocket(), SIOCGARP, (caddr_t) &areq);
+
+ if (result != 0)
+ {
+// CLog::Log(LOGERROR, "%s - GetHostMacAddress/ioctl failed with errno (%d)", __FUNCTION__, errno);
+ return false;
+ }
+
+ struct sockaddr* res = &areq.arp_ha;
+ mac.Format("%02X:%02X:%02X:%02X:%02X:%02X",
+ (uint8_t) res->sa_data[0], (uint8_t) res->sa_data[1], (uint8_t) res->sa_data[2],
+ (uint8_t) res->sa_data[3], (uint8_t) res->sa_data[4], (uint8_t) res->sa_data[5]);
+
+ for (int i=0; i<6; ++i)
+ if (res->sa_data[i])
+ return true;
+
+ return false;
+}
+#endif
+
std::vector<NetworkAccessPoint> CNetworkInterfaceLinux::GetAccessPoints(void)
{
std::vector<NetworkAccessPoint> result;
diff --git a/xbmc/network/linux/NetworkLinux.h b/xbmc/network/linux/NetworkLinux.h
index 7031b6ec37..be4218ea41 100644
--- a/xbmc/network/linux/NetworkLinux.h
+++ b/xbmc/network/linux/NetworkLinux.h
@@ -42,6 +42,8 @@ public:
virtual CStdString GetMacAddress(void);
virtual void GetMacAddressRaw(char rawMac[6]);
+ virtual bool GetHostMacAddress(unsigned long host, CStdString& mac);
+
virtual CStdString GetCurrentIPAddress();
virtual CStdString GetCurrentNetmask();
virtual CStdString GetCurrentDefaultGateway(void);
@@ -71,6 +73,9 @@ public:
virtual std::vector<CNetworkInterface*>& GetInterfaceList(void);
virtual CNetworkInterface* GetFirstConnectedInterface(void);
+ // Ping remote host
+ virtual bool PingHost(unsigned long host, unsigned int timeout_ms = 2000);
+
// Get/set the nameserver(s)
virtual std::vector<CStdString> GetNameServers(void);
virtual void SetNameServers(std::vector<CStdString> nameServers);
diff --git a/xbmc/network/osx/ioshacks.h b/xbmc/network/osx/ioshacks.h
new file mode 100644
index 0000000000..d15cab0f86
--- /dev/null
+++ b/xbmc/network/osx/ioshacks.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program 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, 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 XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// needed for CNetworkInterfaceLinux::GetHostMacAddress and taken from osx sdk
+// net/if_types.h net/route.h netinet/if_ether.h
+
+/*
+ * These numbers are used by reliable protocols for determining
+ * retransmission behavior and are included in the routing structure.
+ */
+struct rt_metrics {
+ u_int32_t rmx_locks; /* Kernel must leave these values alone */
+ u_int32_t rmx_mtu; /* MTU for this path */
+ u_int32_t rmx_hopcount; /* max hops expected */
+ int32_t rmx_expire; /* lifetime for route, e.g. redirect */
+ u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */
+ u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */
+ u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */
+ u_int32_t rmx_rtt; /* estimated round trip time */
+ u_int32_t rmx_rttvar; /* estimated rtt variance */
+ u_int32_t rmx_pksent; /* packets sent using this route */
+ u_int32_t rmx_filler[4]; /* will be used for T/TCP later */
+};
+
+/*
+ * Structures for routing messages.
+ */
+struct rt_msghdr {
+ u_short rtm_msglen; /* to skip over non-understood messages */
+ u_char rtm_version; /* future binary compatibility */
+ u_char rtm_type; /* message type */
+ u_short rtm_index; /* index for associated ifp */
+ int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
+ int rtm_addrs; /* bitmask identifying sockaddrs in msg */
+ pid_t rtm_pid; /* identify sender */
+ int rtm_seq; /* for sender to identify action */
+ int rtm_errno; /* why failed */
+ int rtm_use; /* from rtentry */
+ u_int32_t rtm_inits; /* which metrics we are initializing */
+ struct rt_metrics rtm_rmx; /* metrics themselves */
+};
+struct sockaddr_inarp {
+ u_char sin_len;
+ u_char sin_family;
+ u_short sin_port;
+ struct in_addr sin_addr;
+ struct in_addr sin_srcaddr;
+ u_short sin_tos;
+ u_short sin_other;
+#define SIN_PROXY 1
+};
+#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */
+// --- END
diff --git a/xbmc/network/windows/NetworkWin32.cpp b/xbmc/network/windows/NetworkWin32.cpp
index f19a2296a1..82fe5a8edb 100644
--- a/xbmc/network/windows/NetworkWin32.cpp
+++ b/xbmc/network/windows/NetworkWin32.cpp
@@ -19,6 +19,8 @@
*/
#include <errno.h>
+#include <iphlpapi.h>
+#include <IcmpAPI.h>
#include "PlatformDefs.h"
#include "NetworkWin32.h"
#include "utils/log.h"
@@ -261,6 +263,58 @@ void CNetworkWin32::SetNameServers(std::vector<CStdString> nameServers)
return;
}
+bool CNetworkWin32::PingHost(unsigned long host, unsigned int timeout_ms /* = 2000 */)
+{
+ char SendData[] = "poke";
+ HANDLE hIcmpFile = IcmpCreateFile();
+ BYTE ReplyBuffer [sizeof(ICMP_ECHO_REPLY) + sizeof(SendData)];
+
+ SetLastError(ERROR_SUCCESS);
+
+ DWORD dwRetVal = IcmpSendEcho(hIcmpFile, host, SendData, sizeof(SendData),
+ NULL, ReplyBuffer, sizeof(ReplyBuffer), timeout_ms);
+
+ DWORD lastErr = GetLastError();
+ if (lastErr != ERROR_SUCCESS)
+ CLog::Log(LOGERROR, "%s - IcmpSendEcho failed - %s", __FUNCTION__, WUSysMsg(lastErr).c_str());
+
+ IcmpCloseHandle (hIcmpFile);
+
+ if (dwRetVal != 0)
+ {
+ PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
+ return (pEchoReply->Status == IP_SUCCESS);
+ }
+ return false;
+}
+
+bool CNetworkInterfaceWin32::GetHostMacAddress(unsigned long host, CStdString& mac)
+{
+ IPAddr src_ip = inet_addr(GetCurrentIPAddress().c_str());
+ BYTE bPhysAddr[6]; // for 6-byte hardware addresses
+ ULONG PhysAddrLen = 6; // default to length of six bytes
+
+ memset(&bPhysAddr, 0xff, sizeof (bPhysAddr));
+
+ DWORD dwRetVal = SendARP(host, src_ip, &bPhysAddr, &PhysAddrLen);
+ if (dwRetVal == NO_ERROR)
+ {
+ if (PhysAddrLen == 6)
+ {
+ mac.Format("%02X:%02X:%02X:%02X:%02X:%02X",
+ bPhysAddr[0], bPhysAddr[1], bPhysAddr[2],
+ bPhysAddr[3], bPhysAddr[4], bPhysAddr[5]);
+ return true;
+ }
+ else
+ CLog::Log(LOGERROR, "%s - SendArp completed successfully, but mac address has length != 6 (%d)", __FUNCTION__, PhysAddrLen);
+ }
+ else
+ CLog::Log(LOGERROR, "%s - SendArp failed with error (%d)", __FUNCTION__, dwRetVal);
+
+ return false;
+}
+
std::vector<NetworkAccessPoint> CNetworkInterfaceWin32::GetAccessPoints(void)
{
std::vector<NetworkAccessPoint> result;
diff --git a/xbmc/network/windows/NetworkWin32.h b/xbmc/network/windows/NetworkWin32.h
index d163d8f4d4..fd75508b77 100644
--- a/xbmc/network/windows/NetworkWin32.h
+++ b/xbmc/network/windows/NetworkWin32.h
@@ -45,6 +45,8 @@ public:
virtual CStdString GetMacAddress(void);
virtual void GetMacAddressRaw(char rawMac[6]);
+ virtual bool GetHostMacAddress(unsigned long host, CStdString& mac);
+
virtual CStdString GetCurrentIPAddress();
virtual CStdString GetCurrentNetmask();
virtual CStdString GetCurrentDefaultGateway(void);
@@ -72,6 +74,9 @@ public:
// Return the list of interfaces
virtual std::vector<CNetworkInterface*>& GetInterfaceList(void);
+ // Ping remote host
+ virtual bool PingHost(unsigned long host, unsigned int timeout_ms = 2000);
+
// Get/set the nameserver(s)
virtual std::vector<CStdString> GetNameServers(void);
virtual void SetNameServers(std::vector<CStdString> nameServers);
diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp
index f671959111..1063a12bbd 100644
--- a/xbmc/powermanagement/PowerManager.cpp
+++ b/xbmc/powermanagement/PowerManager.cpp
@@ -216,7 +216,12 @@ int CPowerManager::BatteryLevel()
}
void CPowerManager::ProcessEvents()
{
- m_instance->PumpPowerEvents(this);
+ static int nesting = 0;
+
+ if (++nesting == 1)
+ m_instance->PumpPowerEvents(this);
+
+ nesting--;
}
void CPowerManager::OnSleep()
diff --git a/xbmc/settings/MediaSourceSettings.cpp b/xbmc/settings/MediaSourceSettings.cpp
index 7804ac6605..531e586586 100644
--- a/xbmc/settings/MediaSourceSettings.cpp
+++ b/xbmc/settings/MediaSourceSettings.cpp
@@ -28,6 +28,7 @@
#include "utils/URIUtils.h"
#include "utils/XBMCTinyXML.h"
#include "utils/XMLUtils.h"
+#include "network/WakeOnAccess.h"
#define SOURCES_FILE "sources.xml"
#define XML_SOURCES "sources"
@@ -129,6 +130,8 @@ bool CMediaSourceSettings::Save(const std::string &file) const
SetSources(pRoot, "pictures", m_pictureSources, m_defaultPictureSource);
SetSources(pRoot, "files", m_fileSources, m_defaultFileSource);
+ CWakeOnAccess::Get().QueueMACDiscoveryForAllRemotes();
+
return doc.SaveFile(file);
}
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index 0f2b1b2f69..7a3fec292d 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -50,6 +50,7 @@
#endif // defined(TARGET_LINUX)
#include "network/NetworkServices.h"
#include "network/upnp/UPnPSettings.h"
+#include "network/WakeOnAccess.h"
#if defined(TARGET_DARWIN_OSX)
#include "osx/XBMCHelper.h"
#include "cores/AudioEngine/Engines/CoreAudio/CoreAudioHardware.h"
@@ -411,6 +412,7 @@ void CSettings::Uninitialize()
m_settingsManager->UnregisterSubSettings(&CViewStateSettings::Get());
// unregister ISettingsHandler implementations
+ m_settingsManager->UnregisterSettingsHandler(&CWakeOnAccess::Get());
m_settingsManager->UnregisterSettingsHandler(&g_advancedSettings);
m_settingsManager->UnregisterSettingsHandler(&CMediaSourceSettings::Get());
m_settingsManager->UnregisterSettingsHandler(&CPlayerCoreFactory::Get());
@@ -799,6 +801,7 @@ void CSettings::InitializeISettingsHandlers()
#ifdef HAS_UPNP
m_settingsManager->RegisterSettingsHandler(&CUPnPSettings::Get());
#endif
+ m_settingsManager->RegisterSettingsHandler(&CWakeOnAccess::Get());
}
void CSettings::InitializeISubSettings()