1 #include "../../include/freenet/identityintroductionrequester.h"
\r
2 #include "../../include/freenet/identityintroductionxml.h"
\r
3 #include "../../include/freenet/freenetssk.h"
\r
4 #include "../../include/option.h"
\r
5 #include "../../include/stringfunctions.h"
\r
6 #include "../../include/hex.h"
\r
8 #include <Poco/DateTime.h>
\r
9 #include <Poco/Timestamp.h>
\r
10 #include <Poco/DateTimeFormatter.h>
\r
11 #include <Poco/SHA1Engine.h>
\r
17 IdentityIntroductionRequester::IdentityIntroductionRequester()
\r
22 IdentityIntroductionRequester::IdentityIntroductionRequester(FCPv2 *fcp):IFCPConnected(fcp)
\r
27 void IdentityIntroductionRequester::FCPConnected()
\r
29 m_requesting.clear();
\r
33 void IdentityIntroductionRequester::FCPDisconnected()
\r
38 const bool IdentityIntroductionRequester::HandleAllData(FCPMessage &message)
\r
41 Poco::DateTime date;
\r
42 std::vector<std::string> idparts;
\r
43 std::vector<char> data;
\r
45 IdentityIntroductionXML xml;
\r
47 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
48 StringFunctions::Convert(message["DataLength"],datalength);
\r
50 // wait for all data to be received from connection
\r
51 while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)
\r
56 // if we got disconnected- return immediately
\r
57 if(m_fcp->Connected()==false)
\r
63 data.resize(datalength);
\r
64 m_fcp->ReceiveRaw(&data[0],datalength);
\r
66 // parse file into xml and update the database
\r
67 if(xml.ParseXML(std::string(data.begin(),data.end()))==true)
\r
70 ssk.SetPublicKey(xml.GetIdentity());
\r
72 // mark puzzle found
\r
73 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
74 st.Bind(0,idparts[3]);
\r
78 if(ssk.ValidPublicKey()==true)
\r
80 // try to find existing identity with this SSK
\r
81 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");
\r
82 st.Bind(0,xml.GetIdentity());
\r
84 if(st.RowReturned()==false)
\r
86 // we don't already know about this id - add it
\r
88 date=Poco::Timestamp();
\r
89 st=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");
\r
90 st.Bind(0,xml.GetIdentity());
\r
91 st.Bind(1,Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));
\r
92 st.Bind(2,"solved captcha");
\r
97 m_log->debug("IdentityIntroductionRequester::HandleAddData parsed a valid identity.");
\r
101 m_log->error("IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");
\r
104 m_log->debug("IdentityIntroductionRequester::HandleAllData parsed IdentityIntroduction XML file : "+message["Identifier"]);
\r
109 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
110 st.Bind(0,idparts[3]);
\r
114 m_log->error("IdentityIntroductionRequester::HandleAllData error parsing IdentityIntroduction XML file : "+message["Identifier"]);
\r
117 // remove UUID from request list
\r
118 RemoveFromRequestList(idparts[3]);
\r
123 const bool IdentityIntroductionRequester::HandleGetFailed(FCPMessage &message)
\r
125 std::vector<std::string> idparts;
\r
127 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
129 // fatal error - don't try to download again
\r
130 if(message["Fatal"]=="true")
\r
132 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
133 st.Bind(0,idparts[3]);
\r
137 m_log->debug("IdentityIntroductionRequester::HandleAllData Fatal GetFailed for "+message["Identifier"]);
\r
140 // remove UUID from request list
\r
141 RemoveFromRequestList(idparts[3]);
\r
146 const bool IdentityIntroductionRequester::HandleMessage(FCPMessage &message)
\r
149 if(message["Identifier"].find("IdentityIntroductionRequester")==0)
\r
152 // ignore DataFound
\r
153 if(message.GetName()=="DataFound")
\r
158 if(message.GetName()=="AllData")
\r
160 return HandleAllData(message);
\r
163 if(message.GetName()=="GetFailed")
\r
165 return HandleGetFailed(message);
\r
168 if(message.GetName()=="IdentifierCollision")
\r
170 // remove one of the ids from the requesting list
\r
171 std::vector<std::string> idparts;
\r
172 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
173 RemoveFromRequestList(idparts[3]);
\r
182 void IdentityIntroductionRequester::Initialize()
\r
184 std::string tempval="";
\r
185 Option::Instance()->Get("MaxIdentityIntroductionRequests",tempval);
\r
186 StringFunctions::Convert(tempval,m_maxrequests);
\r
187 if(m_maxrequests<1)
\r
190 m_log->error("Option MaxIdentityIntroductionRequests is currently set at "+tempval+". It must be 1 or greater.");
\r
192 if(m_maxrequests>100)
\r
194 m_log->warning("Option MaxIdentityIntroductionRequests is currently set at "+tempval+". This value might be incorrectly configured.");
\r
196 Option::Instance()->Get("MessageBase",m_messagebase);
\r
197 m_tempdate=Poco::Timestamp();
\r
200 void IdentityIntroductionRequester::PopulateIDList()
\r
202 Poco::DateTime date;
\r
205 date-=Poco::Timespan(1,0,0,0,0);
\r
207 // get all identities that have unsolved puzzles from yesterday or today
\r
208 SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblIntroductionPuzzleInserts WHERE Day>='"+Poco::DateTimeFormatter::format(date,"%Y-%m-%d")+"' AND FoundSolution='false' GROUP BY LocalIdentityID;");
\r
213 while(st.RowReturned())
\r
215 st.ResultInt(0,id);
\r
222 void IdentityIntroductionRequester::Process()
\r
224 // max is the smaller of the config value or the total number of identities we will request from
\r
225 long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;
\r
227 // try to keep up to max requests going
\r
228 if(m_requesting.size()<max)
\r
230 std::map<long,bool>::iterator i=m_ids.begin();
\r
231 while(i!=m_ids.end() && (*i).second==true)
\r
238 StartRequests((*i).first);
\r
242 // we requested from all ids in the list, repopulate the list
\r
246 // special case - if there were 0 identities on the list when we started then we will never get a chance to repopulate the list
\r
247 // this will recheck for ids every minute
\r
248 Poco::DateTime now;
\r
249 if(m_ids.size()==0 && m_tempdate<(now-Poco::Timespan(0,0,1,0,0)))
\r
256 void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)
\r
258 thread->RegisterFCPConnected(this);
\r
259 thread->RegisterFCPMessageHandler(this);
\r
260 thread->RegisterPeriodicProcessor(this);
\r
263 void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)
\r
265 std::vector<std::string>::iterator i=m_requesting.begin();
\r
266 while(i!=m_requesting.end() && (*i)!=UUID)
\r
270 if(i!=m_requesting.end())
\r
272 m_requesting.erase(i);
\r
276 void IdentityIntroductionRequester::StartRequest(const std::string &UUID)
\r
279 std::string solution;
\r
280 // std::vector<unsigned char> solutionhash;
\r
281 std::string encodedhash;
\r
282 FCPMessage message;
\r
283 SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");
\r
287 if(st.RowReturned())
\r
289 st.ResultText(0,day);
\r
290 st.ResultText(1,solution);
\r
292 Poco::SHA1Engine sha1;
\r
293 sha1.update(solution);
\r
294 encodedhash=Poco::DigestEngine::digestToHex(sha1.digest());
\r
295 StringFunctions::UpperCase(encodedhash,encodedhash);
\r
297 // get the hash of the solution
\r
298 // solutionhash.resize(20);
\r
299 // sha1((unsigned char *)solution.c_str(),solution.size(),&solutionhash[0]);
\r
300 // Hex::Encode(solutionhash,encodedhash);
\r
302 //start request for the solution
\r
303 message.SetName("ClientGet");
\r
304 message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";
\r
305 message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];
\r
306 message["ReturnType"]="direct";
\r
307 message["MaxSize"]="10000";
\r
309 m_fcp->SendMessage(message);
\r
311 m_requesting.push_back(UUID);
\r
317 void IdentityIntroductionRequester::StartRequests(const long localidentityid)
\r
319 Poco::DateTime date;
\r
320 std::string localidentityidstr;
\r
323 date-=Poco::Timespan(1,0,0,0,0);
\r
324 StringFunctions::Convert(localidentityid,localidentityidstr);
\r
326 // get all non-solved puzzles from yesterday and today for this identity
\r
327 SQLite3DB::Statement st=m_db->Prepare("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID="+localidentityidstr+" AND Day>='"+Poco::DateTimeFormatter::format(date,"%Y-%m-%d")+"' AND FoundSolution='false';");
\r
330 // start requests for all non-solved puzzles
\r
331 while(st.RowReturned())
\r
334 st.ResultText(0,uuid);
\r
335 StartRequest(uuid);
\r
339 m_ids[localidentityid]=true;
\r