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