version 0.3.27
[fms.git] / src / freenet / freenetmasterthread.cpp
1 #include "../../include/freenet/freenetmasterthread.h"\r
2 #include "../../include/option.h"\r
3 #include "../../include/stringfunctions.h"\r
4 #include "../../include/freenet/unkeyedidcreator.h"\r
5 #include "../../include/freenet/identityinserter.h"\r
6 #include "../../include/freenet/identityrequester.h"\r
7 #include "../../include/freenet/unknownidentityrequester.h"\r
8 #include "../../include/freenet/introductionpuzzleinserter.h"\r
9 #include "../../include/freenet/identityintroductionrequester.h"\r
10 #include "../../include/freenet/introductionpuzzlerequester.h"\r
11 #include "../../include/freenet/identityintroductioninserter.h"\r
12 #include "../../include/freenet/trustlistinserter.h"\r
13 #include "../../include/freenet/trustlistrequester.h"\r
14 #include "../../include/freenet/messagelistrequester.h"\r
15 #include "../../include/freenet/inactivemessagelistrequester.h"\r
16 #include "../../include/freenet/messagelistinserter.h"\r
17 #include "../../include/freenet/messagerequester.h"\r
18 #include "../../include/freenet/messageinserter.h"\r
19 #include "../../include/freenet/boardlistinserter.h"\r
20 #include "../../include/freenet/boardlistrequester.h"\r
21 #include "../../include/freenet/siteinserter.h"\r
22 #include "../../include/freenet/fileinserter.h"\r
23 #include "../../include/freenet/fmsversionrequester.h"\r
24 \r
25 #include <Poco/UUID.h>\r
26 #include <Poco/UUIDGenerator.h>\r
27 #include <Poco/DateTime.h>\r
28 #include <Poco/Timespan.h>\r
29 #include <Poco/Thread.h>\r
30 \r
31 #include <cstdlib>\r
32 \r
33 #ifdef XMEM\r
34         #include <xmem.h>\r
35 #endif\r
36 \r
37 FreenetMasterThread::FreenetMasterThread()\r
38 {\r
39 \r
40         if(Option::Instance()->Get("FCPHost",m_fcphost)==false)\r
41         {\r
42                 m_fcphost="localhost";\r
43                 Option::Instance()->Set("FCPHost",m_fcphost);\r
44         }\r
45         if(Option::Instance()->GetInt("FCPPort",m_fcpport)==false)\r
46         {\r
47                 m_fcpport=9481;\r
48                 Option::Instance()->Set("FCPPort",m_fcpport);\r
49         }\r
50         else\r
51         {\r
52                 if(m_fcpport<1 || m_fcpport>65535)\r
53                 {\r
54                         m_fcpport=9481;\r
55                         Option::Instance()->Set("FCPPort",m_fcpport);\r
56                 }\r
57         }\r
58 \r
59         m_receivednodehello=false;\r
60 \r
61 }\r
62 \r
63 FreenetMasterThread::~FreenetMasterThread()\r
64 {\r
65 \r
66 }\r
67 \r
68 const bool FreenetMasterThread::FCPConnect()\r
69 {\r
70         // we were previosly connected, send FCPDisconnect to objects\r
71         if(m_receivednodehello==true)\r
72         {\r
73                 for(std::vector<IFCPConnected *>::iterator i=m_fcpconnected.begin(); i!=m_fcpconnected.end(); i++)\r
74                 {\r
75                         (*i)->FCPDisconnected();\r
76                 }\r
77                 m_receivednodehello=false;\r
78         }\r
79 \r
80         m_log->information("FreenetMasterThread::FCPConnect trying to connect to node "+m_fcphost);\r
81 \r
82         if(m_fcp.Connect(m_fcphost.c_str(),m_fcpport)==true)\r
83         {\r
84                 Poco::UUIDGenerator uuidgen;\r
85                 Poco::UUID uuid;\r
86 \r
87                 try\r
88                 {\r
89                         uuid=uuidgen.createRandom();\r
90                 }\r
91                 catch(...)\r
92                 {\r
93                         m_log->fatal("FreenetMasterThread::FCPConnect could not generate UUID");\r
94                 }\r
95 \r
96                 std::string clientname="FMSClient-"+uuid.toString();\r
97                 // send ClientHello message to node\r
98                 m_fcp.SendMessage("ClientHello",2,"Name",clientname.c_str(),"ExpectedVersion","2.0");\r
99 \r
100                 m_log->information("FreenetMasterThread::FCPConnect connected to node");\r
101 \r
102                 return true;\r
103         }\r
104         else\r
105         {\r
106                 return false;\r
107         }\r
108 \r
109 }\r
110 \r
111 const bool FreenetMasterThread::HandleMessage(FCPMessage &message)\r
112 {\r
113         if(message.GetName()=="NodeHello")\r
114         {\r
115                 m_receivednodehello=true;\r
116 \r
117                 // send connected message to all objects, must do this AFTER we received the NodeHello message\r
118                 for(std::vector<IFCPConnected *>::iterator i=m_fcpconnected.begin(); i!=m_fcpconnected.end(); i++)\r
119                 {\r
120                         (*i)->FCPConnected();\r
121                 }\r
122 \r
123                 return true;\r
124         }\r
125         if(m_receivednodehello==true)\r
126         {\r
127                 bool handled=false;\r
128 \r
129                 std::vector<IFCPMessageHandler *>::iterator i=m_fcpmessagehandlers.begin();\r
130                 while(handled==false && i!=m_fcpmessagehandlers.end())\r
131                 {\r
132                         handled=(*i)->HandleMessage(message);\r
133                         i++;\r
134                 }\r
135 \r
136                 if(handled==false)\r
137                 {\r
138                         std::string info("");\r
139                         for(std::map<std::string,std::string>::iterator mi=message.begin(); mi!=message.end(); mi++)\r
140                         {\r
141                                 info+="\t\t\t\t"+(*mi).first+"="+(*mi).second+"\r\n";\r
142                         }\r
143                         m_log->debug("FreenetMasterThread::HandleMessage received unhandled "+message.GetName()+" message.  Message content :\r\n"+info);\r
144 \r
145                         // if unhandled message was alldata - we must retrieve the data\r
146                         if(message.GetName()=="AllData")\r
147                         {\r
148                                 long length;\r
149                                 StringFunctions::Convert(message["DataLength"],length);\r
150                                 while(m_fcp.Connected() && m_fcp.ReceiveBufferSize()<length)\r
151                                 {\r
152                                         m_fcp.Update(1);\r
153                                 }\r
154                                 if(m_fcp.Connected() && length>0)\r
155                                 {\r
156                                         char *data=new char[length];\r
157                                         m_fcp.ReceiveRaw(data,length);\r
158                                         delete [] data;\r
159                                 }\r
160                         }\r
161                 }\r
162 \r
163                 return handled;\r
164 \r
165         }\r
166         else\r
167         {\r
168                 m_log->error("FreenetMasterThread::HandleMessage received "+message.GetName()+" message before NodeHello");\r
169         }\r
170 \r
171         return false;\r
172 }\r
173 \r
174 void FreenetMasterThread::RegisterFCPConnected(IFCPConnected *obj)\r
175 {\r
176         m_fcpconnected.push_back(obj);\r
177 }\r
178 \r
179 void FreenetMasterThread::RegisterFCPMessageHandler(IFCPMessageHandler *obj)\r
180 {\r
181         m_fcpmessagehandlers.push_back(obj);\r
182 }\r
183 \r
184 void FreenetMasterThread::RegisterPeriodicProcessor(IPeriodicProcessor *obj)\r
185 {\r
186         m_processors.push_back(obj);\r
187 }\r
188 \r
189 void FreenetMasterThread::run()\r
190 {\r
191 \r
192         Poco::DateTime lastreceivedmessage;\r
193         Poco::DateTime lastconnected;\r
194         Poco::DateTime now;\r
195         FCPMessage message;\r
196         bool done=false;\r
197 \r
198         lastconnected-=Poco::Timespan(0,0,1,0,0);\r
199 \r
200         m_log->debug("FreenetMasterThread::run thread started.");\r
201 \r
202         Setup();\r
203 \r
204         do\r
205         {\r
206                 try\r
207                 {\r
208                         if(m_fcp.Connected()==false)\r
209                         {\r
210                                 // wait at least 1 minute since last successful connect\r
211                                 now=Poco::Timestamp();\r
212                                 if(lastconnected<=(now-Poco::Timespan(0,0,1,0,0)))\r
213                                 {\r
214                                         if(FCPConnect()==false)\r
215                                         {\r
216 \r
217                                                 m_log->error("FreenetMasterThread::run could not connect to node.  Waiting 60 seconds.");\r
218 \r
219                                                 for(int i=0; i<60 && !IsCancelled(); i++)\r
220                                                 {\r
221                                                         Poco::Thread::sleep(1000);\r
222                                                 }\r
223                                         }\r
224                                         else\r
225                                         {\r
226                                                 lastreceivedmessage=Poco::Timestamp();\r
227                                                 lastconnected=Poco::Timestamp();\r
228                                         }\r
229                                 }\r
230                                 else\r
231                                 {\r
232                                         Poco::Thread::sleep(1000);\r
233                                 }\r
234                         }\r
235                         // fcp is connected\r
236                         else\r
237                         {\r
238                                 m_fcp.Update(1);\r
239 \r
240                                 // check for message on receive buffer and handle it\r
241                                 if(m_fcp.ReceiveBufferSize()>0)\r
242                                 {\r
243                                         message.Reset();\r
244                                         message=m_fcp.ReceiveMessage();\r
245 \r
246                                         if(message.GetName()!="")\r
247                                         {\r
248                                                 HandleMessage(message);\r
249                                                 lastreceivedmessage=Poco::Timestamp();\r
250                                         }\r
251                                 }\r
252 \r
253                                 // let objects do their processing\r
254                                 for(std::vector<IPeriodicProcessor *>::iterator i=m_processors.begin(); i!=m_processors.end(); i++)\r
255                                 {\r
256                                         (*i)->Process();\r
257                                 }\r
258 \r
259                                 // if we haven't received any messages from the node in 10 minutes, something is wrong\r
260                                 now=Poco::Timestamp();\r
261                                 if(lastreceivedmessage<(now-Poco::Timespan(0,0,10,0,0)))\r
262                                 {\r
263                                         m_log->error("FreenetMasterThread::Run The Freenet node has not responded in 10 minutes.  Trying to reconnect.");\r
264                                         m_fcp.Disconnect();\r
265                                 }\r
266 \r
267                                 if(m_fcp.Connected()==false)\r
268                                 {\r
269                                         m_log->information("FreenetMasterThread::Run Disconnected from Freenet node.");\r
270                                 }\r
271 \r
272                         }\r
273                 }\r
274                 catch(Poco::Exception &e)\r
275                 {\r
276                         m_log->error("FreenetMasterThread::run caught exception : "+e.displayText());\r
277                 }\r
278                 catch(...)\r
279                 {\r
280                         m_log->error("FreenetMasterThread::run caught unknown exception");\r
281                 }\r
282         }while(!IsCancelled() && done==false);\r
283 \r
284         m_fcp.Disconnect();\r
285 \r
286         Shutdown();\r
287 \r
288         m_log->debug("FreenetMasterThread::run thread exiting.");\r
289 \r
290 }\r
291 \r
292 void FreenetMasterThread::Setup()\r
293 {\r
294 \r
295         // seed random number generator\r
296         srand(time(NULL));\r
297 \r
298         m_registrables.push_back(new UnkeyedIDCreator(&m_fcp));\r
299         m_registrables.push_back(new IdentityInserter(&m_fcp));\r
300         m_registrables.push_back(new IdentityRequester(&m_fcp));\r
301         m_registrables.push_back(new UnknownIdentityRequester(&m_fcp));\r
302         m_registrables.push_back(new IntroductionPuzzleInserter(&m_fcp));\r
303         m_registrables.push_back(new IdentityIntroductionRequester(&m_fcp));\r
304         m_registrables.push_back(new IntroductionPuzzleRequester(&m_fcp));\r
305         m_registrables.push_back(new IdentityIntroductionInserter(&m_fcp));\r
306         m_registrables.push_back(new TrustListInserter(&m_fcp));\r
307         m_registrables.push_back(new TrustListRequester(&m_fcp));\r
308         m_registrables.push_back(new MessageListInserter(&m_fcp));\r
309         m_registrables.push_back(new MessageListRequester(&m_fcp));\r
310         m_registrables.push_back(new InactiveMessageListRequester(&m_fcp));\r
311         m_registrables.push_back(new MessageInserter(&m_fcp));\r
312         m_registrables.push_back(new MessageRequester(&m_fcp));\r
313         m_registrables.push_back(new BoardListInserter(&m_fcp));\r
314         m_registrables.push_back(new BoardListRequester(&m_fcp));\r
315         m_registrables.push_back(new SiteInserter(&m_fcp));\r
316         m_registrables.push_back(new FileInserter(&m_fcp));\r
317         m_registrables.push_back(new FMSVersionRequester(&m_fcp));\r
318 \r
319         for(std::vector<IFreenetRegistrable *>::iterator i=m_registrables.begin(); i!=m_registrables.end(); i++)\r
320         {\r
321                 (*i)->RegisterWithThread(this);\r
322         }\r
323 \r
324 }\r
325 \r
326 void FreenetMasterThread::Shutdown()\r
327 {\r
328         // delete each registrable object\r
329         for(std::vector<IFreenetRegistrable *>::iterator i=m_registrables.begin(); i!=m_registrables.end(); i++)\r
330         {\r
331                 delete (*i);\r
332         }\r
333 }\r