#include "../../include/freenet/fcpv2.h"\r
-#include <cstdio>\r
-#include <cstdarg>\r
+\r
#include <sstream>\r
+#include <algorithm>\r
+#include <cstdarg>\r
#include <cstring>\r
+#include <cstdlib>\r
\r
#ifdef _WIN32\r
#include <ws2tcpip.h>\r
#include <netinet/in.h>\r
#endif\r
\r
-/* XMEM doesn't play nice with strtok - should replace strtok with something else anyway\r
-#ifdef XMEM\r
- #include <xmem.h>\r
-#endif\r
+namespace FCPv2\r
+{\r
+\r
+/*\r
+\r
+ Message Methods\r
+\r
*/\r
\r
-#ifdef _WIN32\r
- bool FCPv2::m_wsastartup=false;\r
-#endif\r
+Message::Message():m_name("")\r
+{\r
\r
+}\r
\r
+Message::Message(const std::string &name):m_name(name)\r
+{\r
+ \r
+}\r
\r
-FCPv2::FCPv2()\r
+Message::Message(const std::string &name, const int fieldcount, ...):m_name(name)\r
+{\r
+ const char *field=0;\r
+ const char *val=0;\r
+ va_list args;\r
+ va_start(args,fieldcount);\r
+\r
+ for(int i=0; i<fieldcount; i++)\r
+ {\r
+ field=va_arg(args,const char *);\r
+ val=va_arg(args,const char *);\r
+\r
+ if(field && val)\r
+ {\r
+ m_fields[field]=val;\r
+ }\r
+ }\r
+\r
+ va_end(args);\r
+\r
+}\r
+\r
+const std::string Message::GetFCPString() const\r
+{\r
+ std::string rval=m_name;\r
+ rval+="\r\n";\r
+ for(std::map<std::string,std::string>::const_iterator i=m_fields.begin(); i!=m_fields.end(); i++)\r
+ {\r
+ rval+=(*i).first;\r
+ rval+="="+(*i).second;\r
+ rval+="\n";\r
+ }\r
+ if(m_name=="AllData")\r
+ {\r
+ rval+="Data\n";\r
+ }\r
+ else\r
+ {\r
+ rval+="EndMessage\n";\r
+ }\r
+ return rval;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/*\r
+ \r
+ Connection Methods\r
+\r
+*/\r
+\r
+#ifdef _WIN32\r
+ bool Connection::m_wsastartup=false;\r
+#endif\r
+\r
+Connection::Connection():m_socket(-1),m_tempbuffer(65535,0)\r
{\r
#ifdef _WIN32\r
if(m_wsastartup==false)\r
m_wsastartup=true;\r
}\r
#endif\r
-\r
- // initialize socket to server\r
- m_serversocket=-1;\r
-\r
- // initialize buffers\r
- m_tempbuffer=new char[65535];\r
-\r
}\r
\r
+Connection::Connection(const int sock):m_socket(sock),m_tempbuffer(65535,0)\r
+{\r
+#ifdef _WIN32\r
+ if(m_wsastartup==false)\r
+ {\r
+ WSAData wsadata;\r
+ WSAStartup(MAKEWORD(2,2),&wsadata);\r
+ m_wsastartup=true;\r
+ }\r
+#endif\r
+}\r
\r
-FCPv2::~FCPv2()\r
+Connection::~Connection()\r
{\r
Disconnect();\r
#ifdef _WIN32\r
WSACleanup();\r
#endif\r
-\r
- delete [] m_tempbuffer;\r
-\r
}\r
\r
-\r
-const bool FCPv2::Connect(const char *host, const int port)\r
+const bool Connection::Connect(const std::string &fcphost, const int fcpport)\r
{\r
- // disconnect socket to server if it is currently open\r
- if(Connected())\r
+\r
+ m_sendbuffer.clear();\r
+ m_receivebuffer.clear();\r
+\r
+ if(IsConnected()==true)\r
{\r
Disconnect();\r
}\r
\r
int rval=-1;\r
- struct sockaddr_storage m_serveraddr;\r
-\r
std::ostringstream portstring;\r
addrinfo hint,*result,*current;\r
- result=NULL;\r
- portstring << port;\r
\r
- memset(&hint,0,sizeof(addrinfo));\r
+ result=current=0;\r
+ portstring << fcpport;\r
+ std::memset(&hint,0,sizeof(hint));\r
hint.ai_socktype=SOCK_STREAM;\r
- rval=getaddrinfo(host,portstring.str().c_str(),&hint,&result);\r
\r
- // erase any data in buffers\r
- m_sendbuffer.clear();\r
- m_receivebuffer.clear();\r
+ rval=getaddrinfo(fcphost.c_str(),portstring.str().c_str(),&hint,&result);\r
\r
if(result)\r
{\r
- for(current=result; current!=NULL && m_serversocket==-1; current=current->ai_next)\r
+ for(current=result; current!=0 && m_socket==-1; current=current->ai_next)\r
{\r
- memset(&m_serveraddr,0,sizeof(struct sockaddr_storage));\r
\r
- m_serversocket=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
+ m_socket=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
\r
- if(m_serversocket!=-1)\r
+ if(m_socket!=-1)\r
{\r
- rval=connect(m_serversocket,current->ai_addr,current->ai_addrlen);\r
+ rval=connect(m_socket,current->ai_addr,current->ai_addrlen);\r
if(rval==-1)\r
{\r
Disconnect();\r
}\r
}\r
+\r
}\r
\r
freeaddrinfo(result);\r
\r
}\r
\r
-const bool FCPv2::Disconnect()\r
+const bool Connection::Disconnect()\r
{\r
- if(Connected())\r
+ m_sendbuffer.clear();\r
+ m_receivebuffer.clear();\r
+ if(IsConnected())\r
{\r
#ifdef _WIN32\r
- closesocket(m_serversocket);\r
+ closesocket(m_socket);\r
#else\r
- close(m_serversocket);\r
+ close(m_socket);\r
#endif\r
- m_serversocket=-1;\r
+ m_socket=-1;\r
}\r
return true;\r
}\r
\r
-int FCPv2::FindOnReceiveBuffer(const char *text)\r
+void Connection::DoReceive()\r
{\r
- bool found;\r
- std::vector<char>::size_type i,j;\r
- size_t tlen=strlen(text);\r
-\r
- if(m_receivebuffer.size()>=tlen)\r
+ if(IsConnected())\r
{\r
- for(i=0; i<=m_receivebuffer.size()-tlen; i++)\r
+ int len=recv(m_socket,&m_tempbuffer[0],m_tempbuffer.size(),0);\r
+ if(len>0)\r
{\r
- found=true;\r
- for(j=0; j<tlen; j++)\r
- {\r
- if(m_receivebuffer[i+j]!=text[j])\r
- {\r
- found=false;\r
- j=tlen;\r
- }\r
- }\r
- if(found==true)\r
- {\r
- return i;\r
- }\r
+ m_receivebuffer.insert(m_receivebuffer.end(),m_tempbuffer.begin(),m_tempbuffer.begin()+len);\r
+ }\r
+ else\r
+ {\r
+ Disconnect();\r
}\r
}\r
+}\r
\r
- return -1;\r
+void Connection::DoSend()\r
+{\r
+ if(IsConnected() && m_sendbuffer.size()>0)\r
+ {\r
+ int len=send(m_socket,&m_sendbuffer[0],m_sendbuffer.size(),0);\r
+ if(len>0)\r
+ {\r
+ m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+len);\r
+ }\r
+ else\r
+ {\r
+ Disconnect();\r
+ }\r
+ }\r
}\r
\r
-FCPMessage FCPv2::ReceiveMessage()\r
+const bool Connection::MessageReady() const\r
{\r
- int field=0;\r
- int len=0;\r
- int endlen=0;\r
- int endmessage=-1;\r
- char *buffpos;\r
- char *prevpos;\r
- char *buffer;\r
+ std::vector<char>::const_iterator tempi;\r
+ std::vector<char>::size_type temp;\r
+ return MessageReady(tempi,temp);\r
+}\r
\r
- FCPMessage message;\r
+const bool Connection::MessageReady(std::vector<char>::const_iterator &endpos, std::vector<char>::size_type &endlen) const\r
+{\r
+ static std::string alldatastring="AllData\n";\r
+ static std::string datastring="\nData\n"; // need the \n at the beginning to differentiate from AllData\n\r
+ static std::string endmessagestring="EndMessage\n";\r
+ std::vector<char>::const_iterator tempendpos=m_receivebuffer.end();\r
+ std::vector<char>::size_type tempendlen=0;\r
\r
- // there is data on the receive buffer\r
if(m_receivebuffer.size()>0)\r
{\r
-\r
- // find Data on a line by itself following AllData\r
- if(FindOnReceiveBuffer("AllData\n")==0)\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),alldatastring.begin(),alldatastring.end());\r
+ if(tempendpos==m_receivebuffer.begin())\r
{\r
- endmessage=FindOnReceiveBuffer("\nData\n");\r
- if(endmessage!=-1)\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),datastring.begin(),datastring.end());\r
+ if(tempendpos!=m_receivebuffer.end())\r
{\r
- endmessage++;\r
- endlen=5;\r
+ tempendpos+=1;\r
+ tempendlen=datastring.size()-1;\r
}\r
}\r
- // otherwise this is a regular message - search for EndMessage\r
else\r
{\r
- endmessage=FindOnReceiveBuffer("EndMessage\n");\r
- endlen=11;\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),endmessagestring.begin(),endmessagestring.end());\r
+ tempendlen=endmessagestring.size();\r
}\r
\r
- // continue if we found "EndMessage\n" or "Data\n"\r
- if(endmessage!=-1)\r
+ if(tempendpos!=m_receivebuffer.end())\r
{\r
- // total length of message (including ending \n)\r
- len=endmessage+endlen;\r
-\r
- // allocate space for message\r
- buffer=new char[len+1];\r
-\r
- // copy message from receive buffer to message buffer\r
- std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,buffer);\r
- buffer[len]='\0';\r
-\r
- // remove from receive buffer\r
- m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
-\r
- // set buffer position\r
- buffpos=buffer;\r
-\r
- // find message name\r
- buffpos=strtok(buffer,"\n");\r
- message.SetName(buffer);\r
-\r
- do\r
- {\r
- // find next field\r
- prevpos=buffpos;\r
- buffpos=strtok(NULL,"=");\r
-\r
- // continue if we aren't at the end of a regular message, or at Data for an AllData message\r
- 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
- {\r
-\r
- // find next value\r
- prevpos=buffpos;\r
- buffpos=strtok(NULL,"\n");\r
-\r
- if(prevpos && buffpos)\r
- {\r
- message[prevpos]=buffpos;\r
- }\r
-\r
- field++;\r
- }\r
- else\r
- {\r
- buffpos=0;\r
- }\r
-\r
- }while(buffpos!=0);\r
-\r
- delete [] buffer;\r
-\r
+ endpos=tempendpos;\r
+ endlen=tempendlen;\r
+ return true;\r
}\r
+\r
}\r
\r
- return message;\r
+ return false;\r
}\r
\r
-const long FCPv2::ReceiveRaw(char *data, long &datalen)\r
+const bool Connection::MessageReady(std::vector<char>::iterator &endpos, std::vector<char>::size_type &endlen)\r
{\r
- long len=0;\r
- if(m_receivebuffer.size()>0 && datalen>0)\r
+ static std::string alldatastring="AllData\n";\r
+ static std::string datastring="\nData\n"; // need the \n at the beginning to differentiate from AllData\n\r
+ static std::string endmessagestring="EndMessage\n";\r
+ std::vector<char>::iterator tempendpos=m_receivebuffer.end();\r
+ std::vector<char>::size_type tempendlen=0;\r
+\r
+ if(m_receivebuffer.size()>0)\r
{\r
- if(datalen>m_receivebuffer.size())\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),alldatastring.begin(),alldatastring.end());\r
+ if(tempendpos==m_receivebuffer.begin())\r
{\r
- len=m_receivebuffer.size();\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),datastring.begin(),datastring.end());\r
+ if(tempendpos!=m_receivebuffer.end())\r
+ {\r
+ tempendpos+=1;\r
+ tempendlen=datastring.size()-1;\r
+ }\r
}\r
else\r
{\r
- len=datalen;\r
+ tempendpos=std::search(m_receivebuffer.begin(),m_receivebuffer.end(),endmessagestring.begin(),endmessagestring.end());\r
+ tempendlen=endmessagestring.size();\r
}\r
\r
- std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,data);\r
-\r
- // erase bytes from receive buffer\r
- m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+ if(tempendpos!=m_receivebuffer.end())\r
+ {\r
+ endpos=tempendpos;\r
+ endlen=tempendlen;\r
+ return true;\r
+ }\r
\r
}\r
- datalen=len;\r
- return datalen;\r
-}\r
\r
-void FCPv2::SendBufferedText(const char *text)\r
-{\r
- unsigned int i;\r
- for(i=0; i<strlen(text); i++)\r
- {\r
- m_sendbuffer.push_back(text[i]);\r
- }\r
+ return false;\r
}\r
\r
-void FCPv2::SendBufferedRaw(const char *data, const long len)\r
+const bool Connection::Receive(Message &message)\r
{\r
- int i;\r
- for(i=0; i<len; i++)\r
+ std::vector<char>::iterator endpos;\r
+ std::vector<char>::size_type endlen;\r
+ if(MessageReady(endpos,endlen)==true)\r
{\r
- m_sendbuffer.push_back(data[i]);\r
- }\r
-}\r
+ std::vector<std::string> fields;\r
\r
-const int FCPv2::SendMessage(const char *messagename, const int fieldcount, ...)\r
-{\r
- va_list args;\r
- const char *field;\r
- const char *val;\r
- std::vector<char>::size_type bytecount=0;\r
- int i;\r
- std::vector<char>::size_type startlen;\r
+ Split(std::string(m_receivebuffer.begin(),endpos),"\n=",fields);\r
+ m_receivebuffer.erase(m_receivebuffer.begin(),endpos+endlen);\r
\r
- startlen=m_sendbuffer.size();\r
+ message.Clear();\r
\r
- SendBufferedText(messagename);\r
- SendBufferedText("\n");\r
-\r
- va_start(args,fieldcount);\r
+ if(fields.size()>0)\r
+ {\r
+ message.SetName(fields[0]);\r
+ }\r
\r
- for(i=0; i<fieldcount; i++)\r
- {\r
- field=va_arg(args,const char *);\r
- val=va_arg(args,const char *);\r
+ if(fields.size()>1)\r
+ {\r
+ for(std::vector<std::string>::iterator i=fields.begin()+1; i!=fields.end();)\r
+ {\r
+ if(i+1!=fields.end())\r
+ {\r
+ message.GetFields()[(*i)]=(*(i+1));\r
+ i+=2;\r
+ }\r
+ else\r
+ {\r
+ i++;\r
+ }\r
+ }\r
+ }\r
\r
- SendBufferedText(field);\r
- SendBufferedText("=");\r
- SendBufferedText(val);\r
- SendBufferedText("\n");\r
}\r
-\r
- SendBufferedText("EndMessage\n");\r
-\r
- bytecount=m_sendbuffer.size()-startlen;\r
- \r
- va_end(args);\r
-\r
- return bytecount;\r
+ return false;\r
}\r
\r
-const int FCPv2::SendMessage(FCPMessage &message)\r
+const bool Connection::Receive(std::vector<char> &data, const std::vector<char>::size_type len)\r
{\r
- std::vector<char>::size_type bytecount=0;\r
- std::vector<char>::size_type startlen;\r
- FCPMessage::iterator i;\r
-\r
- startlen=m_sendbuffer.size();\r
-\r
- if(message.GetName()!="")\r
+ if(m_receivebuffer.size()>=len && len>=0)\r
{\r
- SendBufferedText(message.GetName().c_str());\r
- SendBufferedText("\n");\r
-\r
- for(i=message.begin(); i!=message.end(); i++)\r
- {\r
- SendBufferedText((*i).first.c_str());\r
- SendBufferedText("=");\r
- SendBufferedText((*i).second.c_str());\r
- SendBufferedText("\n");\r
- }\r
-\r
- SendBufferedText("EndMessage\n");\r
+ data.insert(data.end(),m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+ m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return false;\r
}\r
-\r
- bytecount=m_sendbuffer.size()-startlen;\r
-\r
- return bytecount;\r
}\r
\r
-\r
-const int FCPv2::SendRaw(const char *data, const int datalen)\r
+const bool Connection::Receive(char *data, const size_t len)\r
{\r
- int bytecount=datalen;\r
-\r
- if(bytecount>0)\r
+ if(m_receivebuffer.size()>=len && len>=0)\r
{\r
- SendBufferedRaw(data,datalen);\r
+ std::copy(m_receivebuffer.begin(),m_receivebuffer.begin()+len,data);\r
+ m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ return false;\r
}\r
-\r
- return bytecount;\r
-\r
}\r
\r
-void FCPv2::SocketReceive()\r
+const bool Connection::ReceiveIgnore(const size_t len)\r
{\r
- int len=0;\r
-\r
- len=recv(m_serversocket,m_tempbuffer,65535,0);\r
-\r
- if(len>0)\r
+ if(m_receivebuffer.size()>=len && len>=0)\r
{\r
-\r
- m_receivebuffer.resize(m_receivebuffer.size()+len);\r
- std::copy(m_tempbuffer,&m_tempbuffer[len],m_receivebuffer.end()-len);\r
-\r
+ m_receivebuffer.erase(m_receivebuffer.begin(),m_receivebuffer.begin()+len);\r
+ return true;\r
}\r
- // there was an error or server closed connection - disconnect socket\r
else\r
{\r
- Disconnect();\r
+ return false;\r
}\r
}\r
\r
-void FCPv2::SocketSend()\r
+const bool Connection::Send(const Message &message)\r
{\r
- int len=0;\r
- if(m_sendbuffer.size()>0)\r
+ if(message.GetName()!="")\r
{\r
- len=send(m_serversocket,&m_sendbuffer[0],m_sendbuffer.size(),0);\r
- if(len>0)\r
- {\r
- // move remaining data in buffer to beginning of buffer (erase the bytes we just sent)\r
- m_sendbuffer.erase(m_sendbuffer.begin(),m_sendbuffer.begin()+len);\r
- }\r
- // there was an error with send - disconnect socket\r
- else\r
- {\r
- Disconnect();\r
- }\r
+ std::string fcpstring=message.GetFCPString();\r
+ m_sendbuffer.insert(m_sendbuffer.end(),fcpstring.begin(),fcpstring.end());\r
+ return true;\r
}\r
+ return false;\r
}\r
\r
+const bool Connection::Send(const std::vector<char> &data)\r
+{\r
+ m_sendbuffer.insert(m_sendbuffer.end(),data.begin(),data.end());\r
+ return true;\r
+}\r
\r
-const bool FCPv2::Update(const long waittime)\r
+const bool Connection::Send(const char *data, const size_t len)\r
{\r
+ if(data)\r
+ {\r
+ m_sendbuffer.insert(m_sendbuffer.end(),data[0],data[0]+len);\r
+ return true; \r
+ }\r
+ return false;\r
+}\r
\r
- if(Connected())\r
+void Connection::Split(const std::string &str, const std::string &separators, std::vector<std::string> &elements)\r
+{\r
+ std::string::size_type offset = 0;\r
+ std::string::size_type delimIndex = 0;\r
+ \r
+ delimIndex = str.find_first_of(separators, offset);\r
+\r
+ while (delimIndex != std::string::npos)\r
+ {\r
+ elements.push_back(str.substr(offset, delimIndex - offset));\r
+ offset += delimIndex - offset + 1;\r
+ delimIndex = str.find_first_of(separators, offset);\r
+ }\r
+\r
+ elements.push_back(str.substr(offset));\r
+}\r
+\r
+const bool Connection::Update(const unsigned long ms)\r
+{\r
+ if(IsConnected())\r
{\r
- m_timeval.tv_sec=waittime;\r
- m_timeval.tv_usec=0;\r
+ m_timeval.tv_sec=ms/1000;\r
+ m_timeval.tv_usec=(ms%1000)*1000;\r
\r
FD_ZERO(&m_readfs);\r
FD_ZERO(&m_writefs);\r
\r
- FD_SET(m_serversocket,&m_readfs);\r
- \r
+ FD_SET(m_socket,&m_readfs);\r
+\r
if(m_sendbuffer.size()>0)\r
{\r
- FD_SET(m_serversocket,&m_writefs);\r
+ FD_SET(m_socket,&m_writefs);\r
}\r
\r
- select(m_serversocket+1,&m_readfs,&m_writefs,0,&m_timeval);\r
+ select(m_socket+1,&m_readfs,&m_writefs,0,&m_timeval);\r
\r
- if(FD_ISSET(m_serversocket,&m_readfs))\r
+ if(FD_ISSET(m_socket,&m_readfs))\r
{\r
- SocketReceive();\r
+ DoReceive();\r
}\r
- if(Connected() && FD_ISSET(m_serversocket,&m_writefs))\r
+ if(IsConnected() && FD_ISSET(m_socket,&m_writefs))\r
{\r
- SocketSend();\r
+ DoSend();\r
}\r
\r
- return true;\r
+ }\r
\r
+ if(IsConnected())\r
+ {\r
+ return true;\r
}\r
else\r
{\r
}\r
\r
}\r
+\r
+const bool Connection::WaitForBytes(const unsigned long ms, const size_t len)\r
+{\r
+ while(IsConnected() && m_receivebuffer.size()<len)\r
+ {\r
+ Update(ms);\r
+ }\r
+ \r
+ if(IsConnected() && m_receivebuffer.size()>=len)\r
+ {\r
+ return true; \r
+ }\r
+ else\r
+ {\r
+ return false; \r
+ }\r
+}\r
+\r
+} // namespace\r