]> git.vomp.tv Git - vompclient-marten.git/commitdiff
WOL support
authorChris Tallon <chris@vomp.tv>
Fri, 6 Apr 2007 17:27:33 +0000 (17:27 +0000)
committerChris Tallon <chris@vomp.tv>
Fri, 6 Apr 2007 17:27:33 +0000 (17:27 +0000)
command.cc
main.cc
objects.mk
vconnect.cc
vdr.cc
vdr.h
wol.cc [new file with mode: 0644]
wol.h [new file with mode: 0644]

index a97c1dbe038b9565346e8e41747eed580261ea19..e1e83e014677253d9fcc7413521d10beba07a3e3 100644 (file)
@@ -769,6 +769,27 @@ void Command::doJustConnected(VConnect* vconnect)
     vdr->setReceiveWindow(2048); // Default
   }
 
+  config = vdr->configLoad("Advanced", "Disable WOL");
+  if (config)
+  {
+    if (!STRCASECMP(config, "Yes"))
+    {
+      logger->log("Command", Log::INFO, "Config says disable WOL");
+      Wol::getInstance()->setEnabled(false);
+    }
+    else
+    {
+      logger->log("Command", Log::INFO, "Config says enable WOL");
+      Wol::getInstance()->setEnabled(true);
+    }
+
+    delete[] config;
+  }
+  else
+  {
+    logger->log("Command", Log::INFO, "By default, enable WOL");
+    Wol::getInstance()->setEnabled(true);
+  }
 
   // config done
 
diff --git a/main.cc b/main.cc
index 9a329fb1d68f14f4cb29d3cbf7024411ac2b699c..f51b75de950cf1a7c4cbbfa51fd1d906013770eb 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -65,6 +65,7 @@ Command* command;
 VDR* vdr;
 Video* video;
 Audio* audio;
+Wol* wol;
 
 // Linux MVP main function and sighandler
 #ifndef WIN32
@@ -88,8 +89,9 @@ int main(int argc, char** argv)
   video      = new VideoMVP();
   viewman    = new ViewMan();
   command    = new Command();
+  wol        = new Wol();
 
-  if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !viewman || !command)
+  if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !viewman || !command || !wol)
   {
     printf("Could not create objects. Memory problems?\n");
     shutdown(1);
@@ -427,6 +429,12 @@ void shutdown(int code)
     logger->log("Core", Log::NOTICE, "Remote module shut down");
   }
 
+  if (wol)
+  {
+    delete wol;
+    logger->log("Core", Log::NOTICE, "WOL module shut down");
+  }
+
   if (logger)
   {
     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
index 8e4bef7bbe79d75813339d3e982a8d1ac35342fe..e9277081f3f80d44085276394db68b5b756841cf 100644 (file)
@@ -1,5 +1,5 @@
 OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o     \
-           message.o messagequeue.o udp.o                                     \
+           message.o messagequeue.o udp.o wol.o                               \
            vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o  \
            directory.o mark.o                                                 \
            player.o playerradio.o vfeed.o afeed.o                             \
index f8ca4bd93a2c364a911a7be8d80224c80eeca70b..52ed9950367f2f2824cfa0fea33b52474701517b 100644 (file)
@@ -117,6 +117,7 @@ void VConnect::threadMethod()
     }
 
     logger->log("VConnect", Log::NOTICE, "Connecting to server at %s", servers[selectedServer].ip);
+    Wol::getInstance()->setWakeUpIP(servers[selectedServer].ip);
     vdr->setServerIP(servers[selectedServer].ip);
 
     // Clear the serverIPs vector
