Merge pull request #4775 from jmarshallnz/empty_episode_playcount
[vuplus_xbmc] / xbmc / network / DNSNameCache.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 "DNSNameCache.h"
22 #include "threads/SingleLock.h"
23 #include "utils/log.h"
24 #include "utils/StringUtils.h"
25
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29
30 CDNSNameCache g_DNSCache;
31
32 CCriticalSection CDNSNameCache::m_critical;
33
34 CDNSNameCache::CDNSNameCache(void)
35 {}
36
37 CDNSNameCache::~CDNSNameCache(void)
38 {}
39
40 bool CDNSNameCache::Lookup(const CStdString& strHostName, CStdString& strIpAddress)
41 {
42   if (strHostName.empty() && strIpAddress.empty())
43     return false;
44
45   // first see if this is already an ip address
46   unsigned long address = inet_addr(strHostName.c_str());
47   strIpAddress.clear();
48
49   if (address != INADDR_NONE)
50   {
51     strIpAddress = StringUtils::Format("%d.%d.%d.%d", (address & 0xFF), (address & 0xFF00) >> 8, (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24 );
52     return true;
53   }
54
55   // check if there's a custom entry or if it's already cached
56   if(g_DNSCache.GetCached(strHostName, strIpAddress))
57     return true;
58
59 #ifndef TARGET_WINDOWS
60   // perform netbios lookup (win32 is handling this via gethostbyname)
61   char nmb_ip[100];
62   char line[200];
63
64   CStdString cmd = "nmblookup " + strHostName;
65   FILE* fp = popen(cmd, "r");
66   if (fp)
67   {
68     while (fgets(line, sizeof line, fp))
69     {
70       if (sscanf(line, "%99s *<00>\n", nmb_ip))
71       {
72         if (inet_addr(nmb_ip) != INADDR_NONE)
73           strIpAddress = nmb_ip;
74       }
75     }
76     pclose(fp);
77   }
78
79   if (!strIpAddress.empty())
80   {
81     g_DNSCache.Add(strHostName, strIpAddress);
82     return true;
83   }
84 #endif
85
86   // perform dns lookup
87   struct hostent *host = gethostbyname(strHostName.c_str());
88   if (host && host->h_addr_list[0])
89   {
90     strIpAddress = StringUtils::Format("%d.%d.%d.%d",
91                                        (unsigned char)host->h_addr_list[0][0],
92                                        (unsigned char)host->h_addr_list[0][1],
93                                        (unsigned char)host->h_addr_list[0][2],
94                                        (unsigned char)host->h_addr_list[0][3]);
95     g_DNSCache.Add(strHostName, strIpAddress);
96     return true;
97   }
98
99   CLog::Log(LOGERROR, "Unable to lookup host: '%s'", strHostName.c_str());
100   return false;
101 }
102
103 bool CDNSNameCache::GetCached(const CStdString& strHostName, CStdString& strIpAddress)
104 {
105   CSingleLock lock(m_critical);
106
107   // loop through all DNSname entries and see if strHostName is cached
108   for (int i = 0; i < (int)g_DNSCache.m_vecDNSNames.size(); ++i)
109   {
110     CDNSName& DNSname = g_DNSCache.m_vecDNSNames[i];
111     if ( DNSname.m_strHostName == strHostName )
112     {
113       strIpAddress = DNSname.m_strIpAddress;
114       return true;
115     }
116   }
117
118   // not cached
119   return false;
120 }
121
122 void CDNSNameCache::Add(const CStdString &strHostName, const CStdString &strIpAddress)
123 {
124   CDNSName dnsName;
125
126   dnsName.m_strHostName = strHostName;
127   dnsName.m_strIpAddress  = strIpAddress;
128
129   CSingleLock lock(m_critical);
130   g_DNSCache.m_vecDNSNames.push_back(dnsName);
131 }
132