]> git.vomp.tv Git - vompclient.git/blob - wol.cc
6b23680f1a01f9c320bbbbb171e1968538a6db3a
[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 Wol* Wol::instance = NULL;
52
53 Wol::Wol()
54 {
55   if (instance) return;
56   instance = this;
57   bEtherKnown = false;
58   wolEnabled = true;
59   logger = Log::getInstance();
60 #ifdef WIN32
61 //  goo;
62 #endif
63 }
64
65 Wol::~Wol()
66 {
67 }
68
69 Wol* Wol::getInstance()
70 {
71   return instance;
72 }
73
74 void Wol::setEnabled(bool tEnabled)
75 {
76   wolEnabled = tEnabled;
77 }
78 #ifndef WIN32
79 /* Display the contents of the ARP cache in the kernel. */
80 int Wol::find_ether(char *name)
81 {
82   char ip[100];
83   char line[200];
84   FILE *fp;
85   int num;
86
87   /* Open the PROCps kernel table. */
88   if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL)
89   {
90     perror(_PATH_PROCNET_ARP);
91     return -1;
92   }
93   /* Bypass header -- read until newline */
94   if (fgets(line, sizeof(line), fp) != (char *) NULL)
95   {
96     /* Read the ARP cache entries. */
97     for (; fgets(line, sizeof(line), fp);) {
98       num = sscanf(line, "%s 0x%*x 0x%*x %100s %*100s %*100s\n",
99         ip, ether_addr);
100       if (num < 2)
101         break;
102       /* if the user specified address differs, skip it */
103       if (name[0] && !strcmp(ip, name))
104       {
105         logger->log("Wol", Log::NOTICE, "Found etheraddr %s", ether_addr);
106         return 1;
107       }
108     }
109   }
110   fclose(fp);
111   return 0;
112 }
113 #else
114 int Wol::find_ether(char *name)
115 {
116   sockaddr_in sock_address;
117   int sockname_len=sizeof(sock_address);
118   WSAStringToAddress(name,AF_INET,NULL,(sockaddr*)&sock_address,&sockname_len);
119   
120   DWORD ip=sock_address.sin_addr.s_addr;;
121   ULONG size=0;
122   PMIB_IPNETTABLE table;
123
124   GetIpNetTable(NULL,&size,TRUE);
125   table=(PMIB_IPNETTABLE)new char[size];
126   if (table==NULL) return -1;
127   if (GetIpNetTable(table,&size,TRUE)!=NOERROR)
128   {
129       logger->log("Wol", Log::NOTICE, "Error getting IPtable");
130       delete [] table;
131       return -1;
132   }
133   for (int x=0;x<table->dwNumEntries;x++)
134   {
135       if (table->table[x].dwAddr==ip) {
136           char *ethp=ether_addr;
137           for (int i=0;i<table->table[x].dwPhysAddrLen;i++) {
138               ethp+=sprintf(ethp,"%X:",table->table[x].bPhysAddr[i]);
139           }
140           delete [] table;
141           logger->log("Wol", Log::NOTICE, "Found etheraddr %s", ether_addr);
142           return 1;
143       }
144       
145   }
146
147   delete [] table;
148  return 0;
149
150   
151 }
152 #endif
153
154 /* Input an Ethernet address and convert to binary. */
155 int Wol::convertToBinary(char *bufp, unsigned char *addr)
156 {
157     char c, *orig;
158     int i;
159         unsigned char *ptr = addr;
160     unsigned val;
161
162     i = 0;
163     orig = bufp;
164     while ((*bufp != '\0') && (i < ETH_ALEN))
165     {
166         val = 0;
167         c = *bufp++;
168         if (isdigit(c))
169             val = c - '0';
170         else if (c >= 'a' && c <= 'f')
171             val = c - 'a' + 10;
172         else if (c >= 'A' && c <= 'F')
173             val = c - 'A' + 10;
174         else
175         {
176 #ifdef DEBUG
177             fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
178 #endif
179             errno = EINVAL;
180             return (-1);
181         }
182         val <<= 4;
183         c = *bufp;
184         if (isdigit(c))
185             val |= c - '0';
186         else if (c >= 'a' && c <= 'f')
187             val |= c - 'a' + 10;
188         else if (c >= 'A' && c <= 'F')
189             val |= c - 'A' + 10;
190         else if (c == ':' || c == 0)
191             val >>= 4;
192         else
193         {
194 #ifdef DEBUG
195             fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
196 #endif
197             errno = EINVAL;
198             return (-1);
199         }
200         if (c != 0)
201             bufp++;
202         *ptr++ = (unsigned char) (val & 0377);
203         i++;
204
205         /* We might get a semicolon here - not required. */
206         if (*bufp == ':')
207         {
208             if (i == ETH_ALEN)
209             {
210                     ;           /* nothing */
211             }
212             bufp++;
213         }
214     }
215     return (0);
216 } /* in_ether */
217
218 int Wol::doWakeUp()
219 {
220   if (!wolEnabled) return -2;
221   if (!bEtherKnown) return -3;
222
223   int i, j;
224   int packet;
225   struct sockaddr_in sap;
226   unsigned char ethaddr[8];
227   unsigned char *ptr;
228   unsigned char buf [128];
229   int optval = 1;
230
231   /* Fetch the hardware address. */
232   if (convertToBinary (ether_addr, ethaddr) < 0)
233   {
234     return (-1);
235   }
236
237   /* setup the packet socket */
238   if ((packet = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
239   {
240     return (-1);
241   }
242
243   /* Set socket options */
244 #ifndef WIN32
245   if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (caddr_t) &optval,
246      sizeof (optval)) < 0)
247 #else
248   if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char*)&optval,
249      sizeof (optval)) < 0)
250 #endif
251   {
252     fprintf (stderr, "setsocket failed %s\n",
253     strerror (errno));
254     CLOSESOCKET(packet);
255     return (-1);
256   }
257
258   /* Set up broadcast address */
259   sap.sin_family = AF_INET;
260   sap.sin_addr.s_addr = htonl(0xffffffff);        /* broadcast address
261 */
262   sap.sin_port = htons(60000);
263
264   /* Build the message to send - 6 x 0xff then 16 x MAC address */
265   ptr = buf;
266   for (i = 0; i < 6; i++)
267     *ptr++ = 0xff;
268   for (j = 0; j < 16; j++)
269     for (i = 0; i < ETH_ALEN; i++)
270       *ptr++ = ethaddr [i];
271
272   /* Send the packet out */
273   if (sendto (packet,(char*) buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0)
274   {
275     fprintf (stderr, " sendto failed, %s\n",
276     strerror(errno));
277     CLOSESOCKET(packet);
278     return (-1);
279   }
280
281   logger->log("Wol", Log::NOTICE, "Send wakeonlan to server");
282
283   CLOSESOCKET(packet);
284   return (0);
285 }
286
287 void Wol::setWakeUpIP(char* ip_addr)
288 {
289   if(find_ether(ip_addr))
290   {
291     bEtherKnown = true;
292     logger->log("Wol", Log::NOTICE, "Server IP set");
293   }
294 }
295