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