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/xyssl/sha1.h"
\r
7 #include "../../include/hex.h"
\r
13 IdentityIntroductionRequester::IdentityIntroductionRequester()
\r
18 IdentityIntroductionRequester::IdentityIntroductionRequester(FCPv2 *fcp):IFCPConnected(fcp)
\r
23 void IdentityIntroductionRequester::FCPConnected()
\r
25 m_requesting.clear();
\r
29 void IdentityIntroductionRequester::FCPDisconnected()
\r
34 const bool IdentityIntroductionRequester::HandleAllData(FCPMessage &message)
\r
38 std::vector<std::string> idparts;
\r
39 std::vector<char> data;
\r
41 IdentityIntroductionXML xml;
\r
43 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
44 StringFunctions::Convert(message["DataLength"],datalength);
\r
46 // wait for all data to be received from connection
\r
47 while(m_fcp->Connected() && m_fcp->ReceiveBufferSize()<datalength)
\r
52 // if we got disconnected- return immediately
\r
53 if(m_fcp->Connected()==false)
\r
59 data.resize(datalength);
\r
60 m_fcp->ReceiveRaw(&data[0],datalength);
\r
62 // parse file into xml and update the database
\r
63 if(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
85 st=m_db->Prepare("INSERT INTO tblIdentity(PublicKey,DateAdded,AddedMethod) VALUES(?,?,?);");
\r
86 st.Bind(0,xml.GetIdentity());
\r
87 st.Bind(1,date.Format("%Y-%m-%d %H:%M:%S"));
\r
88 st.Bind(2,"solved captcha");
\r
93 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAddData parsed a valid identity.");
\r
97 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");
\r
100 m_log->WriteLog(LogFile::LOGLEVEL_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->WriteLog(LogFile::LOGLEVEL_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(FCPMessage &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->WriteLog(LogFile::LOGLEVEL_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(FCPMessage &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
180 std::string tempval="";
\r
181 Option::Instance()->Get("MaxIdentityIntroductionRequests",tempval);
\r
182 StringFunctions::Convert(tempval,m_maxrequests);
\r
183 if(m_maxrequests<1)
\r
186 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+". It must be 1 or greater.");
\r
188 if(m_maxrequests>100)
\r
190 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+". This value might be incorrectly configured.");
\r
192 Option::Instance()->Get("MessageBase",m_messagebase);
\r
193 m_tempdate.SetToGMTime();
\r
196 void IdentityIntroductionRequester::PopulateIDList()
\r
201 date.SetToGMTime();
\r
202 date.Add(0,0,0,-1);
\r
204 // get all identities that have unsolved puzzles from yesterday or today
\r
205 SQLite3DB::Statement st=m_db->Prepare("SELECT LocalIdentityID FROM tblIntroductionPuzzleInserts WHERE Day>='"+date.Format("%Y-%m-%d")+"' AND FoundSolution='false' GROUP BY LocalIdentityID;");
\r
210 while(st.RowReturned())
\r
212 st.ResultInt(0,id);
\r
219 void IdentityIntroductionRequester::Process()
\r
221 // max is the smaller of the config value or the total number of identities we will request from
\r
222 long max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;
\r
224 // try to keep up to max requests going
\r
225 if(m_requesting.size()<max)
\r
227 std::map<long,bool>::iterator i=m_ids.begin();
\r
228 while(i!=m_ids.end() && (*i).second==true)
\r
235 StartRequests((*i).first);
\r
239 // we requested from all ids in the list, repopulate the list
\r
243 // 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
244 // this will recheck for ids every minute
\r
247 if(m_ids.size()==0 && m_tempdate<(now-(1.0/1440.0)))
\r
254 void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)
\r
256 thread->RegisterFCPConnected(this);
\r
257 thread->RegisterFCPMessageHandler(this);
\r
258 thread->RegisterPeriodicProcessor(this);
\r
261 void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)
\r
263 std::vector<std::string>::iterator i=m_requesting.begin();
\r
264 while(i!=m_requesting.end() && (*i)!=UUID)
\r
268 if(i!=m_requesting.end())
\r
270 m_requesting.erase(i);
\r
274 void IdentityIntroductionRequester::StartRequest(const std::string &UUID)
\r
277 std::string solution;
\r
278 std::vector<unsigned char> solutionhash;
\r
279 std::string encodedhash;
\r
280 FCPMessage message;
\r
281 SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");
\r
285 if(st.RowReturned())
\r
287 st.ResultText(0,day);
\r
288 st.ResultText(1,solution);
\r
290 // get the hash of the solution
\r
291 solutionhash.resize(20);
\r
292 sha1((unsigned char *)solution.c_str(),solution.size(),&solutionhash[0]);
\r
293 Hex::Encode(solutionhash,encodedhash);
\r
295 //start request for the solution
\r
296 message.SetName("ClientGet");
\r
297 message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";
\r
298 message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];
\r
299 message["ReturnType"]="direct";
\r
300 message["MaxSize"]="10000";
\r
302 m_fcp->SendMessage(message);
\r
304 m_requesting.push_back(UUID);
\r
310 void IdentityIntroductionRequester::StartRequests(const long localidentityid)
\r
313 std::string localidentityidstr;
\r
316 date.SetToGMTime();
\r
317 date.Add(0,0,0,-1);
\r
318 StringFunctions::Convert(localidentityid,localidentityidstr);
\r
320 // get all non-solved puzzles from yesterday and today for this identity
\r
321 SQLite3DB::Statement st=m_db->Prepare("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID="+localidentityidstr+" AND Day>='"+date.Format("%Y-%m-%d")+"' AND FoundSolution='false';");
\r
324 // start requests for all non-solved puzzles
\r
325 while(st.RowReturned())
\r
328 st.ResultText(0,uuid);
\r
329 StartRequest(uuid);
\r
333 m_ids[localidentityid]=true;
\r