Initial Comit
This commit is contained in:
33
listener/.vscode/launch.json
vendored
Normal file
33
listener/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/listener",
|
||||
"args": ["SERVERMODE","55000"],
|
||||
"stopAtEntry": true,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Set Disassembly Flavor to Intel",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
57
listener/.vscode/settings.json
vendored
Normal file
57
listener/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"complex": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"thread": "cpp",
|
||||
"*.tpp": "cpp"
|
||||
}
|
||||
}
|
||||
28
listener/.vscode/tasks.json
vendored
Normal file
28
listener/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "C/C++: g++ build active file",
|
||||
"command": "/usr/bin/g++",
|
||||
"args": [
|
||||
"-fdiagnostics-color=always",
|
||||
"-g",
|
||||
"${file}",
|
||||
"-o",
|
||||
"${fileDirname}/${fileBasenameNoExtension}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${fileDirname}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Task generated by Debugger."
|
||||
}
|
||||
],
|
||||
"version": "2.0.0"
|
||||
}
|
||||
11
listener/CMakeLists.txt
Normal file
11
listener/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/home/pi/Boneyard")
|
||||
project(listener VERSION 0.1.0 LANGUAGES C CXX)
|
||||
|
||||
add_executable(listener main.cpp ClientSocketSender.cpp SocketConnectionReceiver.cpp SocketServer.cpp)
|
||||
|
||||
add_subdirectory(/home/pi/Boneyard/common /home/pi/Boneyard/common/build)
|
||||
target_link_libraries(listener PRIVATE common)
|
||||
|
||||
|
||||
|
||||
118
listener/ClientSocketSender.cpp
Normal file
118
listener/ClientSocketSender.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <listener/ClientSocketSender.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
ClientSocketSender::~ClientSocketSender()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void ClientSocketSender::close(void)
|
||||
{
|
||||
if(-1!=mSocket)
|
||||
{
|
||||
::close(mSocket);
|
||||
mSocket=-1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientSocketSender::sendFile(String &pathFileName)
|
||||
{
|
||||
Profiler profiler;
|
||||
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<char> 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<readBuffer.size())break;
|
||||
}
|
||||
sendPacketIndicator(0);
|
||||
sendQuit();
|
||||
readFile.close();
|
||||
std::cout << "SendFile done, total took " << profiler.end() << "(ms)" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientSocketSender::sendPacketIndicator(DWORD bytesToSend)
|
||||
{
|
||||
if(!isOkay())return false;
|
||||
String packetIndicator = "PCKT|";
|
||||
packetIndicator+=String().fromULong(bytesToSend);
|
||||
packetIndicator+="\r\n";
|
||||
::send(mSocket, (char*)packetIndicator, packetIndicator.length(),0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientSocketSender::sendPutIndicator(String fileName,DWORD fileLength)
|
||||
{
|
||||
if(!isOkay())return false;
|
||||
Block<String> parts = fileName.split('/');
|
||||
String pureFileName = parts[parts.size()-1];
|
||||
String putIndicator = "PUT|";
|
||||
putIndicator+=pureFileName;
|
||||
putIndicator+="|";
|
||||
putIndicator+=String().fromULong(fileLength);
|
||||
putIndicator+="\r\n";
|
||||
::send(mSocket, (char*)putIndicator, putIndicator.length(),0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientSocketSender::sendQuit(void)
|
||||
{
|
||||
if(!isOkay())return false;
|
||||
String quitIndicator = "QUIT\r\n";
|
||||
::send(mSocket, (char*)quitIndicator, quitIndicator.length(),0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientSocketSender::sendPacket(Array<char> &buffer,DWORD bytesToSend)
|
||||
{
|
||||
if(!isOkay())return false;
|
||||
::send(mSocket, (char*)&buffer[0], bytesToSend,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientSocketSender::isOkay(void)
|
||||
{
|
||||
return -1==mSocket?false:true;
|
||||
}
|
||||
37
listener/ClientSocketSender.hpp
Normal file
37
listener/ClientSocketSender.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef _LISTENER_CLIENTSOCKETSENDER_HPP_
|
||||
#define _LISTENER_CLIENTSOCKETSENDER_HPP_
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <thread>
|
||||
#include <common/string.hpp>
|
||||
#include <common/profiler.hpp>
|
||||
#include <common/block.hpp>
|
||||
#include <common/fileio.hpp>
|
||||
|
||||
class ClientSocketSender
|
||||
{
|
||||
public:
|
||||
ClientSocketSender(String ipAddress,int port);
|
||||
virtual ~ClientSocketSender();
|
||||
bool sendFile(String &pathFileName);
|
||||
bool isOkay(void);
|
||||
private:
|
||||
// static constexpr int BUFFER_LENGTH=65536;
|
||||
static constexpr int BUFFER_LENGTH=1048576;
|
||||
void close(void);
|
||||
bool sendPacketIndicator(DWORD bytesToSend);
|
||||
bool sendPacket(Array<char> &buffer,DWORD bytesToSend);
|
||||
bool sendPutIndicator(String fileName,DWORD fileLength);
|
||||
bool sendQuit(void);
|
||||
|
||||
struct sockaddr_in mInternalSocketAddress;
|
||||
int mSocket;
|
||||
String mIPAddress;
|
||||
int mPort;
|
||||
};
|
||||
#endif
|
||||
157
listener/SocketConnectionReceiver.cpp
Normal file
157
listener/SocketConnectionReceiver.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#include <listener/SocketConnectionReceiver.hpp>
|
||||
#include <common/utility.hpp>
|
||||
|
||||
SocketConnectionReceiver::SocketConnectionReceiver(int socket, sockaddr_in internalSocketAddress)
|
||||
: mSocket(socket), mInternalSocketAddress(internalSocketAddress)
|
||||
{
|
||||
}
|
||||
|
||||
SocketConnectionReceiver::~SocketConnectionReceiver()
|
||||
{
|
||||
}
|
||||
|
||||
void SocketConnectionReceiver::close(void)
|
||||
{
|
||||
if(-1==mSocket)return;
|
||||
std::cout << "Closing connection " << mSocket << std::endl;
|
||||
::close(mSocket);
|
||||
mSocket=-1;
|
||||
}
|
||||
|
||||
void SocketConnectionReceiver::threadFunction(int data)
|
||||
{
|
||||
String line;
|
||||
while(true)
|
||||
{
|
||||
readLine(line);
|
||||
if(0==line.length())
|
||||
{
|
||||
std::cout << "Received an empty command" << std::endl;
|
||||
break;
|
||||
}
|
||||
if(line=="QUIT" || line=="quit")break;
|
||||
Block<String> 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
|
||||
bool SocketConnectionReceiver::handlePut(Block<String> &commands)
|
||||
{
|
||||
Profiler profiler;
|
||||
Array<char> receiveBuffer;
|
||||
Block<String> subCommands;
|
||||
String strLine;
|
||||
String fileName;
|
||||
size_t fileLength;
|
||||
size_t 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);
|
||||
size_t 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());
|
||||
|
||||
double percent = ((double)totalBytesRead / (double)fileLength)*100.00;
|
||||
if(Utility::fmod(percent,10.00,0.0078125))
|
||||
{
|
||||
double elapsedTimeSeconds = profiler.elapsed()/1000.00;
|
||||
double bytesPerSecond = totalBytesRead / elapsedTimeSeconds;
|
||||
String strBytesPerSecond = Utility::bytesTransferredToString(bytesPerSecond);
|
||||
std::cout << "Transferred " << totalBytesRead << " of " << fileLength << " " << percent << " percent " << strBytesPerSecond << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
std::cout << "Transfer complete" << std::endl;
|
||||
std::cout << "Received " << totalBytesRead << std::endl;
|
||||
writeFile.close();
|
||||
return totalBytesRead==fileLength;
|
||||
}
|
||||
|
||||
size_t SocketConnectionReceiver::readLine(String &line)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
size_t 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;
|
||||
}
|
||||
|
||||
size_t SocketConnectionReceiver::read(Array<char> &buffer)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
size_t bytes_to_read = buffer.size();
|
||||
size_t 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;
|
||||
}
|
||||
35
listener/SocketConnectionReceiver.hpp
Normal file
35
listener/SocketConnectionReceiver.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _LISTENER_SOCKETCONNECTIONRECEIVER_HPP_
|
||||
#define _LISTENER_SOCKETCONNECTIONRECEIVER_HPP_
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <thread>
|
||||
#include <common/string.hpp>
|
||||
#include <common/profiler.hpp>
|
||||
#include <common/block.hpp>
|
||||
#include <common/fileio.hpp>
|
||||
|
||||
class SocketConnectionReceiver
|
||||
{
|
||||
public:
|
||||
SocketConnectionReceiver(int socket, sockaddr_in inernalSocketAddress);
|
||||
virtual ~SocketConnectionReceiver();
|
||||
void close(void);
|
||||
private:
|
||||
static constexpr size_t BUFFER_LENGTH=65536; // this is the buffer length for the socket
|
||||
void threadFunction(int data);
|
||||
bool handlePut(Block<String> &commands);
|
||||
size_t readLine(String &line);
|
||||
size_t read(Array<char> &buffer);
|
||||
String restoreFileName(Block<String> block,DWORD startIndex,DWORD endIndex);
|
||||
|
||||
friend class SocketServer;
|
||||
char mBuffer[BUFFER_LENGTH] = {0};
|
||||
int mSocket;
|
||||
sockaddr_in mInternalSocketAddress;
|
||||
};
|
||||
#endif
|
||||
85
listener/SocketServer.cpp
Normal file
85
listener/SocketServer.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <listener/SocketServer.hpp>
|
||||
#include <listener/SocketConnectionReceiver.hpp>
|
||||
|
||||
/// @brief This will construct the socket listener. You must then call listen() to listen for connections
|
||||
/// @param port
|
||||
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;
|
||||
}
|
||||
|
||||
SocketServer::~SocketServer()
|
||||
{
|
||||
std::cout << "~SocketServer()" << std::endl;
|
||||
close();
|
||||
}
|
||||
|
||||
bool SocketServer::isOkay(void)
|
||||
{
|
||||
return mIsOkay;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void SocketServer::close(void)
|
||||
{
|
||||
if(-1!=mSocketFileDescriptor)
|
||||
{
|
||||
::close(mSocketFileDescriptor);
|
||||
mSocketFileDescriptor=-1;
|
||||
}
|
||||
}
|
||||
34
listener/SocketServer.hpp
Normal file
34
listener/SocketServer.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef _LISTENER_SOCKETSERVER_HPP_
|
||||
#define _LISTENER_SOCKETSERVER_HPP_
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <common/string.hpp>
|
||||
#include <common/profiler.hpp>
|
||||
#include <common/block.hpp>
|
||||
#include <common/fileio.hpp>
|
||||
|
||||
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<std::thread> mExecutionThreads;
|
||||
};
|
||||
#endif
|
||||
101
listener/main.cpp
Normal file
101
listener/main.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <common/string.hpp>
|
||||
#include <common/profiler.hpp>
|
||||
#include <common/block.hpp>
|
||||
#include <common/fileio.hpp>
|
||||
#include <common/utility.hpp>
|
||||
#include <listener/SocketServer.hpp>
|
||||
#include <listener/ClientSocketSender.hpp>
|
||||
|
||||
// https://www.man7.org/linux/man-pages/man2/accept.2.html
|
||||
|
||||
void handleServer(Block<String> &commands);
|
||||
void handleClient(Block<String> &commands);
|
||||
|
||||
/// @brief
|
||||
/// @param argc
|
||||
/// @param argv [0] program. [1] SERVERMODE {port} [2] CLIENTMODE {serveripaddress} {serverport} SEND {FileName}
|
||||
/// @return
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Profiler profiler;
|
||||
|
||||
if(argc<2)
|
||||
{
|
||||
std::cout << "listener SERVERMODE {port} | CLIENTMODE {serveripaddress} {serverport} SEND {FileName}" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Block<String> arguments;
|
||||
for(int index=0;index<argc;index++)
|
||||
{
|
||||
String item(argv[index]);
|
||||
arguments.insert(item);
|
||||
}
|
||||
|
||||
std::cout << argv[1] << std::endl;
|
||||
if(arguments[1]=="SERVERMODE")
|
||||
{
|
||||
handleServer(arguments);
|
||||
}
|
||||
else if(arguments[1]=="CLIENTMODE")
|
||||
{
|
||||
handleClient(arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unknown command " << arguments[1] << std::endl;
|
||||
}
|
||||
return 0;
|
||||
|
||||
std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl;
|
||||
}
|
||||
|
||||
/// @brief [0]=program [1]=SERVERMODE [2]={port}
|
||||
/// @param commands
|
||||
void handleServer(Block<String> &commands)
|
||||
{
|
||||
Profiler profiler;
|
||||
|
||||
if(commands.size()!=3)
|
||||
{
|
||||
std::cout << "Missing required parameters" << std::endl;
|
||||
return;
|
||||
}
|
||||
int port = commands[2].toInt();
|
||||
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;
|
||||
}
|
||||
|
||||
/// @brief [0]=program, [1]=CLIENTMODE, [2]=serveripaddress, [3]=serverport, [4]=pathfilename
|
||||
/// @param commands
|
||||
void handleClient(Block<String> &commands)
|
||||
{
|
||||
Profiler profiler;
|
||||
if(commands.size()!=5)
|
||||
{
|
||||
std::cout << "Missing required parameters" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSocketSender clientSocketSender(commands[2],commands[3].toInt());
|
||||
bool returnCode = clientSocketSender.sendFile(commands[4]);
|
||||
if(!returnCode)
|
||||
{
|
||||
std::cout << "The transfer failed." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Transfer complete" << std::endl;
|
||||
}
|
||||
std::cout << "Done, total took " << profiler.end() << "(ms)" << std::endl;
|
||||
}
|
||||
435
listener/scraps.txt
Normal file
435
listener/scraps.txt
Normal file
@@ -0,0 +1,435 @@
|
||||
// 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<char> &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<char> 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<readBuffer.size())break;
|
||||
// }
|
||||
// sendPacketIndicator(0);
|
||||
// sendQuit();
|
||||
// readFile.close();
|
||||
// std::cout << "SendFile complete" << std::endl;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// bool ClientSocketSender::sendPacketIndicator(long bytesToSend)
|
||||
// {
|
||||
// if(!isOkay())return false;
|
||||
// String packetIndicator = "PCKT|";
|
||||
// packetIndicator+=String().fromInt(bytesToSend);
|
||||
// packetIndicator+="\r\n";
|
||||
// ::send(mSocket, (char*)packetIndicator, packetIndicator.length(),0);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// bool ClientSocketSender::sendPutIndicator(String fileName,long fileLength)
|
||||
// {
|
||||
// if(!isOkay())return false;
|
||||
// Block<String> 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<char> &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<String> &commands);
|
||||
// int readLine(String &line);
|
||||
// long read(Array<char> &buffer);
|
||||
// String restoreFileName(Block<String> 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<String> 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<String> &commands)
|
||||
// {
|
||||
// Array<char> receiveBuffer;
|
||||
// Block<String> 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<char> &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<std::thread> 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;
|
||||
// }
|
||||
// }
|
||||
Reference in New Issue
Block a user