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