version 0.3.20
[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 #include <Poco/DateTimeFormatter.h>\r
7 #include <Poco/Timespan.h>\r
8 \r
9 #ifdef XMEM\r
10         #include <xmem.h>\r
11 #endif\r
12 \r
13 TrustListRequester::TrustListRequester()\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 TrustListRequester::TrustListRequester(FCPv2 *fcp):IIndexRequester<long>(fcp)\r
19 {\r
20         Initialize();\r
21 }\r
22 \r
23 const bool TrustListRequester::HandleAllData(FCPMessage &message)\r
24 {\r
25         Poco::DateTime now;\r
26         SQLite3DB::Statement st;\r
27         SQLite3DB::Statement trustst;\r
28         std::vector<std::string> idparts;\r
29         long datalength;\r
30         std::vector<char> data;\r
31         TrustListXML xml;\r
32         long identityid;\r
33         long index;\r
34         int insertcount=0;\r
35         int dayinsertcount=0;\r
36         int previnsertcount=0;\r
37 \r
38         StringFunctions::Split(message["Identifier"],"|",idparts);\r
39         StringFunctions::Convert(message["DataLength"],datalength);\r
40         StringFunctions::Convert(idparts[1],identityid);\r
41         StringFunctions::Convert(idparts[2],index);\r
42 \r
43         // wait for all data to be received from connection\r
44         while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)\r
45         {\r
46                 m_fcp->Update(1);\r
47         }\r
48 \r
49         // if we got disconnected- return immediately\r
50         if(m_fcp->Connected()==false)\r
51         {\r
52                 return false;\r
53         }\r
54 \r
55         // receive the file\r
56         data.resize(datalength);\r
57         if(data.size()>0)\r
58         {\r
59                 m_fcp->ReceiveRaw(&data[0],datalength);\r
60         }\r
61 \r
62         // get count of identities added in last 24 hours\r
63         st=m_db->Prepare("SELECT COUNT(*) FROM tblIdentity WHERE DateAdded>=?;");\r
64         now-=Poco::Timespan(1,0,0,0,0);\r
65         st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
66         st.Step();\r
67         if(st.RowReturned())\r
68         {\r
69                 if(st.ResultNull(0)==false)\r
70                 {\r
71                         st.ResultInt(0,dayinsertcount);\r
72                 }\r
73         }\r
74         else\r
75         {\r
76                 m_log->error("TrustListRequester::HandleAllData couldn't get count of identities added in last 24 hours");\r
77         }\r
78 \r
79         // get count of identities added more than 24 hours ago - if 0 then we will accept more than 100 identities now\r
80         st=m_db->Prepare("SELECT COUNT(*) FROM tblIdentity WHERE DateAdded<?;");\r
81         st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
82         st.Step();\r
83         if(st.RowReturned())\r
84         {\r
85                 if(st.ResultNull(0)==false)\r
86                 {\r
87                         st.ResultInt(0,previnsertcount);\r
88                 }\r
89         }\r
90         else\r
91         {\r
92                 m_log->error("TrustListRequester::HandleAllData couldn't get count of identities added more than 24 hours ago");\r
93         }\r
94 \r
95         now=Poco::DateTime();\r
96 \r
97         // parse file into xml and update the database\r
98         if(data.size()>0 && xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
99         {\r
100                 // find the identity name and public key of the identity publishing the trust list\r
101                 std::string publisherid="";\r
102                 st=m_db->Prepare("SELECT Name,PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
103                 st.Bind(0,identityid);\r
104                 st.Step();\r
105                 if(st.RowReturned())\r
106                 {\r
107                         std::string publishername="";\r
108                         std::string publisherpublickey="";\r
109                         st.ResultText(0,publishername);\r
110                         st.ResultText(1,publisherpublickey);\r
111                         publisherid=publishername;\r
112                         if(publisherpublickey.size()>4)\r
113                         {\r
114                                 publisherid+=publisherpublickey.substr(3,44);\r
115                         }\r
116                 }\r
117                 st.Finalize();\r
118 \r
119                 // drop all existing peer trust from this identity - we will rebuild it when we go through each trust in the xml file\r
120                 st=m_db->Prepare("DELETE FROM tblPeerTrust WHERE IdentityID=?;");\r
121                 st.Bind(0,identityid);\r
122                 st.Step();\r
123                 st.Finalize();\r
124 \r
125                 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
126                 trustst=m_db->Prepare("INSERT INTO tblPeerTrust(IdentityID,TargetIdentityID,MessageTrust,TrustListTrust,MessageTrustComment,TrustListTrustComment) VALUES(?,?,?,?,?,?);");\r
127                 \r
128                 SQLite3DB::Statement idinsert=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");\r
129                 \r
130                 // loop through all trust entries in xml and add to database if we don't already know them\r
131                 for(long i=0; i<xml.TrustCount(); i++)\r
132                 {\r
133                         int id=-1;\r
134                         std::string identity;\r
135                         std::string messagetrustcomment="";\r
136                         std::string trustlisttrustcomment="";\r
137                         identity=xml.GetIdentity(i);\r
138 \r
139                         st.Bind(0,identity);\r
140                         st.Step();\r
141                         if(st.RowReturned()==false)\r
142                         {\r
143                                 if(insertcount<50 && (dayinsertcount<100 || previnsertcount==0))\r
144                                 {\r
145                                         idinsert.Bind(0,identity);\r
146                                         idinsert.Bind(1,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
147                                         idinsert.Bind(2,"trust list of "+publisherid);\r
148                                         idinsert.Step(true);\r
149                                         id=idinsert.GetLastInsertRowID();\r
150                                         idinsert.Reset();\r
151                                 }\r
152                                 insertcount++;\r
153                                 dayinsertcount++;\r
154                         }\r
155                         else\r
156                         {\r
157                                 st.ResultInt(0,id);\r
158                         }\r
159                         st.Reset();\r
160 \r
161                         //insert trust for this identity\r
162                         if(id!=-1)\r
163                         {\r
164                                 trustst.Bind(0,identityid);\r
165                                 trustst.Bind(1,id);\r
166                                 if(xml.GetMessageTrust(i)==-1)\r
167                                 {\r
168                                         trustst.Bind(2);\r
169                                 }\r
170                                 else\r
171                                 {\r
172                                         trustst.Bind(2,xml.GetMessageTrust(i));\r
173                                 }\r
174                                 if(xml.GetTrustListTrust(i)==-1)\r
175                                 {\r
176                                         trustst.Bind(3);\r
177                                 }\r
178                                 else\r
179                                 {\r
180                                         trustst.Bind(3,xml.GetTrustListTrust(i));\r
181                                 }\r
182                                 messagetrustcomment=xml.GetMessageTrustComment(i);\r
183                                 trustlisttrustcomment=xml.GetTrustListTrustComment(i);\r
184                                 // limit comments to 50 characters each\r
185                                 if(messagetrustcomment.size()>50)\r
186                                 {\r
187                                         messagetrustcomment.erase(50);\r
188                                 }\r
189                                 if(trustlisttrustcomment.size()>50)\r
190                                 {\r
191                                         trustlisttrustcomment.erase(50);\r
192                                 }\r
193                                 trustst.Bind(4,messagetrustcomment);\r
194                                 trustst.Bind(5,trustlisttrustcomment);\r
195                                 trustst.Step();\r
196                                 trustst.Reset();\r
197                         }\r
198                 }\r
199 \r
200                 trustst.Finalize();\r
201                 st.Finalize();\r
202 \r
203                 if(insertcount>=50)\r
204                 {\r
205                         m_log->warning("TrustListRequester::HandleAllData TrustList contained more than 50 new identities : "+message["Identifier"]);\r
206                 }\r
207                 if(dayinsertcount>=100 && previnsertcount>0)\r
208                 {\r
209                         m_log->warning("TrustListRequester::HandleAllData TrustList would have inserted more than 100 new identities in the last 24 hours : "+message["Identifier"]);\r
210                 }\r
211 \r
212                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
213                 st.Bind(0,identityid);\r
214                 st.Bind(1,idparts[4]);\r
215                 st.Bind(2,index);\r
216                 st.Step();\r
217                 st.Finalize();\r
218 \r
219                 m_log->debug("TrustListRequester::HandleAllData parsed TrustList XML file : "+message["Identifier"]);\r
220         }\r
221         else\r
222         {\r
223                 // bad data - mark index\r
224                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
225                 st.Bind(0,identityid);\r
226                 st.Bind(1,idparts[4]);\r
227                 st.Bind(2,index);\r
228                 st.Step();\r
229                 st.Finalize();\r
230 \r
231                 m_log->error("TrustListRequester::HandleAllData error parsing TrustList XML file : "+message["Identifier"]);\r
232         }\r
233 \r
234         // remove this identityid from request list\r
235         RemoveFromRequestList(identityid);\r
236 \r
237         return true;\r
238 \r
239 }\r
240 \r
241 const bool TrustListRequester::HandleGetFailed(FCPMessage &message)\r
242 {\r
243         SQLite3DB::Statement st;\r
244         std::vector<std::string> idparts;\r
245         long identityid;\r
246         long index;\r
247 \r
248         StringFunctions::Split(message["Identifier"],"|",idparts);\r
249         StringFunctions::Convert(idparts[1],identityid);\r
250         StringFunctions::Convert(idparts[2],index);     \r
251 \r
252         // if this is a fatal error - insert index into database so we won't try to download this index again\r
253         if(message["Fatal"]=="true")\r
254         {\r
255                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'false');");\r
256                 st.Bind(0,identityid);\r
257                 st.Bind(1,idparts[4]);\r
258                 st.Bind(2,index);\r
259                 st.Step();\r
260                 st.Finalize();\r
261 \r
262                 m_log->error("TrustListRequester::HandleGetFailed fatal error requesting "+message["Identifier"]);\r
263         }\r
264 \r
265         // remove this identityid from request list\r
266         RemoveFromRequestList(identityid);\r
267 \r
268         return true;\r
269 \r
270 }\r
271 \r
272 void TrustListRequester::Initialize()\r
273 {\r
274         std::string tempval="";\r
275         m_fcpuniquename="TrustListRequester";\r
276 \r
277         m_maxrequests=0;\r
278         Option::Instance()->GetInt("MaxIdentityRequests",m_maxrequests);\r
279         if(m_maxrequests<1)\r
280         {\r
281                 m_maxrequests=1;\r
282                 m_log->error("Option MaxTrustListRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
283         }\r
284         if(m_maxrequests>100)\r
285         {\r
286                 m_log->warning("Option MaxTrustListRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
287         }\r
288         m_tempdate=Poco::Timestamp();\r
289 }\r
290 \r
291 void TrustListRequester::PopulateIDList()\r
292 {\r
293         Poco::DateTime date;\r
294         int id;\r
295         std::string sql;\r
296 \r
297         // 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
298         sql="SELECT IdentityID FROM tblIdentity ";\r
299         sql+="WHERE Name IS NOT NULL AND Name <> '' AND PublicKey IS NOT NULL AND PublicKey <> '' AND LastSeen>='"+Poco::DateTimeFormatter::format(date,"%Y-%m-%d")+"' AND PublishTrustList='true' AND LocalTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinLocalTrustListTrust') AND ( PeerTrustListTrust IS NULL OR PeerTrustListTrust>=(SELECT OptionValue FROM tblOption WHERE Option='MinPeerTrustListTrust') )";\r
300         sql+="ORDER BY LocalTrustListTrust DESC, LastSeen;";\r
301 \r
302         SQLite3DB::Statement st=m_db->Prepare(sql);\r
303         st.Step();\r
304 \r
305         m_ids.clear();\r
306 \r
307         while(st.RowReturned())\r
308         {\r
309                 st.ResultInt(0,id);\r
310                 m_ids[id]=false;\r
311                 st.Step();\r
312         }\r
313 }\r
314 \r
315 void TrustListRequester::StartRequest(const long &identityid)\r
316 {\r
317         Poco::DateTime now;\r
318         FCPMessage message;\r
319         std::string publickey;\r
320         int index;\r
321         std::string indexstr;\r
322         std::string identityidstr;\r
323 \r
324         SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
325         st.Bind(0,identityid);\r
326         st.Step();\r
327 \r
328         if(st.RowReturned())\r
329         {\r
330                 st.ResultText(0,publickey);\r
331 \r
332                 SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblTrustListRequests WHERE Day=? AND IdentityID=?;");\r
333                 st2.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d"));\r
334                 st2.Bind(1,identityid);\r
335                 st2.Step();\r
336 \r
337                 index=0;\r
338                 if(st2.RowReturned())\r
339                 {\r
340                         if(st2.ResultNull(0)==false)\r
341                         {\r
342                                 st2.ResultInt(0,index);\r
343                                 index++;\r
344                         }\r
345                 }\r
346                 st2.Finalize();\r
347 \r
348                 StringFunctions::Convert(index,indexstr);\r
349                 StringFunctions::Convert(identityid,identityidstr);\r
350 \r
351                 message.SetName("ClientGet");\r
352                 message["URI"]=publickey+m_messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"|TrustList|"+indexstr+".xml";\r
353                 message["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|"+message["URI"];\r
354                 message["ReturnType"]="direct";\r
355                 message["MaxSize"]="1000000";                   // 1 MB\r
356 \r
357                 m_fcp->SendMessage(message);\r
358 \r
359                 m_requesting.push_back(identityid);\r
360         }\r
361         st.Finalize();\r
362 \r
363         m_ids[identityid]=true;\r
364 \r
365 }\r