diff --git a/vdr.cc b/vdr.cc
index b0934f59aa43f0847ce0ed11a28c3c83a3eecaff..1c0ee71406e4d98ac8eeb5a120978ffee4a376aa 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
@@ -83,6 +83,7 @@ int VDR::shutdown()
 
 void VDR::findServers(vector<VDRServer>& servers)
 {
+  Wol* wol = Wol::getInstance();
   findingServer = 1;
   char* message = "VOMP";
 
@@ -90,6 +91,7 @@ void VDR::findServers(vector<VDRServer>& servers)
   int haveAtLeastOne = 0;
   int retval;
   int waitType = 1;
+  bool firstloop = true;
   while(findingServer)
   {
     if (waitType == 1)
@@ -98,6 +100,7 @@ void VDR::findServers(vector<VDRServer>& servers)
       ds.init();
       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
       ds.send("255.255.255.255", 3024, message, strlen(message));
+      if(!firstloop) wol->doWakeUp();
     }
     retval = ds.waitforMessage(waitType);
 
@@ -133,6 +136,7 @@ void VDR::findServers(vector<VDRServer>& servers)
     {
       if (haveAtLeastOne) break;
       waitType = 1;
+      firstloop = false;
     }
   }
   sort(servers.begin(), servers.end(), ServerSorter());
diff --git a/vdr.h b/vdr.h
index 4e0e64ce67aa89a5e283f9e81136a357d017578a..a35b3a81fa90a261fd770cfb430d3558e9f75323 100644 (file)
--- a/vdr.h
+++ b/vdr.h
@@ -40,6 +40,7 @@
 #include "rectimer.h"
 #include "recinfo.h"
 #include "mark.h"
+#include "wol.h"
 
 using namespace std;
 
