version 0.3.29
[fms.git] / src / freenet / fcpv2.cpp
1 #include "../../include/freenet/fcpv2.h"\r
2 \r
3 #include <sstream>\r
4 #include <algorithm>\r
5 #include <cstdarg>\r
6 #include <cstring>\r
7 #include <cstdlib>\r
8 \r
9 #ifdef _WIN32\r
10         #include <ws2tcpip.h>\r
11 #else\r
12         #include <netdb.h>\r
13         #include <netinet/in.h>\r
14 #endif\r
15 \r
16 namespace FCPv2\r
17 {\r
18 \r
19 /*\r
20 \r
21         Message Methods\r
22 \r
23 */\r
24 \r
25 Message::Message():m_name("")\r
26 {\r
27 \r
28 }\r
29 \r
30 Message::Message(const std::string &name):m_name(name)\r
31 {\r
32         \r
33 }\r
34 \r
35 Message::Message(const std::string &name, const int fieldcount, ...):m_name(name)\r
36 {\r
37         const char *field=0;\r
38         const char *val=0;\r
39         va_list args;\r
40         va_start(args,fieldcount);\r
41 \r
42         for(int i=0; i<fieldcount; i++)\r
43         {\r
44                 field=va_arg(args,const char *);\r
45                 val=va_arg(args,const char *);\r
46 \r
47                 if(field && val)\r
48                 {\r
49                         m_fields[field]=val;\r
50                 }\r
51         }\r
52 \r
53         va_end(args);\r
54 \r
55 }\r
56 \r
57 const std::string Message::GetFCPString() const\r
58 {\r
59         std::string rval=m_name;\r
60         rval+="\r\n";\r
61         for(std::map<std::string,std::string>::const_iterator i=m_fields.begin(); i!=m_fields.end(); i++)\r
62         {\r
63                 rval+=(*i).first;\r
64                 rval+="="+(*i).second;\r
65                 rval+="\n";\r
66         }\r
67         if(m_name=="AllData")\r
68         {\r
69                 rval+="Data\n";\r
70         }\r
71         else\r
72         {\r
73                 rval+="EndMessage\n";\r
74         }\r
75         return rval;\r
76 }\r
77 \r
78 \r
79 \r
80 \r
81 \r
82 /*\r
83         \r
84         Connection Methods\r
85 \r
86 */\r
87 \r
88 #ifdef _WIN32\r
89         bool Connection::m_wsastartup=false;\r
90 #endif\r
91 \r
92 Connection::Connection():m_socket(-1),m_tempbuffer(65535,0)\r
93 {\r
94 #ifdef _WIN32\r
95         if(m_wsastartup==false)\r
96         {\r
97                 WSAData wsadata;\r
98                 WSAStartup(MAKEWORD(2,2),&wsadata);\r
99                 m_wsastartup=true;\r
100         }\r
101 #endif\r
102 }\r
103 \r
104 Connection::Connection(const int sock):m_socket(sock),m_tempbuffer(65535,0)\r
105 {\r
106 #ifdef _WIN32\r
107         if(m_wsastartup==false)\r
108         {\r
109                 WSAData wsadata;\r
110                 WSAStartup(MAKEWORD(2,2),&wsadata);\r
111                 m_wsastartup=true;\r
112         }\r
113 #endif\r
114 }\r
115 \r
116 Connection::~Connection()\r
117 {\r
118         Disconnect();\r
119 #ifdef _WIN32\r
120         WSACleanup();\r
121 #endif\r
122 }\r
123 \r
124 const bool Connection::Connect(const std::string &fcphost, const int fcpport)\r
125 {\r
126 \r
127         m_sendbuffer.clear();\r
128         m_receivebuffer.clear();\r
129 \r
130         if(IsConnected()==true)\r
131         {\r
132                 Disconnect();\r
133         }\r
134 \r
135         int rval=-1;\r
136         std::ostringstream portstring;\r
137         addrinfo hint,*result,*current;\r
138 \r
139         result=current=0;\r
140         portstring << fcpport;\r
141         std::memset(&hint,0,sizeof(hint));\r
142         hint.ai_socktype=SOCK_STREAM;\r
143 \r
144         rval=getaddrinfo(fcphost.c_str(),portstring.str().c_str(),&hint,&result);\r
145 \r
146         if(result)\r
147         {\r
148                 for(current=result; current!=0 && m_socket==-1; current=current->ai_next)\r
149                 {\r
150 \r
151                         m_socket=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
152 \r
153                         if(m_socket!=-1)\r
154                         {\r
155                                 rval=connect(m_socket,current->ai_addr,current->ai_addrlen);\r
156                                 if(rval==-1)\r
157                                 {\r
158                                         Disconnect();\r
159                                 }\r
160                         }\r
161 \r
162                 }\r
163 \r
164                 freeaddrinfo(result);\r
165         }\r
166 \r
167         if(rval==0)\r
168         {\r
169                 return true;\r
170         }\r
171         else\r
172         {\r
173                 return false;\r
174         }\r
175 \r
176 }\r
177 \r
178 const bool Connection::Disconnect()\r
179 {\r
180         m_sendbuffer.clear();\r
181         m_receivebuffer.clear();\r
182         if(IsConnected())\r
183         {\r
184         #ifdef _WIN32\r
185                 closesocket(m_socket);\r
186         #else\r
187                 close(m_socket);\r
188         #endif\r
189                 m_socket=-1;\r
190         }\r
191         return true;\r
192 }\r
193 \r
194 void Connection::DoReceive()\r
195 {\r
196         if(IsConnected())\r
197         {\r
198                 int len=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);\r
199                 if(len>0)\r
200                 {\r
201                         m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+len);\r
202                 }\r
203                 else\r
204                 {\r
205                         Disconnect();\r
206                 }\r
207         }\r
208 }\r
209 \r
210 void Connection::DoSend()\r
211 {\r
212         if(IsConnected() && m_sendbuffer.size()>0)\r
213         {\r
214                 int len=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);\r
215                 if(len>0)\r
216                 {\r
217                         m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+len);\r
218                 }\r
219                 else\r
220                 {\r
221                         Disconnect();\r
222                 }\r
223         }\r
224 }\r
225 \r
226 const bool Connection::MessageReady() const\r
227 {\r
228         std::vector<char>::const_iterator tempi;\r
229         std::vector<char>::size_type temp;\r
230         return MessageReady(tempi,temp);\r
231 }\r
232 \r
233 const bool Connection::MessageReady(std::vector<char>::const_iterator &endpos, std::vector<char>::size_type &endlen) const\r
234 {\r
235         static std::string alldatastring="AllData\n";\r
236         static std::string datastring="\nData\n";       // need the \n at the beginning to differentiate from AllData\n\r
237         static std::string endmessagestring="EndMessage\n";\r
238         std::vector<char>::const_iterator tempendpos=m_receivebuffer.end();\r
239         std::vector<char>::size_type tempendlen=0;\r
240 \r
241         if(m_receivebuffer.size()>0)\r
242         {\r
243                 tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),alldatastring.begin(),alldatastring.end());\r
244                 if(tempendpos==m_receivebuffer.begin())\r
245                 {\r
246                         tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),datastring.begin(),datastring.end());\r
247                         if(tempendpos!=m_receivebuffer.end())\r
248                         {\r
249                                 tempendpos+=1;\r
250                                 tempendlen=datastring.size()-1;\r
251                         }\r
252                 }\r
253                 else\r
254                 {\r
255                         tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),endmessagestring.begin(),endmessagestring.end());\r
256                         tempendlen=endmessagestring.size();\r
257                 }\r
258 \r
259                 if(tempendpos!=m_receivebuffer.end())\r
260                 {\r
261                         endpos=tempendpos;\r
262                         endlen=tempendlen;\r
263                         return true;\r
264                 }\r
265 \r
266         }\r
267 \r
268         return false;\r
269 }\r
270 \r
271 const bool Connection::MessageReady(std::vector<char>::iterator &endpos, std::vector<char>::size_type &endlen)\r
272 {\r
273         static std::string alldatastring="AllData\n";\r
274         static std::string datastring="\nData\n";       // need the \n at the beginning to differentiate from AllData\n\r
275         static std::string endmessagestring="EndMessage\n";\r
276         std::vector<char>::iterator tempendpos=m_receivebuffer.end();\r
277         std::vector<char>::size_type tempendlen=0;\r
278 \r
279         if(m_receivebuffer.size()>0)\r
280         {\r
281                 tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),alldatastring.begin(),alldatastring.end());\r
282                 if(tempendpos==m_receivebuffer.begin())\r
283                 {\r
284                         tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),datastring.begin(),datastring.end());\r
285                         if(tempendpos!=m_receivebuffer.end())\r
286                         {\r
287                                 tempendpos+=1;\r
288                                 tempendlen=datastring.size()-1;\r
289                         }\r
290                 }\r
291                 else\r
292                 {\r
293                         tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),endmessagestring.begin(),endmessagestring.end());\r
294                         tempendlen=endmessagestring.size();\r
295                 }\r
296 \r
297                 if(tempendpos!=m_receivebuffer.end())\r
298                 {\r
299                         endpos=tempendpos;\r
300                         endlen=tempendlen;\r
301                         return true;\r
302                 }\r
303 \r
304         }\r
305 \r
306         return false;\r
307 }\r
308 \r
309 const bool Connection::Receive(Message &message)\r
310 {\r
311         std::vector<char>::iterator endpos;\r
312         std::vector<char>::size_type endlen;\r
313         if(MessageReady(endpos,endlen)==true)\r
314         {\r
315                 std::vector<std::string> fields;\r
316 \r
317                 Split(std::string(m_receivebuffer.begin(),endpos),"\n=",fields);\r
318                 m_receivebuffer.erase(m_receivebuffer.begin(),endpos+endlen);\r
319 \r
320                 message.Clear();\r
321 \r
322                 if(fields.size()>0)\r
323                 {\r
324                         message.SetName(fields[0]);\r
325                 }\r
326 \r
327                 if(fields.size()>1)\r
328                 {\r
329                         for(std::vector<std::string>::iterator i=fields.begin()+1; i!=fields.end();)\r
330                         {\r
331                                 if(i+1!=fields.end())\r
332                                 {\r
333                                         message.GetFields()[(*i)]=(*(i+1));\r
334                                         i+=2;\r
335                                 }\r
336                                 else\r
337                                 {\r
338                                         i++;\r
339                                 }\r
340                         }\r
341                 }\r
342 \r
343         }\r
344         return false;\r
345 }\r
346 \r
347 const bool Connection::Receive(std::vector<char> &data, const std::vector<char>::size_type len)\r
348 {\r
349         if(m_receivebuffer.size()>=len && len>=0)\r
350         {\r
351                 data.insert(data.end(),m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
352                 m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
353                 return true;\r
354         }\r
355         else\r
356         {\r
357                 return false;\r
358         }\r
359 }\r
360 \r
361 const bool Connection::Receive(char *data, const size_t len)\r
362 {\r
363         if(m_receivebuffer.size()>=len && len>=0)\r
364         {\r
365                 std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,data);\r
366                 m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
367                 return true;\r
368         }\r
369         else\r
370         {\r
371                 return false;\r
372         }\r
373 }\r
374 \r
375 const bool Connection::ReceiveIgnore(const size_t len)\r
376 {\r
377         if(m_receivebuffer.size()>=len && len>=0)\r
378         {\r
379                 m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
380                 return true;\r
381         }\r
382         else\r
383         {\r
384                 return false;\r
385         }\r
386 }\r
387 \r
388 const bool Connection::Send(const Message &message)\r
389 {\r
390         if(message.GetName()!="")\r
391         {\r
392                 std::string fcpstring=message.GetFCPString();\r
393                 m_sendbuffer.insert(m_sendbuffer.end(),fcpstring.begin(),fcpstring.end());\r
394                 return true;\r
395         }\r
396         return false;\r
397 }\r
398 \r
399 const bool Connection::Send(const std::vector<char> &data)\r
400 {\r
401         m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());\r
402         return true;\r
403 }\r
404 \r
405 const bool Connection::Send(const char *data, const size_t len)\r
406 {\r
407         if(data)\r
408         {\r
409                 m_sendbuffer.insert(m_sendbuffer.end(),data[0],data[0]+len);\r
410                 return true;    \r
411         }\r
412         return false;\r
413 }\r
414 \r
415 void Connection::Split(const std::string &str, const std::string &separators, std::vector<std::string> &elements)\r
416 {\r
417         std::string::size_type offset = 0;\r
418         std::string::size_type delimIndex = 0;\r
419     \r
420         delimIndex = str.find_first_of(separators, offset);\r
421 \r
422     while (delimIndex != std::string::npos)\r
423     {\r
424         elements.push_back(str.substr(offset, delimIndex - offset));\r
425         offset += delimIndex - offset + 1;\r
426         delimIndex = str.find_first_of(separators, offset);\r
427     }\r
428 \r
429     elements.push_back(str.substr(offset));\r
430 }\r
431 \r
432 const bool Connection::Update(const unsigned long ms)\r
433 {\r
434         if(IsConnected())\r
435         {\r
436                 m_timeval.tv_sec=ms/1000;\r
437                 m_timeval.tv_usec=(ms%1000)*1000;\r
438 \r
439                 FD_ZERO(&m_readfs);\r
440                 FD_ZERO(&m_writefs);\r
441 \r
442                 FD_SET(m_socket,&m_readfs);\r
443 \r
444                 if(m_sendbuffer.size()>0)\r
445                 {\r
446                         FD_SET(m_socket,&m_writefs);\r
447                 }\r
448 \r
449                 select(m_socket+1,&m_readfs,&m_writefs,0,&m_timeval);\r
450 \r
451                 if(FD_ISSET(m_socket,&m_readfs))\r
452                 {\r
453                         DoReceive();\r
454                 }\r
455                 if(IsConnected() && FD_ISSET(m_socket,&m_writefs))\r
456                 {\r
457                         DoSend();\r
458                 }\r
459 \r
460         }\r
461 \r
462         if(IsConnected())\r
463         {\r
464                 return true;\r
465         }\r
466         else\r
467         {\r
468                 return false;\r
469         }\r
470 \r
471 }\r
472 \r
473 const bool Connection::WaitForBytes(const unsigned long ms, const size_t len)\r
474 {\r
475         while(IsConnected() && m_receivebuffer.size()<len)\r
476         {\r
477                 Update(ms);\r
478         }\r
479         \r
480         if(IsConnected() && m_receivebuffer.size()>=len)\r
481         {\r
482                 return true;    \r
483         }\r
484         else\r
485         {\r
486                 return false;   \r
487         }\r
488 }\r
489 \r
490 }       // namespace\r