From baf2c24a93a3a26ce7c40ce6cab25e7b44d91636 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Fri, 6 Apr 2007 17:27:33 +0000 Subject: [PATCH] WOL support --- command.cc | 21 +++++ main.cc | 10 ++- objects.mk | 2 +- vconnect.cc | 1 + vdr.cc | 4 + vdr.h | 1 + wol.cc | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++ wol.h | 53 ++++++++++++ 8 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 wol.cc create mode 100644 wol.h diff --git a/command.cc b/command.cc index a97c1db..e1e83e0 100644 --- a/command.cc +++ b/command.cc @@ -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 9a329fb..f51b75d 100644 --- 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"); diff --git a/objects.mk b/objects.mk index 8e4bef7..e927708 100644 --- a/objects.mk +++ b/objects.mk @@ -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 \ diff --git a/vconnect.cc b/vconnect.cc index f8ca4bd..52ed995 100644 --- a/vconnect.cc +++ b/vconnect.cc @@ -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 b0934f5..1c0ee71 100644 --- a/vdr.cc +++ b/vdr.cc @@ -83,6 +83,7 @@ int VDR::shutdown() void VDR::findServers(vector& servers) { + Wol* wol = Wol::getInstance(); findingServer = 1; char* message = "VOMP"; @@ -90,6 +91,7 @@ void VDR::findServers(vector& 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& 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& servers) { if (haveAtLeastOne) break; waitType = 1; + firstloop = false; } } sort(servers.begin(), servers.end(), ServerSorter()); diff --git a/vdr.h b/vdr.h index 4e0e64c..a35b3a8 100644 --- 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 index 0000000..f9081db --- /dev/null +++ b/wol.cc @@ -0,0 +1,231 @@ +/* + Copyright 2006 Matthias Haas + + 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, for the arp stuff + Thanks to you guys. +*/ + +#include +#include +#include +#include +#include +#include +#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 index 0000000..02312a5 --- /dev/null +++ b/wol.h @@ -0,0 +1,53 @@ +/* + Copyright 2006 Matthias Haas + + 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, for the arp stuff + Thanks to you guys. + +*/ + +#ifndef WOL_H +#define WOL_H + +#include +#include +#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 -- 2.39.5