version 0.0.1
[fms.git] / src / freenet / fcpv2.cpp
1 #include "../../include/freenet/fcpv2.h"\r
2 #include <cstdio>\r
3 #include <cstdarg>\r
4 #include <sstream>\r
5 \r
6 #ifdef _WIN32\r
7         #include <ws2tcpip.h>\r
8 #else\r
9         #include <netdb.h>\r
10         #include <netinet/in.h>\r
11 #endif\r
12 \r
13 /* XMEM doesn't play nice with strtok - should replace strtok with something else anyway\r
14 #ifdef XMEM\r
15         #include <xmem.h>\r
16 #endif\r
17 */\r
18 \r
19 #ifdef _WIN32\r
20         bool FCPv2::m_wsastartup=false;\r
21 #endif\r
22 \r
23 \r
24 \r
25 FCPv2::FCPv2()\r
26 {\r
27 #ifdef _WIN32\r
28         if(m_wsastartup==false)\r
29         {\r
30                 WSAData wsadata;\r
31                 WSAStartup(MAKEWORD(2,2),&wsadata);\r
32                 m_wsastartup=true;\r
33         }\r
34 #endif\r
35 \r
36         // initialize socket to server\r
37         m_serversocket=-1;\r
38 \r
39         // initialize buffers\r
40         m_tempbuffer=new char[65535];\r
41 \r
42 }\r
43 \r
44 \r
45 FCPv2::~FCPv2()\r
46 {\r
47         Disconnect();\r
48 #ifdef _WIN32\r
49         WSACleanup();\r
50 #endif\r
51 \r
52         delete [] m_tempbuffer;\r
53 \r
54 }\r
55 \r
56 \r
57 const bool FCPv2::Connect(const char *host, const int port)\r
58 {\r
59         // disconnect socket to server if it is currently open\r
60         if(Connected())\r
61         {\r
62                 Disconnect();\r
63         }\r
64 \r
65         int rval=-1;\r
66         struct sockaddr_storage m_serveraddr;\r
67 \r
68         std::ostringstream portstring;\r
69         addrinfo hint,*result;\r
70         result=NULL;\r
71         portstring << port;\r
72 \r
73         memset(&hint,0,sizeof(addrinfo));\r
74         hint.ai_socktype=SOCK_STREAM;\r
75         rval=getaddrinfo(host,portstring.str().c_str(),&hint,&result);\r
76 \r
77         // erase any data in buffers\r
78         m_sendbuffer.clear();\r
79         m_receivebuffer.clear();\r
80 \r
81         if(result)\r
82         {\r
83                 memset(&m_serveraddr,0,sizeof(struct sockaddr_storage));\r
84 \r
85                 m_serversocket=socket(result->ai_family,result->ai_socktype,result->ai_protocol);\r
86 \r
87                 if(m_serversocket!=-1)\r
88                 {\r
89                         rval=connect(m_serversocket,result->ai_addr,result->ai_addrlen);\r
90                         if(rval==-1)\r
91                         {\r
92                                 Disconnect();\r
93                         }\r
94                 }\r
95 \r
96                 freeaddrinfo(result);\r
97         }\r
98 \r
99         if(rval==0)\r
100         {\r
101                 return true;\r
102         }\r
103         else\r
104         {\r
105                 return false;\r
106         }\r
107 \r
108 }\r
109 \r
110 const bool FCPv2::Disconnect()\r
111 {\r
112         if(Connected())\r
113         {\r
114         #ifdef _WIN32\r
115                 closesocket(m_serversocket);\r
116         #else\r
117                 close(m_serversocket);\r
118         #endif\r
119                 m_serversocket=-1;\r
120         }\r
121         return true;\r
122 }\r
123 \r
124 int FCPv2::FindOnReceiveBuffer(const char *text)\r
125 {\r
126         bool found;\r
127         int i,j;\r
128         size_t tlen=strlen(text);\r
129 \r
130         if(m_receivebuffer.size()>=tlen)\r
131         {\r
132                 for(i=0; i<=m_receivebuffer.size()-tlen; i++)\r
133                 {\r
134                         found=true;\r
135                         for(j=0; j<tlen; j++)\r
136                         {\r
137                                 if(m_receivebuffer[i+j]!=text[j])\r
138                                 {\r
139                                         found=false;\r
140                                         j=tlen;\r
141                                 }\r
142                         }\r
143                         if(found==true)\r
144                         {\r
145                                 return i;\r
146                         }\r
147                 }\r
148         }\r
149 \r
150         return -1;\r
151 }\r
152 \r
153 FCPMessage FCPv2::ReceiveMessage()\r
154 {\r
155         int field=0;\r
156         int len=0;\r
157         int endlen=0;\r
158         int endmessage=-1;\r
159         char *buffpos;\r
160         char *prevpos;\r
161         char *buffer;\r
162 \r
163         FCPMessage message;\r
164 \r
165         // there is data on the receive buffer\r
166         if(m_receivebuffer.size()>0)\r
167         {\r
168 \r
169                 // find Data on a line by itself following AllData\r
170                 if(FindOnReceiveBuffer("AllData\n")==0)\r
171                 {\r
172                         endmessage=FindOnReceiveBuffer("\nData\n");\r
173                         if(endmessage!=-1)\r
174                         {\r
175                                 endmessage++;\r
176                                 endlen=5;\r
177                         }\r
178                 }\r
179                 // otherwise this is a regular message - search for EndMessage\r
180                 else\r
181                 {\r
182                         endmessage=FindOnReceiveBuffer("EndMessage\n");\r
183                         endlen=11;\r
184                 }\r
185 \r
186                 // continue if we found "EndMessage\n" or "Data\n"\r
187                 if(endmessage!=-1)\r
188                 {\r
189                         // total length of message (including ending \n)\r
190                         len=endmessage+endlen;\r
191 \r
192                         // allocate space for message\r
193                         buffer=new char[len+1];\r
194 \r
195                         // copy message from receive buffer to message buffer\r
196                         std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,buffer);\r
197                         buffer[len]='\0';\r
198 \r
199                         // remove from receive buffer\r
200                         m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
201 \r
202                         // set buffer position\r
203                         buffpos=buffer;\r
204 \r
205                         // find message name\r
206                         buffpos=strtok(buffer,"\n");\r
207                         message.SetName(buffer);\r
208 \r
209                         do\r
210                         {\r
211                                 // find next field\r
212                                 prevpos=buffpos;\r
213                                 buffpos=strtok(NULL,"=");\r
214 \r
215                                 // continue if we aren't at the end of a regular message, or at Data for an AllData message\r
216                                 if(strncmp(buffpos,"EndMessage\n",11)!=0 && strncmp(buffpos,"Data\n",5)!=0)     //!(strncmp(message->MessageName,"AllData",7)==0 && strncmp(buffpos,"Data\n",5)==0))\r
217                                 {\r
218 \r
219                                         // find next value\r
220                                         prevpos=buffpos;\r
221                                         buffpos=strtok(NULL,"\n");\r
222 \r
223                                         if(prevpos && buffpos)\r
224                                         {\r
225                                                 message[prevpos]=buffpos;\r
226                                         }\r
227 \r
228                                         field++;\r
229                                 }\r
230                                 else\r
231                                 {\r
232                                         buffpos=0;\r
233                                 }\r
234 \r
235                         }while(buffpos!=0);\r
236 \r
237                         delete [] buffer;\r
238 \r
239                 }\r
240         }\r
241 \r
242         return message;\r
243 }\r
244 \r
245 const long FCPv2::ReceiveRaw(char *data, long &datalen)\r
246 {\r
247         long len=0;\r
248         if(m_receivebuffer.size()>0 && datalen>0)\r
249         {\r
250                 if(datalen>m_receivebuffer.size())\r
251                 {\r
252                         len=m_receivebuffer.size();\r
253                 }\r
254                 else\r
255                 {\r
256                         len=datalen;\r
257                 }\r
258 \r
259                 std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,data);\r
260 \r
261                 // erase bytes from receive buffer\r
262                 m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
263 \r
264         }\r
265         datalen=len;\r
266         return datalen;\r
267 }\r
268 \r
269 void FCPv2::SendBufferedText(const char *text)\r
270 {\r
271         unsigned int i;\r
272         for(i=0; i<strlen(text); i++)\r
273         {\r
274                 m_sendbuffer.push_back(text[i]);\r
275         }\r
276 }\r
277 \r
278 void FCPv2::SendBufferedRaw(const char *data, const long len)\r
279 {\r
280         int i;\r
281         for(i=0; i<len; i++)\r
282         {\r
283                 m_sendbuffer.push_back(data[i]);\r
284         }\r
285 }\r
286 \r
287 const int FCPv2::SendMessage(const char *messagename, const int fieldcount, ...)\r
288 {\r
289         va_list args;\r
290         const char *field;\r
291         const char *val;\r
292         int bytecount=0;\r
293         int i;\r
294         int startlen;\r
295 \r
296         startlen=m_sendbuffer.size();\r
297 \r
298         SendBufferedText(messagename);\r
299         SendBufferedText("\n");\r
300 \r
301         va_start(args,fieldcount);\r
302 \r
303         for(i=0; i<fieldcount; i++)\r
304         {\r
305                 field=va_arg(args,const char *);\r
306                 val=va_arg(args,const char *);\r
307 \r
308                 SendBufferedText(field);\r
309                 SendBufferedText("=");\r
310                 SendBufferedText(val);\r
311                 SendBufferedText("\n");\r
312         }\r
313 \r
314         SendBufferedText("EndMessage\n");\r
315 \r
316         bytecount=m_sendbuffer.size()-startlen;\r
317         \r
318         va_end(args);\r
319 \r
320         return bytecount;\r
321 }\r
322 \r
323 const int FCPv2::SendMessage(FCPMessage &message)\r
324 {\r
325         int bytecount=0;\r
326         int startlen;\r
327         FCPMessage::iterator i;\r
328 \r
329         startlen=m_sendbuffer.size();\r
330 \r
331         if(message.GetName()!="")\r
332         {\r
333                 SendBufferedText(message.GetName().c_str());\r
334                 SendBufferedText("\n");\r
335 \r
336                 for(i=message.begin(); i!=message.end(); i++)\r
337                 {\r
338                         SendBufferedText((*i).first.c_str());\r
339                         SendBufferedText("=");\r
340                         SendBufferedText((*i).second.c_str());\r
341                         SendBufferedText("\n");\r
342                 }\r
343 \r
344                 SendBufferedText("EndMessage\n");\r
345         }\r
346 \r
347         bytecount=m_sendbuffer.size()-startlen;\r
348 \r
349         return bytecount;\r
350 }\r
351 \r
352 \r
353 const int FCPv2::SendRaw(const char *data, const int datalen)\r
354 {\r
355         int bytecount=datalen;\r
356 \r
357         if(bytecount>0)\r
358         {\r
359                 SendBufferedRaw(data,datalen);\r
360         }\r
361 \r
362         return bytecount;\r
363 \r
364 }\r
365 \r
366 void FCPv2::SocketReceive()\r
367 {\r
368         int len=0;\r
369 \r
370         len=recv(m_serversocket,m_tempbuffer,65535,0);\r
371 \r
372         if(len>0)\r
373         {\r
374 \r
375                 m_receivebuffer.resize(m_receivebuffer.size()+len);\r
376                 std::copy(m_tempbuffer,&m_tempbuffer[len],m_receivebuffer.end()-len);\r
377 \r
378         }\r
379         // there was an error or server closed connection  - disconnect socket\r
380         else\r
381         {\r
382                 Disconnect();\r
383         }\r
384 }\r
385 \r
386 void FCPv2::SocketSend()\r
387 {\r
388         int len=0;\r
389         if(m_sendbuffer.size()>0)\r
390         {\r
391                 len=send(m_serversocket,&m_sendbuffer[0],m_sendbuffer.size(),0);\r
392                 if(len>0)\r
393                 {\r
394                         // move remaining data in buffer to beginning of buffer (erase the bytes we just sent)\r
395                         m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+len);\r
396                 }\r
397                 // there was an error with send - disconnect socket\r
398                 else\r
399                 {\r
400                         Disconnect();\r
401                 }\r
402         }\r
403 }\r
404 \r
405 \r
406 const bool FCPv2::Update(const long waittime)\r
407 {\r
408 \r
409         if(Connected())\r
410         {\r
411                 m_timeval.tv_sec=waittime;\r
412                 m_timeval.tv_usec=0;\r
413 \r
414                 FD_ZERO(&m_readfs);\r
415                 FD_ZERO(&m_writefs);\r
416 \r
417                 FD_SET(m_serversocket,&m_readfs);\r
418                 \r
419                 if(m_sendbuffer.size()>0)\r
420                 {\r
421                         FD_SET(m_serversocket,&m_writefs);\r
422                 }\r
423 \r
424                 select(m_serversocket+1,&m_readfs,&m_writefs,0,&m_timeval);\r
425 \r
426                 if(FD_ISSET(m_serversocket,&m_readfs))\r
427                 {\r
428                         SocketReceive();\r
429                 }\r
430                 if(Connected() && FD_ISSET(m_serversocket,&m_writefs))\r
431                 {\r
432                         SocketSend();\r
433                 }\r
434 \r
435                 return true;\r
436 \r
437         }\r
438         else\r
439         {\r
440                 return false;\r
441         }\r
442 \r
443 }\r