1 /***************************************************************************
2                            casyncdns.cpp  -  description
3                              -------------------
4     begin                : Mon Jun 10 2002
5     copyright            : (C) 2002-2004 by Mathias Küster
6     email                : mathen@users.berlios.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "casyncdns.h"
19 #include "cnetaddr.h"
20 
21 #include <string.h>
22 
23 #define HOST_LIST_TIMEOUT	60
24 #define HOST_CACHE_TIMEOUT	60
25 
26 /** */
CAsyncDns()27 CAsyncDns::CAsyncDns()
28 {
29 	m_pHostCache = new CStringList<CAsyncDnsEntry>(4);
30 	m_pHostList  = new CStringList<CAsyncDnsEntry>(4);
31 
32 	// start new thread
33 	Start();
34 }
35 
36 /** */
~CAsyncDns()37 CAsyncDns::~CAsyncDns()
38 {
39 	SetInstance(0);
40 
41 	// stop thread
42 	Stop(true);
43 
44 	Lock();
45 
46 	delete m_pHostCache;
47 	m_pHostCache = 0;
48 
49 	delete m_pHostList;
50 	m_pHostList = 0;
51 
52 	UnLock();
53 }
54 
55 /** call from application */
GetHostI4(CString stringHost,struct sockaddr_in * sin,CString * errmsg)56 eAsyncDns CAsyncDns::GetHostI4( CString stringHost, struct sockaddr_in * sin, CString * errmsg )
57 {
58 	CAsyncDnsEntry * AsyncDnsEntry;
59 	eAsyncDns err;
60 
61 	// return if lock failed
62 	if ( TryLock() == false )
63 	{
64 		return eadAGAIN;
65 	}
66 
67 	err = eadERROR;
68 
69 	// sanity check
70 	if ( m_pHostCache && m_pHostList && (stringHost.NotEmpty()) && sin )
71 	{
72 		if ( m_pHostCache->Get( stringHost, &AsyncDnsEntry ) != -1 )
73 		{
74 			// host found in the m_pHostCache list, return first resolved ip
75 			memcpy( sin, &AsyncDnsEntry->m_sin, sizeof(struct sockaddr_in) );
76 			m_pHostCache->Del(stringHost);
77 			err = eadSUCCESS;
78 		}
79 
80 		if ( err == eadERROR )
81 		{
82 			if ( m_pHostList->Get( stringHost, &AsyncDnsEntry ) == -1 )
83 			{
84 				// host not found in the m_pHostList, add it
85 				AsyncDnsEntry = new CAsyncDnsEntry();
86 
87 				AsyncDnsEntry->m_sHost    = stringHost;
88 				AsyncDnsEntry->m_bError   = false;
89 				// set initial timeout
90 				AsyncDnsEntry->m_tTimeout = time(0);
91 
92 				m_pHostList->Add( stringHost, AsyncDnsEntry );
93 
94 				err = eadAGAIN;
95 			}
96 			else if ( AsyncDnsEntry->m_bError == false )
97 			{
98 				// dns query not finished
99 				err = eadAGAIN;
100 			}
101 			else
102 			{
103 				if ( errmsg != 0 )
104 				{
105 					// return error message
106 					*errmsg = AsyncDnsEntry->m_sErrMsg;
107 				}
108 
109 				// remove from hostlist
110 				m_pHostList->Del(AsyncDnsEntry->m_sHost);
111 			}
112 		}
113 	}
114 
115 	UnLock();
116 
117 	return err;
118 }
119 
120 /** */
Thread()121 void CAsyncDns::Thread()
122 {
123 	CAsyncDnsEntry * AsyncDnsEntry = 0;
124 
125 	Lock();
126 
127 	if ( m_pHostCache->Count() > 0 )
128 	{
129 		// check cache timeout to avoid possible list overflows
130 		while ( m_pHostCache->Next( &AsyncDnsEntry ) != 0 )
131 		{
132 			if ( (time(0)-AsyncDnsEntry->m_tTimeout) >= HOST_CACHE_TIMEOUT )
133 			{
134 				// remove entry from m_pHostCache list
135 				m_pHostCache->Del(AsyncDnsEntry->m_sHost);
136 				AsyncDnsEntry = 0;
137 				break;
138 			}
139 		}
140 	}
141 
142 	AsyncDnsEntry = 0;
143 
144 	if ( m_pHostList->Count() > 0 )
145 	{
146 		while ( m_pHostList->Next( &AsyncDnsEntry ) != 0 )
147 		{
148 			if ( AsyncDnsEntry->m_bError == false )
149 			{
150 				// no error
151 				break;
152 			}
153 			else if ( (time(0)-AsyncDnsEntry->m_tTimeout) >= HOST_LIST_TIMEOUT )
154 			{
155 				// timeout, remove host from m_pHostList
156 				m_pHostList->Del(AsyncDnsEntry->m_sHost);
157 				AsyncDnsEntry = 0;
158 				break;
159 			}
160 		}
161 	}
162 
163 	if ( AsyncDnsEntry != 0 )
164 	{
165 		// no error, no timeout -> update entry
166 		CString s = AsyncDnsEntry->m_sHost;
167 		UnLock();
168 		UpdateEntry(s);
169 	}
170 	else
171 	{
172 		UnLock();
173 	}
174 
175 	NanoSleep(50);
176 }
177 
178 /** */
UpdateEntry(CString stringHost)179 void CAsyncDns::UpdateEntry( CString stringHost )
180 {
181 	CAsyncDnsEntry * AsyncDnsEntry = 0;
182 	struct sockaddr_in sin;
183 	bool res;
184 	CString errmsg;
185 
186 	// ask dns for ip
187 	res = CNetAddr::GetHostI4( stringHost.Data(), &sin, &errmsg );
188 
189 	Lock();
190 
191 	if ( m_pHostList->Get( stringHost, &AsyncDnsEntry ) == 0 )
192 	{
193 		if ( !res )
194 		{
195 			// error, update entry
196 			AsyncDnsEntry->m_bError   = true;
197 			// update timeout to avoid list overflow
198 			AsyncDnsEntry->m_tTimeout = time(0);
199 			AsyncDnsEntry->m_sErrMsg = errmsg;
200 		}
201 		else
202 		{
203 			// no error, remove from m_pHostList and update m_pHostCache
204 			AsyncDnsEntry = new CAsyncDnsEntry();
205 
206 			AsyncDnsEntry->m_sHost    = stringHost;
207 			AsyncDnsEntry->m_bError   = false;
208 			// update timeout to avoid list overflow
209 			AsyncDnsEntry->m_tTimeout = time(0);
210 			memcpy( &AsyncDnsEntry->m_sin, &sin, sizeof(struct sockaddr_in) );
211 
212 			m_pHostList->Del(stringHost);
213 			m_pHostCache->Add(stringHost,AsyncDnsEntry);
214 		}
215 	}
216 
217 	UnLock();
218 }
219