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) VALUES(?,?);");
\r
86 st.Bind(0,xml.GetIdentity());
\r
87 st.Bind(1,date.Format("%Y-%m-%d %H:%M:%S"));
\r
92 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAddData parsed a valid identity.");
\r
96 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IdentityIntroductionRequester::HandleAllData parsed, public SSK key was not valid.");
\r
99 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAllData parsed IdentityIntroduction XML file : "+message["Identifier"]);
\r
104 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
105 st.Bind(0,idparts[3]);
\r
109 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IdentityIntroductionRequester::HandleAllData error parsing IdentityIntroduction XML file : "+message["Identifier"]);
\r
112 // remove UUID from request list
\r
113 RemoveFromRequestList(idparts[3]);
\r
118 const bool IdentityIntroductionRequester::HandleGetFailed(FCPMessage &message)
\r
120 std::vector<std::string> idparts;
\r
122 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
124 // fatal error - don't try to download again
\r
125 if(message["Fatal"]=="true")
\r
127 SQLite3DB::Statement st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET FoundSolution='true' WHERE UUID=?;");
\r
128 st.Bind(0,idparts[3]);
\r
132 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IdentityIntroductionRequester::HandleAllData Fatal GetFailed for "+message["Identifier"]);
\r
135 // remove UUID from request list
\r
136 RemoveFromRequestList(idparts[3]);
\r
141 const bool IdentityIntroductionRequester::HandleMessage(FCPMessage &message)
\r
144 if(message["Identifier"].find("IdentityIntroductionRequester")==0)
\r
147 // ignore DataFound
\r
148 if(message.GetName()=="DataFound")
\r
153 if(message.GetName()=="AllData")
\r
155 return HandleAllData(message);
\r
158 if(message.GetName()=="GetFailed")
\r
160 return HandleGetFailed(message);
\r
163 if(message.GetName()=="IdentifierCollision")
\r
165 // remove one of the ids from the requesting list
\r
166 std::vector<std::string> idparts;
\r
167 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
168 RemoveFromRequestList(idparts[3]);
\r
177 void IdentityIntroductionRequester::Initialize()
\r
179 std::string tempval="";
\r
180 Option::Instance()->Get("MaxIdentityIntroductionRequests",tempval);
\r
181 StringFunctions::Convert(tempval,m_maxrequests);
\r
182 if(m_maxrequests<1)
\r
185 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+". It must be 1 or greater.");
\r
187 if(m_maxrequests>100)
\r
189 m_log->WriteLog(LogFile::LOGLEVEL_WARNING,"Option MaxIdentityIntroductionRequests is currently set at "+tempval+". This value might be incorrectly configured.");
\r
191 Option::Instance()->Get("MessageBase",m_messagebase);
\r
192 m_tempdate.SetToGMTime();
\r
195 void IdentityIntroductionRequester::PopulateIDList()
\r
200 date.SetToGMTime();
\r
201 date.Add(0,0,0,-1);
\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>='"+date.Format("%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
246 if(m_ids.size()==0 && m_tempdate<(now-(1.0/1440.0)))
\r
253 void IdentityIntroductionRequester::RegisterWithThread(FreenetMasterThread *thread)
\r
255 thread->RegisterFCPConnected(this);
\r
256 thread->RegisterFCPMessageHandler(this);
\r
257 thread->RegisterPeriodicProcessor(this);
\r
260 void IdentityIntroductionRequester::RemoveFromRequestList(const std::string &UUID)
\r
262 std::vector<std::string>::iterator i=m_requesting.begin();
\r
263 while(i!=m_requesting.end() && (*i)!=UUID)
\r
267 if(i!=m_requesting.end())
\r
269 m_requesting.erase(i);
\r
273 void IdentityIntroductionRequester::StartRequest(const std::string &UUID)
\r
276 std::string solution;
\r
277 std::vector<unsigned char> solutionhash;
\r
278 std::string encodedhash;
\r
279 FCPMessage message;
\r
280 SQLite3DB::Statement st=m_db->Prepare("SELECT Day, PuzzleSolution FROM tblIntroductionPuzzleInserts WHERE FoundSolution='false' AND UUID=?;");
\r
284 if(st.RowReturned())
\r
286 st.ResultText(0,day);
\r
287 st.ResultText(1,solution);
\r
289 // get the hash of the solution
\r
290 solutionhash.resize(20);
\r
291 sha1((unsigned char *)solution.c_str(),solution.size(),&solutionhash[0]);
\r
292 Hex::Encode(solutionhash,encodedhash);
\r
294 //start request for the solution
\r
295 message.SetName("ClientGet");
\r
296 message["URI"]="KSK@"+m_messagebase+"|"+day+"|"+UUID+"|"+encodedhash+".xml";
\r
297 message["Identifier"]="IdentityIntroductionRequester|"+message["URI"];
\r
298 message["ReturnType"]="direct";
\r
299 message["MaxSize"]="10000";
\r
301 m_fcp->SendMessage(message);
\r
303 m_requesting.push_back(UUID);
\r
309 void IdentityIntroductionRequester::StartRequests(const long localidentityid)
\r
312 std::string localidentityidstr;
\r
315 date.SetToGMTime();
\r
316 date.Add(0,0,0,-1);
\r
317 StringFunctions::Convert(localidentityid,localidentityidstr);
\r
319 // get all non-solved puzzles from yesterday and today for this identity
\r
320 SQLite3DB::Statement st=m_db->Prepare("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE LocalIdentityID="+localidentityidstr+" AND Day>='"+date.Format("%Y-%m-%d")+"' AND FoundSolution='false';");
\r
323 // start requests for all non-solved puzzles
\r
324 while(st.RowReturned())
\r
327 st.ResultText(0,uuid);
\r
328 StartRequest(uuid);
\r
332 m_ids[localidentityid]=true;
\r