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