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
66 m_fcp->ReceiveRaw(&data[0],datalength);
\r
69 // parse file into xml and update the database
\r
70 if(data.size()>0 && xml.ParseXML(std::string(data.begin(),data.end()))==true)
\r
73 ssk.SetPublicKey(xml.GetIdentity());
\r
75 // mark puzzle found
\r
76 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
77 st.Bind(0,idparts[3]);
\r
81 if(ssk.ValidPublicKey()==true)
\r
83 // try to find existing identity with this SSK
\r
84 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");
\r
85 st.Bind(0,xml.GetIdentity());
\r
87 if(st.RowReturned()==false)
\r
89 // we don't already know about this id - add it
\r
91 date=Poco::Timestamp();
\r
92 st=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");
\r
93 st.Bind(0,xml.GetIdentity());
\r
94 st.Bind(1,Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));
\r
95 st.Bind(2,"solved captcha");
\r
100 m_log->debug("IdentityIntroductionRequester::HandleAddData parsed a valid identity.");
\r
104 m_log->error("IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");
\r
107 m_log->debug("IdentityIntroductionRequester::HandleAllData parsed IdentityIntroduction XML file : "+message["Identifier"]);
\r
112 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
113 st.Bind(0,idparts[3]);
\r
117 m_log->error("IdentityIntroductionRequester::HandleAllData error parsing IdentityIntroduction XML file : "+message["Identifier"]);
\r
120 // remove UUID from request list
\r
121 RemoveFromRequestList(idparts[3]);
\r
126 const bool IdentityIntroductionRequester::HandleGetFailed(FCPMessage &message)
\r
128 std::vector<std::string> idparts;
\r
130 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
132 // fatal error - don't try to download again
\r
133 if(message["Fatal"]=="true")
\r
135 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
136 st.Bind(0,idparts[3]);
\r
140 m_log->debug("IdentityIntroductionRequester::HandleAllData Fatal GetFailed for "+message["Identifier"]);
\r
143 // remove UUID from request list
\r
144 RemoveFromRequestList(idparts[3]);
\r
149 const bool IdentityIntroductionRequester::HandleMessage(FCPMessage &message)
\r
152 if(message["Identifier"].find("IdentityIntroductionRequester")==0)
\r
155 // ignore DataFound
\r
156 if(message.GetName()=="DataFound")
\r
161 if(message.GetName()=="AllData")
\r
163 return HandleAllData(message);
\r
166 if(message.GetName()=="GetFailed")
\r
168 return HandleGetFailed(message);
\r
171 if(message.GetName()=="IdentifierCollision")
\r
173 // remove one of the ids from the requesting list
\r
174 std::vector<std::string> idparts;
\r
175 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
176 RemoveFromRequestList(idparts[3]);
\r
185 void IdentityIntroductionRequester::Initialize()
\r
188 Option::Instance()->GetInt("MaxIdentityIntroductionRequests",m_maxrequests);
\r
189 if(m_maxrequests<1)
\r
192 m_log->error("Option MaxIdentityIntroductionRequests is currently less than 1. It must be 1 or greater.");
\r
194 if(m_maxrequests>100)
\r
196 m_log->warning("Option MaxIdentityIntroductionRequests is currently set at more than 100. This value might be incorrectly configured.");
\r
198 Option::Instance()->Get("MessageBase",m_messagebase);
\r
199 m_tempdate=Poco::Timestamp();
\r
202 void IdentityIntroductionRequester::PopulateIDList()
\r
204 Poco::DateTime date;
\r
207 date-=Poco::Timespan(1,0,0,0,0);
\r
209 // get all identities that have unsolved puzzles from yesterday or today
\r
210 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
215 while(st.RowReturned())
\r
217 st.ResultInt(0,id);
\r
224 void IdentityIntroductionRequester::Process()
\r
226 // max is the smaller of the config value or the total number of identities we will request from
\r
227 long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;
\r
229 // try to keep up to max requests going
\r
230 if(m_requesting.size()<max)
\r
232 std::map<long,bool>::iterator i=m_ids.begin();
\r
233 while(i!=m_ids.end() && (*i).second==true)
\r
240 StartRequests((*i).first);
\r
244 // we requested from all ids in the list, repopulate the list
\r
248 // 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
249 // this will recheck for ids every minute
\r
250 Poco::DateTime now;
\r
251 if(m_ids.size()==0 && m_tempdate<(now-Poco::Timespan(0,0,1,0,0)))
\r
258 void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)
\r
260 thread->RegisterFCPConnected(this);
\r
261 thread->RegisterFCPMessageHandler(this);
\r
262 thread->RegisterPeriodicProcessor(this);
\r
265 void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)
\r
267 std::vector<std::string>::iterator i=m_requesting.begin();
\r
268 while(i!=m_requesting.end() && (*i)!=UUID)
\r
272 if(i!=m_requesting.end())
\r
274 m_requesting.erase(i);
\r
278 void IdentityIntroductionRequester::StartRequest(const std::string &UUID)
\r
281 std::string solution;
\r
282 std::string encodedhash;
\r
283 FCPMessage message;
\r
284 SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");
\r
288 if(st.RowReturned())
\r
290 st.ResultText(0,day);
\r
291 st.ResultText(1,solution);
\r
293 // get the hash of the solution
\r
294 Poco::SHA1Engine sha1;
\r
295 sha1.update(solution);
\r
296 encodedhash=Poco::DigestEngine::digestToHex(sha1.digest());
\r
297 StringFunctions::UpperCase(encodedhash,encodedhash);
\r
299 //start request for the solution
\r
300 message.SetName("ClientGet");
\r
301 message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";
\r
302 message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];
\r
303 message["ReturnType"]="direct";
\r
304 message["MaxSize"]="10000";
\r
306 m_fcp->SendMessage(message);
\r
308 m_requesting.push_back(UUID);
\r
314 void IdentityIntroductionRequester::StartRequests(const long localidentityid)
\r
316 Poco::DateTime date;
\r
317 std::string localidentityidstr;
\r
320 date-=Poco::Timespan(1,0,0,0,0);
\r
321 StringFunctions::Convert(localidentityid,localidentityidstr);
\r
323 // get all non-solved puzzles from yesterday and today for this identity
\r
324 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
327 // start requests for all non-solved puzzles
\r
328 while(st.RowReturned())
\r
331 st.ResultText(0,uuid);
\r
332 StartRequest(uuid);
\r
336 m_ids[localidentityid]=true;
\r