diff --git a/common/except.hpp b/common/except.hpp index d92ec11..6ce31ce 100755 --- a/common/except.hpp +++ b/common/except.hpp @@ -47,4 +47,11 @@ public: InvalidStateException(const String &reason="InvalidStateException"):Exception(reason){;} String toString(){return getReason();} }; + +class InvalidOperationException : public Exception +{ +public: + InvalidOperationException(const String &reason="InvalidOperationException"):Exception(reason){;} + String toString(){return getReason();} +}; #endif diff --git a/common/stringbuffer.hpp b/common/stringbuffer.hpp new file mode 100644 index 0000000..48521a9 --- /dev/null +++ b/common/stringbuffer.hpp @@ -0,0 +1,93 @@ +#ifndef _COMMON_STRINGBUFFER_HPP_ +#define _COMMON_STRINGBUFFER_HPP_ +#ifndef _COMMON_STRING_HPP_ +#include +#endif +#ifndef _COMMON_ARRAY_HPP_ +#include +#endif + +class StringBuffer +{ +public: + StringBuffer(); + StringBuffer(DWORD initialSize); + virtual ~StringBuffer(); + StringBuffer &append(const String &string); + StringBuffer &append(const char &ch); + void growBy(DWORD growBy); + String toString(void)const; +private: + enum{GrowBy=2048}; + void preallocate(DWORD items); + Array mInternalRep; + DWORD mItemCount; + DWORD mGrowBy; +}; + + +inline +StringBuffer::StringBuffer() +: mGrowBy(GrowBy), mItemCount(0) +{ + mInternalRep.size(mGrowBy); +} + +inline +StringBuffer::StringBuffer(DWORD initialSize) +: mGrowBy(initialSize?initialSize:GrowBy), mItemCount(0) +{ + mInternalRep.size(mGrowBy); +} + +inline +StringBuffer::~StringBuffer() +{ +} + +inline +StringBuffer &StringBuffer::append(const String &string) +{ + int length(string.length()); + preallocate(length); + ::memcpy(&mInternalRep[mItemCount],string.str(),length); + mItemCount+=length; + return *this; +} + +inline +StringBuffer &StringBuffer::append(const char &ch) +{ + preallocate(1); + mInternalRep[mItemCount]=ch; + mItemCount++; + return *this; +} + +inline +void StringBuffer::preallocate(DWORD items) +{ + if(mInternalRep.size()>mItemCount+items)return; + Array tmpArray; + tmpArray.size(mInternalRep.size()+(mGrowBy>items?mGrowBy:items)); + ::memcpy(&tmpArray[0],&mInternalRep[0],mInternalRep.size()); + mInternalRep.size(tmpArray.size()); + ::memcpy(&mInternalRep[0],&tmpArray[0],mItemCount); +} + +inline +void StringBuffer::growBy(DWORD growBy) +{ + if(growBy)mGrowBy=growBy; +} + +inline +String StringBuffer::toString(void)const +{ + String str; + str.reserve(mItemCount+1); + ::memcpy(str.str(),&((Array&)mInternalRep)[0],mItemCount); + (str.str())[mItemCount]=0; + return str; +} +#endif \ No newline at end of file diff --git a/listener/SocketConnectionReceiver.cpp b/listener/SocketConnectionReceiver.cpp index e618f3f..f87bfc7 100644 --- a/listener/SocketConnectionReceiver.cpp +++ b/listener/SocketConnectionReceiver.cpp @@ -1,5 +1,6 @@ #include #include +#include SocketConnectionReceiver::SocketConnectionReceiver(int socket, sockaddr_in internalSocketAddress) : mSocket(socket), mInternalSocketAddress(internalSocketAddress) @@ -32,7 +33,6 @@ void SocketConnectionReceiver::threadFunction(int data) if(line=="QUIT" || line=="quit")break; Block commands = line.split('|'); if(0==commands.size())continue; - std::cout << commands[0] << std::endl; commands[0].upper(); if(commands[0]=="PUT") { @@ -75,14 +75,16 @@ bool SocketConnectionReceiver::handlePut(Block &commands) while(true) { - readLine(strLine); - strLine.makeBlock(subCommands, "|"); - if(subCommands.size()!=2 || !(subCommands[0]=="PCKT")) + size_t bufferLength=0; + try { - std::cout << "Unexpected command sequence" << std::endl; + bufferLength = expectPacket(); + } + catch(Exception &exception) + { + std::cerr << exception.toString() << '\n'; break; } - int bufferLength = subCommands[1].toLong(); if(0==bufferLength) { std::cout << "Client indicated end of data" << std::endl; @@ -109,11 +111,39 @@ bool SocketConnectionReceiver::handlePut(Block &commands) } std::cout << "Transfer complete" << std::endl; - std::cout << "Received " << totalBytesRead << std::endl; + std::cout << "Received " << totalBytesRead << " in " << Utility::formatNumber(profiler.end()) << "(ms)" << std::endl; writeFile.close(); return totalBytesRead==fileLength; } +size_t SocketConnectionReceiver::expectPacket(void) +{ + Block subCommands; + String strLine; + readLine(strLine); + strLine.makeBlock(subCommands, "|"); + if(subCommands.size()!=2) + { + StringBuffer sb; + sb.append("Received an invalid PCKT command"); + String str=sb.toString(); + std::cout << str << std::endl; + throw new InvalidOperationException(str); + } + if(!(subCommands[0]=="PCKT")) + { + + StringBuffer sb; + sb.append("Unexpected command sequence."); + sb.append("Expected PCKT but received ").append(subCommands[0]); + String str = sb.toString(); + std::cout << str << std::endl; + throw new InvalidOperationException(str); + } + size_t bufferLength = subCommands[1].toULong(); + return bufferLength; +} + size_t SocketConnectionReceiver::readLine(String &line) { size_t bytes_read = 0; diff --git a/listener/SocketConnectionReceiver.hpp b/listener/SocketConnectionReceiver.hpp index f33f967..116d9d0 100644 --- a/listener/SocketConnectionReceiver.hpp +++ b/listener/SocketConnectionReceiver.hpp @@ -24,6 +24,7 @@ class SocketConnectionReceiver void threadFunction(int data); bool handlePut(Block &commands); size_t readLine(String &line); + size_t expectPacket(void); size_t read(Array &buffer); String restoreFileName(Block block,DWORD startIndex,DWORD endIndex); diff --git a/listener/main.cpp b/listener/main.cpp index 76aef44..67d4cb7 100644 --- a/listener/main.cpp +++ b/listener/main.cpp @@ -57,7 +57,7 @@ int main(int argc, char **argv) } return 0; - std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl; + std::cout << "Done, total took " << Utility::formatNumber(profiler.end()) << "(ms)" << std::endl; } /// @brief [0]=program [1]=SERVERMODE [2]={port} @@ -75,7 +75,7 @@ void handleServer(Block &commands) std::cout << commands[1] << ":" << commands[2] << std::endl; SocketServer socketServer(commands[2].toInt()); socketServer.listen(); - std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl; + std::cout << "Done, total took " << Utility::formatNumber(profiler.end()) << "(ms)" << std::endl; } /// @brief [0]=program, [1]=CLIENTMODE, [2]=serveripaddress, [3]=serverport, [4]=pathfilename @@ -99,5 +99,5 @@ void handleClient(Block &commands) { std::cout << "Transfer complete" << std::endl; } - std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl; + std::cout << "Done, total took " << Utility::formatNumber(profiler.end()) << "(ms)" << std::endl; } diff --git a/listener/scraps.txt b/listener/scraps.txt deleted file mode 100644 index 9159032..0000000 --- a/listener/scraps.txt +++ /dev/null @@ -1,435 +0,0 @@ -// class ClientSocketSender -// { -// public: -// ClientSocketSender(String ipAddress,int port); -// virtual ~ClientSocketSender(); -// bool sendFile(String &pathFileName); -// bool isOkay(void); -// private: -// static constexpr int BUFFER_LENGTH=65536; -// void close(void); -// bool sendPacketIndicator(long bytesToSend); -// bool sendPacket(Array &buffer,long bytesToSend); -// bool sendPutIndicator(String fileName,long fileLength); -// bool sendQuit(void); - -// struct sockaddr_in mInternalSocketAddress; -// int mSocket; -// String mIPAddress; -// int mPort; -// }; - -// inline -// ClientSocketSender::ClientSocketSender(String ipAddress, int port) -// : mIPAddress(ipAddress), mPort(port) -// { -// mSocket = ::socket(AF_INET,SOCK_STREAM,0); -// if(!isOkay()) -// { -// std::cout << "Unable to initialize socket " << std::endl; -// return; -// } -// mInternalSocketAddress.sin_family = AF_INET; -// mInternalSocketAddress.sin_port= ::htons(mPort); -// int result = ::inet_pton(AF_INET, ipAddress.str(), &mInternalSocketAddress.sin_addr); -// if(result<0) -// { -// std::cout << "Unable to convert ipaddress to network address" << std::endl; -// close(); -// return; -// } -// result = ::connect(mSocket, (struct sockaddr*)&mInternalSocketAddress, sizeof(mInternalSocketAddress)); -// if(result<0) -// { -// close(); -// std::cout << "Unable to connect to host " << mIPAddress << ":" << mPort << std::endl; -// } -// } - -// inline -// ClientSocketSender::~ClientSocketSender() -// { -// close(); -// } - -// inline -// void ClientSocketSender::close(void) -// { -// if(-1!=mSocket) -// { -// ::close(mSocket); -// mSocket=-1; -// } -// } - -// inline -// bool ClientSocketSender::sendFile(String &pathFileName) -// { -// FileIO readFile(pathFileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadOnly, FileIO::CreationFlags::None); -// if(!readFile.isOkay()) -// { -// std::cout << "File open failed " << pathFileName << std::endl; -// return false; -// } -// readFile.setBufferLength(BUFFER_LENGTH); -// DWORD fileLength = readFile.size(); -// sendPutIndicator(pathFileName, fileLength); -// Array readBuffer; -// readBuffer.size(BUFFER_LENGTH); -// while(true) -// { -// size_t bytesRead = readFile.read(&readBuffer[0], readBuffer.size()); -// if(0==bytesRead) -// { -// std::cout << "No data was read from the file" << std::endl; -// break; -// } -// sendPacketIndicator(bytesRead); -// sendPacket(readBuffer, bytesRead); -// if(bytesRead parts = fileName.split('/'); -// String pureFileName = parts[parts.size()-1]; -// String putIndicator = "PUT|"; -// putIndicator+=pureFileName; -// putIndicator+="|"; -// putIndicator+=String().fromInt(fileLength); -// putIndicator+="\r\n"; -// ::send(mSocket, (char*)putIndicator, putIndicator.length(),0); -// return true; -// } - -// inline -// bool ClientSocketSender::sendQuit(void) -// { -// if(!isOkay())return false; -// String quitIndicator = "QUIT\r\n"; -// ::send(mSocket, (char*)quitIndicator, quitIndicator.length(),0); -// return true; -// } - -// inline -// bool ClientSocketSender::sendPacket(Array &buffer,long bytesToSend) -// { -// if(!isOkay())return false; -// ::send(mSocket, (char*)&buffer[0], bytesToSend,0); -// return true; -// } - -// inline -// bool ClientSocketSender::isOkay(void) -// { -// return -1==mSocket?false:true; -// } - -// *********************************************************************************************************************************************************** -// *********************************************************************************************************************************************************** -// *********************************************************************************************************************************************************** - -// class SocketConnectionReceiver -// { -// public: -// SocketConnectionReceiver(int socket, sockaddr_in inernalSocketAddress); -// virtual ~SocketConnectionReceiver(); -// void close(void); -// private: -// static constexpr int BUFFER_LENGTH=65536; // this is the buffer length for the socket -// void threadFunction(int data); -// bool handlePut(Block &commands); -// int readLine(String &line); -// long read(Array &buffer); -// String restoreFileName(Block block,DWORD startIndex,DWORD endIndex); - -// friend class SocketServer; -// char mBuffer[BUFFER_LENGTH] = {0}; -// int mSocket; -// sockaddr_in mInternalSocketAddress; -// }; - -// inline -// SocketConnectionReceiver::SocketConnectionReceiver(int socket, sockaddr_in internalSocketAddress) -// : mSocket(socket), mInternalSocketAddress(internalSocketAddress) -// { -// } - -// inline -// SocketConnectionReceiver::~SocketConnectionReceiver() -// { -// } - -// inline -// void SocketConnectionReceiver::close(void) -// { -// if(-1==mSocket)return; -// std::cout << "Closing connection " << mSocket << std::endl; -// ::close(mSocket); -// mSocket=-1; -// } - -// inline -// void SocketConnectionReceiver::threadFunction(int data) -// { -// String line; -// while(true) -// { -// readLine(line); -// if(0==line.length()) -// { -// std::cout << "Received an empty command" << std::endl; -// break; -// } -// // std::cout << "'" << (char*)line << "'" << std::endl; -// if(line=="QUIT" || line=="quit")break; -// Block commands = line.split('|'); -// if(0==commands.size())continue; -// std::cout << commands[0] << std::endl; -// commands[0].upper(); -// if(commands[0]=="PUT") -// { -// handlePut(commands); -// } -// else -// { -// std::cout << "Unrecognized command >" << line << "<" << std::endl; -// } -// } -// close(); -// return; -// } - -// /// @brief The client wants to put a file. put {filename} {lengthbytes} -// /// @param commands [0]=PUT, [1]=filename, [2]=total length -// /// This will read PCKT {length}. -// /// The connection will continue reading and writing until it receives PCKT 0 -// /// @return -// inline -// bool SocketConnectionReceiver::handlePut(Block &commands) -// { -// Array receiveBuffer; -// Block subCommands; -// String strLine; -// String fileName; -// long fileLength; -// long totalBytesRead=0; - -// fileName = commands[1]; -// fileLength = commands[commands.size()-1].toLong(); -// std::cout << "PUT" << " " << fileName << " " << fileLength << std::endl; -// FileIO writeFile(fileName, FileIO::ByteOrder::LittleEndian, FileIO::Mode::ReadWrite,FileIO::CreationFlags::CreateAlways); -// if(!writeFile.isOkay()) -// { -// std::cout << "Error creating " << fileName << std::endl; -// return false; -// } - -// while(true) -// { -// readLine(strLine); -// strLine.makeBlock(subCommands, "|"); -// if(subCommands.size()!=2 || !(subCommands[0]=="PCKT")) -// { -// std::cout << "Unexpected command sequence" << std::endl; -// break; -// } -// int bufferLength = subCommands[1].toLong(); -// if(0==bufferLength) -// { -// std::cout << "Client indicated end of data" << std::endl; -// break; -// } -// receiveBuffer.size(bufferLength); -// long bytes_read = read(receiveBuffer); -// totalBytesRead+=bytes_read; -// if(bufferLength!=bytes_read) -// { -// std::cout << "Send/Receive size mismatch. The client indicated a data length of " << bufferLength << " but a data length of " << bytes_read << " was received"; -// break; -// } -// writeFile.write(&receiveBuffer[0], receiveBuffer.size()); -// int percent = ((double)totalBytesRead / (double)fileLength)*100.00; -// if(0==(percent%10)) -// { -// std::cout << "Transferred " << totalBytesRead << " of " << fileLength << " " << percent << " percent" << std::endl; -// } - -// } -// std::cout << "Transfer complete" << std::endl; -// std::cout << "Received " << totalBytesRead << std::endl; -// writeFile.close(); -// return totalBytesRead==fileLength; -// } - -// inline -// int SocketConnectionReceiver::readLine(String &line) -// { -// int bytes_read = 0; -// int total_bytes = 0; -// char ch; - -// char *lpLineBuffer = (char*)line; -// while (total_bytes < line.lengthBytes() - 1) -// { -// bytes_read = ::recv(mSocket, &ch, 1, 0); -// if (bytes_read <= 0) -// { -// return bytes_read; -// } -// if (ch=='\r') // Carriage return -// { -// recv(mSocket, &ch, 1, 0); // consume the line feed -// break; -// } -// lpLineBuffer[total_bytes++] = ch; -// } -// lpLineBuffer[total_bytes] = '\0'; -// return total_bytes; -// } - -// inline -// long SocketConnectionReceiver::read(Array &buffer) -// { -// long bytes_read = 0; -// long bytes_to_read = buffer.size(); -// long total_bytes_read =0; - -// char *lpLineBuffer = (char*)&buffer[0]; -// while(bytes_to_read>0) -// { -// bytes_read = ::recv(mSocket, lpLineBuffer, bytes_to_read, 0); -// lpLineBuffer+=bytes_read; -// bytes_to_read -= bytes_read; -// total_bytes_read += bytes_read; -// } -// return total_bytes_read; -// } - -// *********************************************************************************************************************************************************** -// *********************************************************************************************************************************************************** -// *********************************************************************************************************************************************************** - - -// class SocketServer -// { -// public: -// SocketServer(int port); -// virtual ~SocketServer(); -// void listen(void); -// void close(void); -// bool isOkay(void); -// private: - -// static constexpr int MAX_CONNECTIONS=10; // The maximum connections to be queued at a time -// bool mIsOkay; -// int mListenPort; -// int mSocketFileDescriptor; -// struct sockaddr_in mInternalSocketAddress; -// socklen_t mAddressLength = sizeof(mInternalSocketAddress); -// std::vector mExecutionThreads; -// }; - -// /// @brief This will construct the socket listener. You must then call listen() to listen for connections -// /// @param port -// inline -// SocketServer::SocketServer(int port) -// : mListenPort(port), mIsOkay(false), mSocketFileDescriptor(-1) -// { -// std::cout << "SocketServer()" << std::endl; -// int opt=-1; -// int result; - -// // create socket file descriptor -// mSocketFileDescriptor = ::socket(AF_INET,SOCK_STREAM,0); -// if(0==mSocketFileDescriptor)return; - -// // attach socket to port -// result = ::setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); -// if(result) -// { -// close(); -// return; -// } - -// // bind socket to network address and port -// mInternalSocketAddress.sin_family = AF_INET; -// mInternalSocketAddress.sin_addr.s_addr=INADDR_ANY; - - -// mInternalSocketAddress.sin_port = htons(mListenPort); -// result = ::bind(mSocketFileDescriptor,(struct sockaddr*)&mInternalSocketAddress,sizeof(mInternalSocketAddress)); -// if(result) -// { -// close(); -// return; -// } -// mIsOkay=true; -// } - -// inline -// SocketServer::~SocketServer() -// { -// std::cout << "~SocketServer()" << std::endl; -// close(); -// } - -// inline -// bool SocketServer::isOkay(void) -// { -// return mIsOkay; -// } - -// inline -// void SocketServer::listen(void) -// { -// while(isOkay()) -// { -// std::cout << "Listening on port " << mListenPort << std::endl; -// int result = ::listen(mSocketFileDescriptor, MAX_CONNECTIONS); -// if(result) -// { -// std::cout << "Error listening on port " << mListenPort << std::endl; -// close(); -// return; -// } -// struct sockaddr_in internalSocketAddress; -// socklen_t addressLength = sizeof(internalSocketAddress); - -// int socket = ::accept(mSocketFileDescriptor, (struct sockaddr*)&internalSocketAddress, &addressLength); -// if(result) -// { -// std::cout << "Error accepting connection " << mListenPort << std::endl; -// close(); -// return; -// } -// SocketConnectionReceiver socketConnectionReceiver(socket, internalSocketAddress); -// mExecutionThreads.push_back(std::thread(&SocketConnectionReceiver::threadFunction, &socketConnectionReceiver, 0)); -// } -// } - -// inline -// void SocketServer::close(void) -// { -// if(-1!=mSocketFileDescriptor) -// { -// mSocketFileDescriptor=-1; -// } -// }