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