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