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