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