Merge pull request #4676 from jmarshallnz/dont_set_scraper_on_tvshow_on_nfo
[vuplus_xbmc] / xbmc / network / Network.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <netinet/in.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
24
25 #include "Network.h"
26 #include "ApplicationMessenger.h"
27 #include "network/NetworkServices.h"
28 #include "utils/log.h"
29 #ifdef TARGET_WINDOWS
30 #include "utils/SystemInfo.h"
31 #include "win32/WIN32Util.h"
32 #include "utils/CharsetConverter.h"
33 #endif
34
35 /* slightly modified in_ether taken from the etherboot project (http://sourceforge.net/projects/etherboot) */
36 bool in_ether (const char *bufp, unsigned char *addr)
37 {
38   if (strlen(bufp) != 17)
39     return false;
40
41   char c;
42   const char *orig;
43   unsigned char *ptr = addr;
44   unsigned val;
45
46   int i = 0;
47   orig = bufp;
48
49   while ((*bufp != '\0') && (i < 6))
50   {
51     val = 0;
52     c = *bufp++;
53
54     if (isdigit(c))
55       val = c - '0';
56     else if (c >= 'a' && c <= 'f')
57       val = c - 'a' + 10;
58     else if (c >= 'A' && c <= 'F')
59       val = c - 'A' + 10;
60     else
61       return false;
62
63     val <<= 4;
64     c = *bufp;
65     if (isdigit(c))
66       val |= c - '0';
67     else if (c >= 'a' && c <= 'f')
68       val |= c - 'a' + 10;
69     else if (c >= 'A' && c <= 'F')
70       val |= c - 'A' + 10;
71     else if (c == ':' || c == '-' || c == 0)
72       val >>= 4;
73     else
74       return false;
75
76     if (c != 0)
77       bufp++;
78
79     *ptr++ = (unsigned char) (val & 0377);
80     i++;
81
82     if (*bufp == ':' || *bufp == '-')
83       bufp++;
84   }
85
86   if (bufp - orig != 17)
87     return false;
88
89   return true;
90 }
91
92 int NetworkAccessPoint::getQuality() const
93 {
94   // Cisco dBm lookup table (partially nonlinear)
95   // Source: "Converting Signal Strength Percentage to dBm Values, 2002"
96   int quality;
97   if (m_dBm >= -10) quality = 100;
98   else if (m_dBm >= -20) quality = 85 + (m_dBm + 20);
99   else if (m_dBm >= -30) quality = 77 + (m_dBm + 30);
100   else if (m_dBm >= -60) quality = 48 + (m_dBm + 60);
101   else if (m_dBm >= -98) quality = 13 + (m_dBm + 98);
102   else if (m_dBm >= -112) quality = 1 + (m_dBm + 112);
103   else quality = 0;
104   return quality;
105 }
106
107 int NetworkAccessPoint::FreqToChannel(float frequency)
108 {
109   int IEEE80211Freq[] = {2412, 2417, 2422, 2427, 2432,
110                          2437, 2442, 2447, 2452, 2457,
111                          2462, 2467, 2472, 2484,
112                          5180, 5200, 5210, 5220, 5240, 5250,
113                          5260, 5280, 5290, 5300, 5320,
114                          5745, 5760, 5765, 5785, 5800, 5805, 5825};
115   int IEEE80211Ch[] =   {   1,    2,    3,    4,    5,
116                             6,    7,    8,    9,   10,
117                            11,   12,   13,   14,
118                            36,   40,   42,   44,   48,   50,
119                            52,   56,   58,   60,   64,
120                           149,  152,  153,  157,  160,  161,  165};
121   // Round frequency to the nearest MHz
122   int mod_chan = (int)(frequency / 1000000 + 0.5f);
123   for (unsigned int i = 0; i < sizeof(IEEE80211Freq) / sizeof(int); ++i)
124   {
125     if (IEEE80211Freq[i] == mod_chan)
126       return IEEE80211Ch[i];
127   }
128   return 0; // unknown
129 }
130
131
132 CNetwork::CNetwork()
133 {
134   CApplicationMessenger::Get().NetworkMessage(SERVICES_UP, 0);
135 }
136
137 CNetwork::~CNetwork()
138 {
139   CApplicationMessenger::Get().NetworkMessage(SERVICES_DOWN, 0);
140 }
141
142 int CNetwork::ParseHex(char *str, unsigned char *addr)
143 {
144    int len = 0;
145
146    while (*str)
147    {
148       int tmp;
149       if (str[1] == 0)
150          return -1;
151       if (sscanf(str, "%02x", (unsigned int *)&tmp) != 1)
152          return -1;
153       addr[len] = tmp;
154       len++;
155       str += 2;
156    }
157
158    return len;
159 }
160
161 CStdString CNetwork::GetHostName(void)
162 {
163   char hostName[128];
164   if (gethostname(hostName, sizeof(hostName)))
165     return CStdString("unknown");
166
167   std::string hostStr;
168 #ifdef TARGET_WINDOWS
169   g_charsetConverter.systemToUtf8(hostName, hostStr);
170 #else
171   hostStr = hostName;
172 #endif
173   return hostStr;
174 }
175
176 CNetworkInterface* CNetwork::GetFirstConnectedInterface()
177 {
178    std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
179    std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
180    while (iter != ifaces.end())
181    {
182       CNetworkInterface* iface = *iter;
183       if (iface && iface->IsConnected())
184          return iface;
185       ++iter;
186    }
187
188    return NULL;
189 }
190
191 bool CNetwork::HasInterfaceForIP(unsigned long address)
192 {
193    unsigned long subnet;
194    unsigned long local;
195    std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
196    std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
197    while (iter != ifaces.end())
198    {
199       CNetworkInterface* iface = *iter;
200       if (iface && iface->IsConnected())
201       {
202          subnet = ntohl(inet_addr(iface->GetCurrentNetmask()));
203          local = ntohl(inet_addr(iface->GetCurrentIPAddress()));
204          if( (address & subnet) == (local & subnet) )
205             return true;
206       }
207       ++iter;
208    }
209
210    return false;
211 }
212
213 bool CNetwork::IsAvailable(bool wait /*= false*/)
214 {
215   if (wait)
216   {
217     // NOTE: Not implemented in linuxport branch as 99.9% of the time
218     //       we have the network setup already.  Trunk code has a busy
219     //       wait for 5 seconds here.
220   }
221
222   std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
223   return (ifaces.size() != 0);
224 }
225
226 bool CNetwork::IsConnected()
227 {
228    return GetFirstConnectedInterface() != NULL;
229 }
230
231 CNetworkInterface* CNetwork::GetInterfaceByName(CStdString& name)
232 {
233    std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
234    std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
235    while (iter != ifaces.end())
236    {
237       CNetworkInterface* iface = *iter;
238       if (iface && iface->GetName().Equals(name))
239          return iface;
240       ++iter;
241    }
242
243    return NULL;
244 }
245
246 void CNetwork::NetworkMessage(EMESSAGE message, int param)
247 {
248   switch( message )
249   {
250     case SERVICES_UP:
251       CLog::Log(LOGDEBUG, "%s - Starting network services",__FUNCTION__);
252       CNetworkServices::Get().Start();
253       break;
254
255     case SERVICES_DOWN:
256       CLog::Log(LOGDEBUG, "%s - Signaling network services to stop",__FUNCTION__);
257       CNetworkServices::Get().Stop(false); // tell network services to stop, but don't wait for them yet
258       CLog::Log(LOGDEBUG, "%s - Waiting for network services to stop",__FUNCTION__);
259       CNetworkServices::Get().Stop(true); // wait for network services to stop
260       break;
261   }
262 }
263
264 bool CNetwork::WakeOnLan(const char* mac)
265 {
266   int i, j, packet;
267   unsigned char ethaddr[8];
268   unsigned char buf [128];
269   unsigned char *ptr;
270
271   // Fetch the hardware address
272   if (!in_ether(mac, ethaddr))
273   {
274     CLog::Log(LOGERROR, "%s - Invalid hardware address specified (%s)", __FUNCTION__, mac);
275     return false;
276   }
277
278   // Setup the socket
279   if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
280   {
281     CLog::Log(LOGERROR, "%s - Unable to create socket (%s)", __FUNCTION__, strerror (errno));
282     return false;
283   }
284  
285   // Set socket options
286   struct sockaddr_in saddr;
287   saddr.sin_family = AF_INET;
288   saddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
289   saddr.sin_port = htons(9);
290
291   unsigned int value = 1;
292   if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char*) &value, sizeof( unsigned int ) ) == SOCKET_ERROR)
293   {
294     CLog::Log(LOGERROR, "%s - Unable to set socket options (%s)", __FUNCTION__, strerror (errno));
295     closesocket(packet);
296     return false;
297   }
298  
299   // Build the magic packet (6 x 0xff + 16 x MAC address)
300   ptr = buf;
301   for (i = 0; i < 6; i++)
302     *ptr++ = 0xff;
303
304   for (j = 0; j < 16; j++)
305     for (i = 0; i < 6; i++)
306       *ptr++ = ethaddr[i];
307  
308   // Send the magic packet
309   if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&saddr, sizeof (saddr)) < 0)
310   {
311     CLog::Log(LOGERROR, "%s - Unable to send magic packet (%s)", __FUNCTION__, strerror (errno));
312     closesocket(packet);
313     return false;
314   }
315
316   closesocket(packet);
317   CLog::Log(LOGINFO, "%s - Magic packet send to '%s'", __FUNCTION__, mac);
318   return true;
319 }
320
321 // ping helper
322 static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, struct timeval& timeOut, bool tryRead)
323 {
324   // set non-blocking
325 #ifdef TARGET_WINDOWS
326   u_long nonblocking = 1;
327   int result = ioctlsocket(soc, FIONBIO, &nonblocking);
328 #else
329   int result = fcntl(soc, F_SETFL, fcntl(soc, F_GETFL) | O_NONBLOCK);
330 #endif
331
332   if (result != 0)
333     return "set non-blocking option failed";
334
335   result = connect(soc, (struct sockaddr *)&addr, sizeof(addr)); // non-blocking connect, will fail ..
336
337   if (result < 0)
338   {
339 #ifdef TARGET_WINDOWS
340     if (WSAGetLastError() != WSAEWOULDBLOCK)
341 #else
342     if (errno != EINPROGRESS)
343 #endif
344       return "unexpected connect fail";
345
346     { // wait for connect to complete
347       fd_set wset;
348       FD_ZERO(&wset); 
349       FD_SET(soc, &wset); 
350
351       result = select(FD_SETSIZE, 0, &wset, 0, &timeOut);
352     }
353
354     if (result < 0)
355       return "select fail";
356
357     if (result == 0) // timeout
358       return ""; // no error
359
360     { // verify socket connection state
361       int err_code = -1;
362       socklen_t code_len = sizeof (err_code);
363
364       result = getsockopt(soc, SOL_SOCKET, SO_ERROR, (char*) &err_code, &code_len);
365
366       if (result != 0)
367         return "getsockopt fail";
368
369       if (err_code != 0)
370         return ""; // no error, just not connected
371     }
372   }
373
374   if (tryRead)
375   {
376     fd_set rset;
377     FD_ZERO(&rset); 
378     FD_SET(soc, &rset); 
379
380     result = select(FD_SETSIZE, &rset, 0, 0, &timeOut);
381
382     if (result > 0)
383     {
384       char message [32];
385
386       result = recv(soc, message, sizeof(message), 0);
387     }
388
389     if (result == 0)
390       return ""; // no reply yet
391
392     if (result < 0)
393       return "recv fail";
394   }
395
396   return 0; // success
397 }
398
399 bool CNetwork::PingHost(unsigned long ipaddr, unsigned short port, unsigned int timeOutMs, bool readability_check)
400 {
401   if (port == 0) // use icmp ping
402     return PingHost (ipaddr, timeOutMs);
403
404   struct sockaddr_in addr; 
405   addr.sin_family = AF_INET; 
406   addr.sin_port = htons(port); 
407   addr.sin_addr.s_addr = ipaddr; 
408
409   SOCKET soc = socket(AF_INET, SOCK_STREAM, 0); 
410
411   const char* err_msg = "invalid socket";
412
413   if (soc != INVALID_SOCKET)
414   {
415     struct timeval tmout; 
416     tmout.tv_sec = timeOutMs / 1000; 
417     tmout.tv_usec = (timeOutMs % 1000) * 1000; 
418
419     err_msg = ConnectHostPort (soc, addr, tmout, readability_check);
420
421     (void) closesocket (soc);
422   }
423
424   if (err_msg && *err_msg)
425   {
426 #ifdef TARGET_WINDOWS
427     CStdString sock_err = CWIN32Util::WUSysMsg(WSAGetLastError());
428 #else
429     CStdString sock_err = strerror(errno);
430 #endif
431
432     CLog::Log(LOGERROR, "%s(%s:%d) - %s (%s)", __FUNCTION__, inet_ntoa(addr.sin_addr), port, err_msg, sock_err.c_str());
433   }
434
435   return err_msg == 0;
436 }
437
438 //creates, binds and listens a tcp socket on the desired port. Set bindLocal to
439 //true to bind to localhost only. The socket will listen over ipv6 if possible
440 //and fall back to ipv4 if ipv6 is not available on the platform.
441 int CreateTCPServerSocket(const int port, const bool bindLocal, const int backlog, const char *callerName)
442 {
443   struct sockaddr_storage addr;
444   int    sock = -1;
445
446 #ifdef WINSOCK_VERSION
447   int yes = 1;
448   int no = 0;
449 #else
450   unsigned int yes = 1;
451   unsigned int no = 0;
452 #endif
453   
454   // first try ipv6
455   if ((sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) >= 0)
456   {
457     // in case we're on ipv6, make sure the socket is dual stacked
458     if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&no, sizeof(no)) < 0)
459     {
460 #ifdef _MSC_VER
461       CStdString sock_err = CWIN32Util::WUSysMsg(WSAGetLastError());
462 #else
463       CStdString sock_err = strerror(errno);
464 #endif
465       CLog::Log(LOGWARNING, "%s Server: Only IPv6 supported (%s)", callerName, sock_err.c_str());
466     }
467
468     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes));
469
470     struct sockaddr_in6 *s6;
471     memset(&addr, 0, sizeof(addr));
472     addr.ss_family = AF_INET6;
473     s6 = (struct sockaddr_in6 *) &addr;
474     s6->sin6_port = htons(port);
475     if (bindLocal)
476       s6->sin6_addr = in6addr_loopback;
477     else
478       s6->sin6_addr = in6addr_any;
479
480     if (bind( sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6)) < 0)
481     {
482       closesocket(sock);
483       sock = -1;
484       CLog::Log(LOGDEBUG, "%s Server: Failed to bind ipv6 serversocket, trying ipv4", callerName);
485     }
486   }
487   
488   // ipv4 fallback
489   if (sock < 0 && (sock = socket(PF_INET, SOCK_STREAM, 0)) >= 0)
490   {
491     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes));
492
493     struct sockaddr_in  *s4;
494     memset(&addr, 0, sizeof(addr));
495     addr.ss_family = AF_INET;
496     s4 = (struct sockaddr_in *) &addr;
497     s4->sin_port = htons(port);
498     if (bindLocal)
499       s4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
500     else
501       s4->sin_addr.s_addr = htonl(INADDR_ANY);
502
503     if (bind( sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0)
504     {
505       closesocket(sock);
506       CLog::Log(LOGERROR, "%s Server: Failed to bind ipv4 serversocket", callerName);
507       return INVALID_SOCKET;
508     }
509   }
510   else if (sock < 0)
511   {
512     CLog::Log(LOGERROR, "%s Server: Failed to create serversocket", callerName);
513     return INVALID_SOCKET;
514   }
515
516   if (listen(sock, backlog) < 0)
517   {
518     closesocket(sock);
519     CLog::Log(LOGERROR, "%s Server: Failed to set listen", callerName);
520     return INVALID_SOCKET;
521   }
522
523   return sock;
524 }
525