version 0.3.29
[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(SQLite3DB::DB *db):IIndexRequester<long>(db)\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 TrustListRequester::TrustListRequester(SQLite3DB::DB *db, FCPv2::Connection *fcp):IIndexRequester<long>(db,fcp)\r
19 {\r
20         Initialize();\r
21 }\r
22 \r
23 const bool TrustListRequester::HandleAllData(FCPv2::Message &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         m_fcp->WaitForBytes(1000,datalength);\r
45 \r
46         // if we got disconnected- return immediately\r
47         if(m_fcp->IsConnected()==false)\r
48         {\r
49                 return false;\r
50         }\r
51 \r
52         // receive the file\r
53         m_fcp->Receive(data,datalength);\r
54 \r
55         // get count of identities added in last 24 hours\r
56         st=m_db->Prepare("SELECT COUNT(*) FROM tblIdentity WHERE DateAdded>=?;");\r
57         now-=Poco::Timespan(1,0,0,0,0);\r
58         st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
59         st.Step();\r
60         if(st.RowReturned())\r
61         {\r
62                 if(st.ResultNull(0)==false)\r
63                 {\r
64                         st.ResultInt(0,dayinsertcount);\r
65                 }\r
66         }\r
67         else\r
68         {\r
69                 m_log->error("TrustListRequester::HandleAllData couldn't get count of identities added in last 24 hours");\r
70         }\r
71 \r
72         // get count of identities added more than 24 hours ago - if 0 then we will accept more than 100 identities now\r
73         st=m_db->Prepare("SELECT COUNT(*) FROM tblIdentity WHERE DateAdded<?;");\r
74         st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
75         st.Step();\r
76         if(st.RowReturned())\r
77         {\r
78                 if(st.ResultNull(0)==false)\r
79                 {\r
80                         st.ResultInt(0,previnsertcount);\r
81                 }\r
82         }\r
83         else\r
84         {\r
85                 m_log->error("TrustListRequester::HandleAllData couldn't get count of identities added more than 24 hours ago");\r
86         }\r
87 \r
88         now=Poco::DateTime();\r
89 \r
90         // parse file into xml and update the database\r
91         if(data.size()>0 && xml.ParseXML(std::string(data.begin(),data.end()))==true)\r
92         {\r
93                 // find the identity name and public key of the identity publishing the trust list\r
94                 std::string publisherid="";\r
95                 st=m_db->Prepare("SELECT Name,PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
96                 st.Bind(0,identityid);\r
97                 st.Step();\r
98                 if(st.RowReturned())\r
99                 {\r
100                         std::string publishername="";\r
101                         std::string publisherpublickey="";\r
102                         st.ResultText(0,publishername);\r
103                         st.ResultText(1,publisherpublickey);\r
104                         publisherid=publishername;\r
105                         if(publisherpublickey.size()>4)\r
106                         {\r
107                                 publisherid+=publisherpublickey.substr(3,44);\r
108                         }\r
109                 }\r
110                 st.Finalize();\r
111 \r
112                 m_db->Execute("BEGIN;");\r
113 \r
114                 // drop all existing peer trust from this identity - we will rebuild it when we go through each trust in the xml file\r
115                 st=m_db->Prepare("DELETE FROM tblPeerTrust WHERE IdentityID=?;");\r
116                 st.Bind(0,identityid);\r
117                 st.Step();\r
118                 st.Finalize();\r
119 \r
120                 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");\r
121                 trustst=m_db->Prepare("INSERT INTO tblPeerTrust(IdentityID,TargetIdentityID,MessageTrust,TrustListTrust,MessageTrustComment,TrustListTrustComment) VALUES(?,?,?,?,?,?);");\r
122                 \r
123                 SQLite3DB::Statement idinsert=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");\r
124                 \r
125                 // loop through all trust entries in xml and add to database if we don't already know them\r
126                 for(long i=0; i<xml.TrustCount(); i++)\r
127                 {\r
128                         int id=-1;\r
129                         std::string identity;\r
130                         std::string messagetrustcomment="";\r
131                         std::string trustlisttrustcomment="";\r
132                         identity=xml.GetIdentity(i);\r
133 \r
134                         st.Bind(0,identity);\r
135                         st.Step();\r
136                         if(st.RowReturned()==false)\r
137                         {\r
138                                 if(insertcount<50 && (dayinsertcount<100 || previnsertcount==0))\r
139                                 {\r
140                                         idinsert.Bind(0,identity);\r
141                                         idinsert.Bind(1,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));\r
142                                         idinsert.Bind(2,"trust list of "+publisherid);\r
143                                         idinsert.Step(true);\r
144                                         id=idinsert.GetLastInsertRowID();\r
145                                         idinsert.Reset();\r
146                                 }\r
147                                 insertcount++;\r
148                                 dayinsertcount++;\r
149                         }\r
150                         else\r
151                         {\r
152                                 st.ResultInt(0,id);\r
153                         }\r
154                         st.Reset();\r
155 \r
156                         //insert trust for this identity\r
157                         if(id!=-1)\r
158                         {\r
159                                 trustst.Bind(0,identityid);\r
160                                 trustst.Bind(1,id);\r
161                                 if(xml.GetMessageTrust(i)==-1)\r
162                                 {\r
163                                         trustst.Bind(2);\r
164                                 }\r
165                                 else\r
166                                 {\r
167                                         trustst.Bind(2,xml.GetMessageTrust(i));\r
168                                 }\r
169                                 if(xml.GetTrustListTrust(i)==-1)\r
170                                 {\r
171                                         trustst.Bind(3);\r
172                                 }\r
173                                 else\r
174                                 {\r
175                                         trustst.Bind(3,xml.GetTrustListTrust(i));\r
176                                 }\r
177                                 messagetrustcomment=xml.GetMessageTrustComment(i);\r
178                                 trustlisttrustcomment=xml.GetTrustListTrustComment(i);\r
179                                 // limit comments to 50 characters each\r
180                                 if(messagetrustcomment.size()>50)\r
181                                 {\r
182                                         messagetrustcomment.erase(50);\r
183                                 }\r
184                                 if(trustlisttrustcomment.size()>50)\r
185                                 {\r
186                                         trustlisttrustcomment.erase(50);\r
187                                 }\r
188                                 trustst.Bind(4,messagetrustcomment);\r
189                                 trustst.Bind(5,trustlisttrustcomment);\r
190                                 trustst.Step();\r
191                                 trustst.Reset();\r
192                         }\r
193                 }\r
194 \r
195                 trustst.Finalize();\r
196                 st.Finalize();\r
197 \r
198                 if(insertcount>=50)\r
199                 {\r
200                         m_log->warning("TrustListRequester::HandleAllData TrustList contained more than 50 new identities : "+message["Identifier"]);\r
201                 }\r
202                 if(dayinsertcount>=100 && previnsertcount>0)\r
203                 {\r
204                         m_log->warning("TrustListRequester::HandleAllData TrustList would have inserted more than 100 new identities in the last 24 hours : "+message["Identifier"]);\r
205                 }\r
206 \r
207                 st=m_db->Prepare("INSERT INTO tblTrustListRequests(IdentityID,Day,RequestIndex,Found) VALUES(?,?,?,'true');");\r
208                 st.Bind(0,identityid);\r
209                 st.Bind(1,idparts[4]);\r
210                 st.Bind(2,index);\r
211                 st.Step();\r
212                 st.Finalize();\r
213 \r
214                 m_db->Execute("COMMIT;");\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(FCPv2::Message &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         m_maxrequests=0;\r
274         Option option(m_db);\r
275 \r
276         option.GetInt("MaxIdentityRequests",m_maxrequests);\r
277         if(m_maxrequests<1)\r
278         {\r
279                 m_maxrequests=1;\r
280                 m_log->error("Option MaxTrustListRequests is currently set at "+tempval+".  It must be 1 or greater.");\r
281         }\r
282         if(m_maxrequests>100)\r
283         {\r
284                 m_log->warning("Option MaxTrustListRequests is currently set at "+tempval+".  This value might be incorrectly configured.");\r
285         }\r
286         m_tempdate=Poco::Timestamp();\r
287 }\r
288 \r
289 void TrustListRequester::PopulateIDList()\r
290 {\r
291         Poco::DateTime date;\r
292         int id;\r
293         std::string sql;\r
294 \r
295         // 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
296         sql="SELECT IdentityID FROM tblIdentity ";\r
297         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
298         sql+="ORDER BY LocalTrustListTrust DESC, LastSeen;";\r
299 \r
300         SQLite3DB::Statement st=m_db->Prepare(sql);\r
301         st.Step();\r
302 \r
303         m_ids.clear();\r
304 \r
305         while(st.RowReturned())\r
306         {\r
307                 st.ResultInt(0,id);\r
308                 m_ids[id]=false;\r
309                 st.Step();\r
310         }\r
311 }\r
312 \r
313 void TrustListRequester::StartRequest(const long &identityid)\r
314 {\r
315         Poco::DateTime now;\r
316         FCPv2::Message message;\r
317         std::string publickey;\r
318         int index;\r
319         std::string indexstr;\r
320         std::string identityidstr;\r
321 \r
322         SQLite3DB::Statement st=m_db->Prepare("SELECT PublicKey FROM tblIdentity WHERE IdentityID=?;");\r
323         st.Bind(0,identityid);\r
324         st.Step();\r
325 \r
326         if(st.RowReturned())\r
327         {\r
328                 st.ResultText(0,publickey);\r
329 \r
330                 SQLite3DB::Statement st2=m_db->Prepare("SELECT MAX(RequestIndex) FROM tblTrustListRequests WHERE Day=? AND IdentityID=?;");\r
331                 st2.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d"));\r
332                 st2.Bind(1,identityid);\r
333                 st2.Step();\r
334 \r
335                 index=0;\r
336                 if(st2.RowReturned())\r
337                 {\r
338                         if(st2.ResultNull(0)==false)\r
339                         {\r
340                                 st2.ResultInt(0,index);\r
341                                 index++;\r
342                         }\r
343                 }\r
344                 st2.Finalize();\r
345 \r
346                 StringFunctions::Convert(index,indexstr);\r
347                 StringFunctions::Convert(identityid,identityidstr);\r
348 \r
349                 message.SetName("ClientGet");\r
350                 message["URI"]=publickey+m_messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"|TrustList|"+indexstr+".xml";\r
351                 message["Identifier"]=m_fcpuniquename+"|"+identityidstr+"|"+indexstr+"|"+message["URI"];\r
352                 message["ReturnType"]="direct";\r
353                 message["MaxSize"]="1000000";                   // 1 MB\r
354 \r
355                 m_fcp->Send(message);\r
356 \r
357                 m_requesting.push_back(identityid);\r
358         }\r
359         st.Finalize();\r
360 \r
361         m_ids[identityid]=true;\r
362 \r
363 }\r