version 0.0.2
[fms.git] / src / freenet / trustlistrequester.cpp
1 #include "../../include/freenet/trustlistrequester.h"\r
2 #include "../../include/option.h"\r
3 #include "../../include/stringfunctions.h"\r
4 #include "../../include/freenet/trustlistxml.h"\r
5 \r
6 #ifdef XMEM\r
7         #include <xmem.h>\r
8 #endif\r
9 \r
10 TrustListRequester::TrustListRequester()\r
11 {\r
12         Initialize();\r
13 }\r
14 \r
15 TrustListRequester::TrustListRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
16 {\r
17         Initialize();\r
18 }\r
19 \r
20 void TrustListRequester::FCPConnected()\r
21 {\r
22         m_requesting.clear();\r
23         PopulateIDList();\r
24 }\r
25 \r
26 void TrustListRequester::FCPDisconnected()\r
27 {\r
28         \r
29 }\r
30 \r
31 const bool TrustListRequester::HandleAllData(FCPMessage &message)\r
32 {\r
33         DateTime now;\r
34         SQLite3DB::Statement st;\r
35         std::vector<std::string> idparts;\r
36         long datalength;\r
37         std::vector<char> data;\r
38         TrustListXML xml;\r
39         long identityid;\r
40         long index;\r
41 \r
42         now.SetToGMTime();\r
43         StringFunctions::Split(message["Identifier"],"|",idparts);\r
44         StringFunctions::Convert(message["DataLength"],datalength);\r
45         StringFunctions::Convert(idparts[1],identityid);\r
46         StringFunctions::Convert(idparts[2],index);\r
47 \r
48         // wait for all data to be received from connection\r
49         while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
50         {\r
51                 m_fcp->Update(1);\r
52         }\r
53 \r
54         // if we got disconnected- return immediately\r
55         if(m_fcp->Connected()==false)\r
56         {\r
57                 return false;\r
58         }\r
59 \r
60         // receive the file\r
61         data.resize(datalength);\r
62         m_fcp->ReceiveRaw(&data[0],datalength);\r
63 \r
64         // parse file into xml and update the database\r
65         if(xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
66         {\r
67                 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
68                 // loop through all trust entries in xml and add to database if we don't already know them\r
69                 for(long i=0; i<xml.TrustCount(); i++)\r
70                 {\r
71                         std::string identity;\r
72                         identity=xml.GetIdentity(i);\r
73 \r
74                         //TODO get the trust levels as well\r
75 \r
76                         st.Bind(0,identity);\r
77                         st.Step();\r
78                         if(st.RowReturned()==false)\r
79                         {\r
80                                 m_db->Execute("INSERT INTO tblIdentity(PublicKey,DateAdded) VALUES('"+identity+"','"+now.Format("%Y-%m-%d %H:%M:%S")+"');");\r
81                         }\r
82                         st.Reset();\r
83                 }\r
84 \r
85                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
86                 st.Bind(0,identityid);\r
87                 st.Bind(1,idparts[4]);\r
88                 st.Bind(2,index);\r
89                 st.Step();\r
90                 st.Finalize();\r
91 \r
92                 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,__FUNCTION__" parsed Identity XML file : "+message["Identifier"]);\r
93         }\r
94         else\r
95         {\r
96                 // bad data - mark index\r
97                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
98                 st.Bind(0,identityid);\r
99                 st.Bind(1,idparts[4]);\r
100                 st.Bind(2,index);\r
101                 st.Step();\r
102                 st.Finalize();\r
103 \r
104                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" error parsing TrustList XML file : "+message["Identifier"]);\r
105         }\r
106 \r
107         // remove this identityid from request list\r
108         RemoveFromRequestList(identityid);\r
109 \r
110         return true;\r
111 \r
112 }\r
113 \r
114 const bool TrustListRequester::HandleGetFailed(FCPMessage &message)\r
115 {\r
116         DateTime now;\r
117         SQLite3DB::Statement st;\r
118         std::vector<std::string> idparts;\r
119         long identityid;\r
120         long index;\r
121 \r
122         now.SetToGMTime();\r
123         StringFunctions::Split(message["Identifier"],"|",idparts);\r
124         StringFunctions::Convert(idparts[1],identityid);\r
125         StringFunctions::Convert(idparts[2],index);     \r
126 \r
127         // if this is a fatal error - insert index into database so we won't try to download this index again\r
128         if(message["Fatal"]=="true")\r
129         {\r
130                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
131                 st.Bind(0,identityid);\r
132                 st.Bind(1,idparts[4]);\r
133                 st.Bind(2,index);\r
134                 st.Step();\r
135                 st.Finalize();\r
136 \r
137                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,__FUNCTION__" fatal error requesting "+message["Identifier"]);\r
138         }\r
139 \r
140         // remove this identityid from request list\r
141         RemoveFromRequestList(identityid);\r
142 \r
143         return true;\r
144 \r
145 }\r
146 \r
147 const bool TrustListRequester::HandleMessage(FCPMessage &message)\r
148 {\r
149 \r
150         if(message["Identifier"].find("TrustListRequester")==0)\r
151         {\r
152                 if(message.GetName()=="DataFound")\r
153                 {\r
154                         return true;\r
155                 }\r
156 \r
157                 if(message.GetName()=="AllData")\r
158                 {\r
159                         return HandleAllData(message);\r
160                 }\r
161 \r
162                 if(message.GetName()=="GetFailed")\r
163                 {\r
164                         return HandleGetFailed(message);\r
165                 }\r
166 \r
167                 if(message.GetName()=="IdentifierCollision")\r
168                 {\r
169                         // remove one of the ids from the requesting list\r
170                         long identityid=0;\r
171                         std::vector<std::string> idparts;\r
172                         StringFunctions::Split(message["Identifier"],"|",idparts);\r
173                         StringFunctions::Convert(idparts[1],identityid);\r
174                         RemoveFromRequestList(identityid);\r
175                         return true;\r
176                 }\r
177         }\r
178 \r
179         return false;\r
180 }\r
181 \r
182 void TrustListRequester::Initialize()\r
183 {\r
184         std::string tempval="";\r
185         Option::instance()->Get("MaxIdentityRequests",tempval);\r
186         StringFunctions::Convert(tempval,m_maxrequests);\r
187         if(m_maxrequests<1)\r
188         {\r
189                 m_maxrequests=1;\r
190                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxTrustListRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
191         }\r
192         if(m_maxrequests>100)\r
193         {\r
194                 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxTrustListRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
195         }\r
196         Option::instance()->Get("MessageBase",m_messagebase);\r
197         m_tempdate.SetToGMTime();\r
198 }\r
199 \r
200 void TrustListRequester::PopulateIDList()\r
201 {\r
202         DateTime date;\r
203         int id;\r
204 \r
205         date.SetToGMTime();\r
206 \r
207         // select identities we want to query (we've seen them today and they are publishing trust list) - sort by their trust level (descending) with secondary sort on how long ago we saw them (ascending)\r
208         SQLite3DB::Statement st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey IS NOT NULL AND PublicKey <> '' AND LastSeen>='"+date.Format("%Y-%m-%d")+"' AND PublishTrustList='true' AND LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') ORDER BY LocalMessageTrust+LocalTrustListTrust DESC, LastSeen;");\r
209         st.Step();\r
210 \r
211         m_ids.clear();\r
212 \r
213         while(st.RowReturned())\r
214         {\r
215                 st.ResultInt(0,id);\r
216                 m_ids[id]=false;\r
217                 st.Step();\r
218         }\r
219 }\r
220 \r
221 void TrustListRequester::Process()\r
222 {\r
223         // max is the smaller of the config value or the total number of identities we will request from\r
224         long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
225 \r
226         // try to keep up to max requests going\r
227         if(m_requesting.size()<max)\r
228         {\r
229                 std::map<long,bool>::iterator i=m_ids.begin();\r
230                 while(i!=m_ids.end() && (*i).second==true)\r
231                 {\r
232                         i++;\r
233                 }\r
234 \r
235                 if(i!=m_ids.end())\r
236                 {\r
237                         StartRequest((*i).first);\r
238                 }\r
239                 else\r
240                 {\r
241                         // we requested from all ids in the list, repopulate the list\r
242                         PopulateIDList();\r
243                 }\r
244         }\r
245         // special case - if there were 0 identities on the list when we started then we will never get a chance to repopulate the list\r
246         // this will recheck for ids every minute\r
247         DateTime now;\r
248         now.SetToGMTime();\r
249         if(m_tempdate<(now-(1.0/1440.0)))\r
250         {\r
251                 PopulateIDList();\r
252                 m_tempdate=now;\r
253         }\r
254 \r
255 }\r
256 \r
257 void TrustListRequester::RegisterWithThread(FreenetMasterThread *thread)\r
258 {\r
259         thread->RegisterFCPConnected(this);\r
260         thread->RegisterFCPMessageHandler(this);\r
261         thread->RegisterPeriodicProcessor(this);\r
262 }\r
263 \r
264 void TrustListRequester::RemoveFromRequestList(const long identityid)\r
265 {\r
266         std::vector<long>::iterator i=m_requesting.begin();\r
267         while(i!=m_requesting.end() && (*i)!=identityid)\r
268         {\r
269                 i++;\r
270         }\r
271         if(i!=m_requesting.end())\r
272         {\r
273                 m_requesting.erase(i);\r
274         }\r
275 }\r
276 \r
277 void TrustListRequester::StartRequest(const long identityid)\r
278 {\r
279         DateTime now;\r
280         FCPMessage message;\r
281         std::string publickey;\r
282         int index;\r
283         std::string indexstr;\r
284         std::string identityidstr;\r
285 \r
286         SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
287         st.Bind(0,identityid);\r
288         st.Step();\r
289 \r
290         if(st.RowReturned())\r
291         {\r
292                 st.ResultText(0,publickey);\r
293 \r
294                 now.SetToGMTime();\r
295 \r
296                 SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblTrustListRequests WHERE Day=? AND IdentityID=?;");\r
297                 st2.Bind(0,now.Format("%Y-%m-%d"));\r
298                 st2.Bind(1,identityid);\r
299                 st2.Step();\r
300 \r
301                 index=0;\r
302                 if(st2.RowReturned())\r
303                 {\r
304                         if(st2.ResultNull(0)==false)\r
305                         {\r
306                                 st2.ResultInt(0,index);\r
307                                 index++;\r
308                         }\r
309                 }\r
310                 st2.Finalize();\r
311 \r
312                 StringFunctions::Convert(index,indexstr);\r
313                 StringFunctions::Convert(identityid,identityidstr);\r
314 \r
315                 message.SetName("ClientGet");\r
316                 message["URI"]=publickey+m_messagebase+"|"+now.Format("%Y-%m-%d")+"|TrustList|"+indexstr+".xml";\r
317                 message["Identifier"]="TrustListRequester|"+identityidstr+"|"+indexstr+"|"+message["URI"];\r
318                 message["ReturnType"]="direct";\r
319                 message["MaxSize"]="1000000";                   // 1 MB\r
320 \r
321                 m_fcp->SendMessage(message);\r
322 \r
323                 m_requesting.push_back(identityid);\r
324         }\r
325         st.Finalize();\r
326 \r
327         m_ids[identityid]=true;\r
328 \r
329 }\r