]> git.vomp.tv Git - vompclient.git/blob - wol.cc
Fix text corruption in live TV OSD clock
[vompclient.git] / wol.cc
1 /*
2     Copyright 2006 Matthias Haas <vomp@pompase.net>
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
20     Based on the work by R. Edwards (bob@cs.anu.edu.au) for the wakeonlan stuff
21     Based ont the work of Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> for the arp stuff
22     Thanks to you guys.
23 */
24
25 #include <ctype.h>
26 #include <errno.h>
27
28
29 #if !defined(__ANDROID__) && !defined(WIN32)
30 #include <net/ethernet.h>
31 #else
32 #define ETH_ALEN                6
33 #endif
34
35
36 #ifndef WIN32
37 #include <unistd.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #else
41 #include <winsock2.h>
42 #include <errno.h>
43 #include <Ws2tcpip.h>
44 #include <Iphlpapi.h>
45 #endif
46 #include "wol.h"
47 #include "log.h"
48
49 #define _PATH_PROCNET_ARP "/proc/net/arp"
50
51 static const char* TAG = "WOL";
52
53 Wol* Wol::instance = NULL;
54
55 Wol::Wol()
56 {
57   if (instance) return;
58   instance = this;
59   bEtherKnown = false;
60   wolEnabled = true;
61   logger = LogNT::getInstance();
62 #ifdef WIN32
63 //  goo;
64 #endif
65 }
66
67 Wol::~Wol()
68 {
69 }
70
71 Wol* Wol::getInstance()
72 {
73   return instance;
74 }
75
76 void Wol::setEnabled(bool tEnabled)
77 {
78   wolEnabled = tEnabled;
79 }
80 #ifndef WIN32
81 /* Display the contents of the ARP cache in the kernel. */
82 int Wol::find_ether(const char *name)
83 {
84   char ip[100];
85   char line[200];
86   FILE *fp;
87   int num;
88
89   /* Open the PROCps kernel table. */
90   if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL)
91   {
92     perror(_PATH_PROCNET_ARP);
93     return -1;
94   }
95   /* Bypass header -- read until newline */
96   if (fgets(line, sizeof(line), fp) != (char *) NULL)
97   {
98     /* Read the ARP cache entries. */
99     for (; fgets(line, sizeof(line), fp);) {
100       num = sscanf(line, "%s 0x%*x 0x%*x %100s %*100s %*100s\n",
101         ip, ether_addr);
102       if (num < 2)
103         break;
104       /* if the user specified address differs, skip it */
105       if (name[0] && !strcmp(ip, name))
106       {
107         logger->info(TAG, "Found etheraddr {}", ether_addr);
108         fclose(fp);
109         return 1;
110       }
111     }
112   }
113   fclose(fp);
114   return 0;
115 }
116 #else
117 int Wol::find_ether(const char *name)
118 {
119   sockaddr_in sock_address;
120   int sockname_len=sizeof(sock_address);
121   WSAStringToAddress(const_cast<LPSTR>(name),AF_INET,NULL,(sockaddr*)&sock_address,&sockname_len);
122   
123   DWORD ip=sock_address.sin_addr.s_addr;;
124   ULONG size=0;
125   PMIB_IPNETTABLE table;
126
127   GetIpNetTable(NULL,&size,TRUE);
128   table=(PMIB_IPNETTABLE)new char[size];
129   if (table==NULL) return -1;
130   if (GetIpNetTable(table,&size,TRUE)!=NOERROR)
131   {
132       logger->info(TAG, "Error getting IPtable");
133       delete [] table;
134       return -1;
135   }
136   for (int x=0;x<table->dwNumEntries;x++)
137   {
138       if (table->table[x].dwAddr==ip) {
139           char *ethp=ether_addr;
140           for (int i=0;i<table->table[x].dwPhysAddrLen;i++) {
141               ethp+=sprintf(ethp,"%X:",table->table[x].bPhysAddr[i]);
142           }
143           delete [] table;
144           logger->info(TAG, "Found etheraddr {}", ether_addr);
145           return 1;
146       }
147       
148   }
149
150   delete [] table;
151  return 0;
152
153   
154 }
155 #endif
156
157 /* Input an Ethernet address and convert to binary. */
158 int Wol::convertToBinary(char *bufp, unsigned char *addr)
159 {
160     char c;
161 #ifdef DEBUG
162     char* orig = bufp;
163 #endif
164     int i;
165     unsigned char *ptr = addr;
166     unsigned val;
167
168     i = 0;
169     while ((*bufp != '\0') && (i < ETH_ALEN))
170     {
171         val = 0;
172         c = *bufp++;
173         if (isdigit(c))
174             val = c - '0';
175         else if (c >= 'a' && c <= 'f')
176             val = c - 'a' + 10;
177         else if (c >= 'A' && c <= 'F')
178             val = c - 'A' + 10;
179         else
180         {
181 #ifdef DEBUG
182             fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
183 #endif
184             errno = EINVAL;
185             return (-1);
186         }
187         val <<= 4;
188         c = *bufp;
189         if (isdigit(c))
190             val |= c - '0';
191         else if (c >= 'a' && c <= 'f')
192             val |= c - 'a' + 10;
193         else if (c >= 'A' && c <= 'F')
194             val |= c - 'A' + 10;
195         else if (c == ':' || c == 0)
196             val >>= 4;
197         else
198         {
199 #ifdef DEBUG
200             fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
201 #endif
202             errno = EINVAL;
203             return (-1);
204         }
205         if (c != 0)
206             bufp++;
207         *ptr++ = static_cast<unsigned char>(val & 0377);
208         i++;
209
210         /* We might get a semicolon here - not required. */
211         if (*bufp == ':')
212         {
213             if (i == ETH_ALEN)
214             {
215                     ;           /* nothing */
216             }
217             bufp++;
218         }
219     }
220     return (0);
221 } /* in_ether */
222
223 int Wol::doWakeUp()
224 {
225   if (!wolEnabled) return -2;
226   if (!bEtherKnown) return -3;
227
228   int i, j;
229   int packet;
230   struct sockaddr_in sap;
231   unsigned char ethaddr[8];
232   unsigned char *ptr;
233   unsigned char buf [128];
234   int optval = 1;
235
236   /* Fetch the hardware address. */
237   if (convertToBinary (ether_addr, ethaddr) < 0)
238   {
239     return (-1);
240   }
241
242   /* setup the packet socket */
243   if ((packet = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
244   {
245     return (-1);
246   }
247
248   /* Set socket options */
249 #ifndef WIN32
250   if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, static_cast<void*>(&optval),
251      sizeof (optval)) < 0)
252 #else
253   if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char*)&optval,
254      sizeof (optval)) < 0)
255 #endif
256   {
257     fprintf (stderr, "setsocket failed %s\n",
258     strerror (errno));
259     CLOSESOCKET(packet);
260     return (-1);
261   }
262
263   /* Set up broadcast address */
264   sap.sin_family = AF_INET;
265   sap.sin_addr.s_addr = htonl(0xffffffff);        /* broadcast address
266 */
267   sap.sin_port = htons(60000);
268
269   /* Build the message to send - 6 x 0xff then 16 x MAC address */
270   ptr = buf;
271   for (i = 0; i < 6; i++)
272     *ptr++ = 0xff;
273   for (j = 0; j < 16; j++)
274     for (i = 0; i < ETH_ALEN; i++)
275       *ptr++ = ethaddr [i];
276
277   /* Send the packet out */
278 #ifdef WIN32
279   if (sendto(packet, reinterpret_cast<const char*>(buf), 102, 0, reinterpret_cast<struct sockaddr *>(&sap), sizeof (sap)) < 0)
280 #else
281   if (sendto(packet, static_cast<void*>(buf), 102, 0, reinterpret_cast<struct sockaddr *>(&sap), sizeof(sap)) < 0)
282 #endif
283   {
284     fprintf (stderr, " sendto failed, %s\n",
285     strerror(errno));
286     CLOSESOCKET(packet);
287     return (-1);
288   }
289
290   logger->info(TAG, "Send wakeonlan to server");
291
292   CLOSESOCKET(packet);
293   return (0);
294 }
295
296 void Wol::setWakeUpIP(const char* ip_addr)
297 {
298   if(find_ether(ip_addr))
299   {
300     bEtherKnown = true;
301     logger->info(TAG, "Server IP set");
302   }
303 }
304