diff --git a/wol.cc b/wol.cc
new file mode 100644 (file)
index 0000000..f9081db
--- /dev/null
+++ b/wol.cc
@@ -0,0 +1,231 @@
+/*
+    Copyright 2006 Matthias Haas <vomp@pompase.net>
+
+    This file is part of VOMP.
+
+    VOMP 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.
+
+    VOMP 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 VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Based on the work by R. Edwards (bob@cs.anu.edu.au) for the wakeonlan stuff
+    Based ont the work of Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> for the arp stuff
+    Thanks to you guys.
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "wol.h"
+
+#define _PATH_PROCNET_ARP "/proc/net/arp"
+
+Wol* Wol::instance = NULL;
+
+Wol::Wol()
+{
+  if (instance) return;
+  instance = this;
+  bEtherKnown = false;
+  wolEnabled = true;
+  logger = Log::getInstance();
+}
+
+Wol::~Wol()
+{
+}
+
+Wol* Wol::getInstance()
+{
+  return instance;
+}
+
+void Wol::setEnabled(bool tEnabled)
+{
+  wolEnabled = tEnabled;
+}
+
+/* Display the contents of the ARP cache in the kernel. */
+int Wol::find_ether(char *name)
+{
+  char ip[100];
+  char line[200];
+  FILE *fp;
+  int num;
+
+  /* Open the PROCps kernel table. */
+  if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL)
+  {
+    perror(_PATH_PROCNET_ARP);
+    return -1;
+  }
+  /* Bypass header -- read until newline */
+  if (fgets(line, sizeof(line), fp) != (char *) NULL)
+  {
+    /* Read the ARP cache entries. */
+    for (; fgets(line, sizeof(line), fp);) {
+      num = sscanf(line, "%s 0x%*x 0x%*x %100s %*100s %*100s\n",
+        ip, ether_addr);
+      if (num < 2)
+        break;
+      /* if the user specified address differs, skip it */
+      if (name[0] && !strcmp(ip, name))
+      {
+        logger->log("Wol", Log::NOTICE, "Found etheraddr %s", ether_addr);
+        return 1;
+      }
+    }
+  }
+  fclose(fp);
+  return 0;
+}
+
+/* Input an Ethernet address and convert to binary. */
+int Wol::convertToBinary(char *bufp, unsigned char *addr)
+{
+    char c, *orig;
+    int i;
+        unsigned char *ptr = addr;
+    unsigned val;
+
+    i = 0;
+    orig = bufp;
+    while ((*bufp != '\0') && (i < ETH_ALEN))
+    {
+        val = 0;
+        c = *bufp++;
+        if (isdigit(c))
+            val = c - '0';
+        else if (c >= 'a' && c <= 'f')
+            val = c - 'a' + 10;
+        else if (c >= 'A' && c <= 'F')
+            val = c - 'A' + 10;
+        else
+        {
+#ifdef DEBUG
+            fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
+#endif
+            errno = EINVAL;
+            return (-1);
+        }
+        val <<= 4;
+        c = *bufp;
+        if (isdigit(c))
+            val |= c - '0';
+        else if (c >= 'a' && c <= 'f')
+            val |= c - 'a' + 10;
+        else if (c >= 'A' && c <= 'F')
+            val |= c - 'A' + 10;
+        else if (c == ':' || c == 0)
+            val >>= 4;
+        else
+        {
+#ifdef DEBUG
+            fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
+#endif
+            errno = EINVAL;
+            return (-1);
+        }
+        if (c != 0)
+            bufp++;
+        *ptr++ = (unsigned char) (val & 0377);
+        i++;
+
+        /* We might get a semicolon here - not required. */
+        if (*bufp == ':')
+        {
+            if (i == ETH_ALEN)
+            {
+                    ;           /* nothing */
+            }
+            bufp++;
+        }
+    }
+    return (0);
+} /* in_ether */
+
+int Wol::doWakeUp()
+{
+  if (!wolEnabled) return -2;
+  if (!bEtherKnown) return -3;
+
+  int i, j;
+  int packet;
+  struct sockaddr_in sap;
+  unsigned char ethaddr[8];
+  unsigned char *ptr;
+  unsigned char buf [128];
+  int optval = 1;
+
+  /* Fetch the hardware address. */
+  if (convertToBinary (ether_addr, ethaddr) < 0)
+  {
+    return (-1);
+  }
+
+  /* setup the packet socket */
+  if ((packet = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
+  {
+    return (-1);
+  }
+
+  /* Set socket options */
+  if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (caddr_t) &optval,
+     sizeof (optval)) < 0)
+  {
+    fprintf (stderr, "setsocket failed %s\n",
+    strerror (errno));
+    close (packet);
+    return (-1);
+  }
+
+  /* Set up broadcast address */
+  sap.sin_family = AF_INET;
+  sap.sin_addr.s_addr = htonl(0xffffffff);        /* broadcast address
+*/
+  sap.sin_port = htons(60000);
+
+  /* Build the message to send - 6 x 0xff then 16 x MAC address */
+  ptr = buf;
+  for (i = 0; i < 6; i++)
+    *ptr++ = 0xff;
+  for (j = 0; j < 16; j++)
+    for (i = 0; i < ETH_ALEN; i++)
+      *ptr++ = ethaddr [i];
+
+  /* Send the packet out */
+  if (sendto (packet, buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0)
+  {
+    fprintf (stderr, " sendto failed, %s\n",
+    strerror(errno));
+    close (packet);
+    return (-1);
+  }
+
+  logger->log("Wol", Log::NOTICE, "Send wakeonlan to server");
+
+  close (packet);
+  return (0);
+}
+
+void Wol::setWakeUpIP(char* ip_addr)
+{
+  if(find_ether(ip_addr))
+  {
+    bEtherKnown = true;
+    logger->log("Wol", Log::NOTICE, "Server IP set");
+  }
+}
+
diff --git a/wol.h b/wol.h
new file mode 100644 (file)
index 0000000..02312a5
--- /dev/null
+++ b/wol.h
@@ -0,0 +1,53 @@
+/*
+    Copyright 2006 Matthias Haas <vomp@pompase.net>
+
+    This file is part of VOMP.
+
+    VOMP 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.
+
+    VOMP 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 VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Based on the work by R. Edwards (bob@cs.anu.edu.au) for the wakeonlan stuff
+    Based ont the work of Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> for the arp stuff
+    Thanks to you guys.
+
+*/
+
+#ifndef WOL_H
+#define WOL_H
+
+#include <stdio.h>
+#include <string.h>
+#include "log.h"
+
+class Wol
+{
+  public:
+    Wol();
+    ~Wol();
+    static Wol* getInstance();
+    int doWakeUp();
+    void setWakeUpIP(char* ip_addr);
+    void setEnabled(bool enabled);
+
+  private:
+    static Wol* instance;
+    int find_ether(char *name);
+    int convertToBinary(char *bufp, unsigned char *addr);
+    char ether_addr[100];
+    bool bEtherKnown;
+    bool wolEnabled;
+    Log* logger;
+};
+
+#endif