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(SQLite3DB::DB *db):IDatabase(db)
\r
22 IdentityIntroductionRequester::IdentityIntroductionRequester(SQLite3DB::DB *db, FCPv2::Connection *fcp):IDatabase(db),IFCPConnected(fcp)
\r
27 void IdentityIntroductionRequester::FCPConnected()
\r
29 m_requesting.clear();
\r
33 void IdentityIntroductionRequester::FCPDisconnected()
\r
38 const bool IdentityIntroductionRequester::HandleAllData(FCPv2::Message &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 m_fcp->WaitForBytes(1000,datalength);
\r
53 // if we got disconnected- return immediately
\r
54 if(m_fcp->IsConnected()==false)
\r
60 m_fcp->Receive(data,datalength);
\r
62 // parse file into xml and update the database
\r
63 if(data.size()>0 && xml.ParseXML(std::string(data.begin(),data.end()))==true)
\r
66 ssk.SetPublicKey(xml.GetIdentity());
\r
68 // mark puzzle found
\r
69 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
70 st.Bind(0,idparts[3]);
\r
74 if(ssk.ValidPublicKey()==true)
\r
76 // try to find existing identity with this SSK
\r
77 st=m_db->Prepare("SELECT IdentityID FROM tblIdentity WHERE PublicKey=?;");
\r
78 st.Bind(0,xml.GetIdentity());
\r
80 if(st.RowReturned()==false)
\r
82 // we don't already know about this id - add it
\r
84 date=Poco::Timestamp();
\r
85 st=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");
\r
86 st.Bind(0,xml.GetIdentity());
\r
87 st.Bind(1,Poco::DateTimeFormatter::format(date,"%Y-%m-%d %H:%M:%S"));
\r
88 st.Bind(2,"solved captcha");
\r
93 m_log->debug("IdentityIntroductionRequester::HandleAddData parsed a valid identity.");
\r
97 m_log->error("IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");
\r
100 m_log->debug("IdentityIntroductionRequester::HandleAllData parsed IdentityIntroduction XML file : "+message["Identifier"]);
\r
105 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
106 st.Bind(0,idparts[3]);
\r
110 m_log->error("IdentityIntroductionRequester::HandleAllData error parsing IdentityIntroduction XML file : "+message["Identifier"]);
\r
113 // remove UUID from request list
\r
114 RemoveFromRequestList(idparts[3]);
\r
119 const bool IdentityIntroductionRequester::HandleGetFailed(FCPv2::Message &message)
\r
121 std::vector<std::string> idparts;
\r
123 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
125 // fatal error - don't try to download again
\r
126 if(message["Fatal"]=="true")
\r
128 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
129 st.Bind(0,idparts[3]);
\r
133 m_log->debug("IdentityIntroductionRequester::HandleAllData Fatal GetFailed for "+message["Identifier"]);
\r
136 // remove UUID from request list
\r
137 RemoveFromRequestList(idparts[3]);
\r
142 const bool IdentityIntroductionRequester::HandleMessage(FCPv2::Message &message)
\r
145 if(message["Identifier"].find("IdentityIntroductionRequester")==0)
\r
148 // ignore DataFound
\r
149 if(message.GetName()=="DataFound")
\r
154 if(message.GetName()=="AllData")
\r
156 return HandleAllData(message);
\r
159 if(message.GetName()=="GetFailed")
\r
161 return HandleGetFailed(message);
\r
164 if(message.GetName()=="IdentifierCollision")
\r
166 // remove one of the ids from the requesting list
\r
167 std::vector<std::string> idparts;
\r
168 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
169 RemoveFromRequestList(idparts[3]);
\r
178 void IdentityIntroductionRequester::Initialize()
\r
181 Option option(m_db);
\r
182 option.GetInt("MaxIdentityIntroductionRequests",m_maxrequests);
\r
183 if(m_maxrequests<1)
\r
186 m_log->error("Option MaxIdentityIntroductionRequests is currently less than 1. It must be 1 or greater.");
\r
188 if(m_maxrequests>100)
\r
190 m_log->warning("Option MaxIdentityIntroductionRequests is currently set at more than 100. This value might be incorrectly configured.");
\r
192 option.Get("MessageBase",m_messagebase);
\r
193 m_tempdate=Poco::Timestamp();
\r
196 void IdentityIntroductionRequester::PopulateIDList()
\r
198 Poco::DateTime date;
\r
201 date-=Poco::Timespan(1,0,0,0,0);
\r
203 // get all identities that have unsolved puzzles from yesterday or today
\r
204 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
209 while(st.RowReturned())
\r
211 st.ResultInt(0,id);
\r
218 void IdentityIntroductionRequester::Process()
\r
220 // max is the smaller of the config value or the total number of identities we will request from
\r
221 long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;
\r
223 // try to keep up to max requests going
\r
224 if(m_requesting.size()<max)
\r
226 std::map<long,bool>::iterator i=m_ids.begin();
\r
227 while(i!=m_ids.end() && (*i).second==true)
\r
234 StartRequests((*i).first);
\r
238 // we requested from all ids in the list, repopulate the list
\r
242 // 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
243 // this will recheck for ids every minute
\r
244 Poco::DateTime now;
\r
245 if(m_ids.size()==0 && m_tempdate<(now-Poco::Timespan(0,0,1,0,0)))
\r
252 void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)
\r
254 thread->RegisterFCPConnected(this);
\r
255 thread->RegisterFCPMessageHandler(this);
\r
256 thread->RegisterPeriodicProcessor(this);
\r
259 void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)
\r
261 std::vector<std::string>::iterator i=m_requesting.begin();
\r
262 while(i!=m_requesting.end() && (*i)!=UUID)
\r
266 if(i!=m_requesting.end())
\r
268 m_requesting.erase(i);
\r
272 void IdentityIntroductionRequester::StartRequest(const std::string &UUID)
\r
275 std::string solution;
\r
276 std::string encodedhash;
\r
277 FCPv2::Message message;
\r
278 SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");
\r
282 if(st.RowReturned())
\r
284 st.ResultText(0,day);
\r
285 st.ResultText(1,solution);
\r
287 // get the hash of the solution
\r
288 Poco::SHA1Engine sha1;
\r
289 sha1.update(solution);
\r
290 encodedhash=Poco::DigestEngine::digestToHex(sha1.digest());
\r
291 StringFunctions::UpperCase(encodedhash,encodedhash);
\r
293 //start request for the solution
\r
294 message.SetName("ClientGet");
\r
295 message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";
\r
296 message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];
\r
297 message["ReturnType"]="direct";
\r
298 message["MaxSize"]="10000";
\r
300 m_fcp->Send(message);
\r
302 m_requesting.push_back(UUID);
\r
308 void IdentityIntroductionRequester::StartRequests(const long localidentityid)
\r
310 Poco::DateTime date;
\r
311 std::string localidentityidstr;
\r
314 date-=Poco::Timespan(1,0,0,0,0);
\r
315 StringFunctions::Convert(localidentityid,localidentityidstr);
\r
317 // get all non-solved puzzles from yesterday and today for this identity
\r
318 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
321 // start requests for all non-solved puzzles
\r
322 while(st.RowReturned())
\r
325 st.ResultText(0,uuid);
\r
326 StartRequest(uuid);
\r
330 m_ids[localidentityid]=true;
\r