Initial Commit

master
Thies Block 1 year ago
commit f80993fed3
Signed by: thiesyy
GPG Key ID: 3344988F036E9390
  1. 3
      .gitignore
  2. 55
      .vscode/settings.json
  3. 69
      Makefile
  4. 34
      inc/fileutility.hpp
  5. 31
      inc/packetmanager.hpp
  6. 11
      inc/protocol.hpp
  7. 12
      inc/settings.hpp
  8. 19
      inc/udpclient.hpp
  9. 16
      inc/udpserver.hpp
  10. 78
      src/fileutility.cpp
  11. 32
      src/main.cpp
  12. 101
      src/packetmanager.cpp
  13. 35
      src/settings.cpp
  14. 49
      src/udpclient.cpp
  15. 55
      src/udpserver.cpp

3
.gitignore vendored

@ -0,0 +1,3 @@
app
build/
test*

@ -0,0 +1,55 @@
{
"files.associations": {
"ostream": "cpp",
"vector": "cpp",
"memory": "cpp",
"optional": "cpp",
"string_view": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"map": "cpp",
"unordered_map": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"ratio": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

@ -0,0 +1,69 @@
# Author Yannis Gerlach
# HochSchule Osnabrück
# 29.04.2020
# `make clean all` nicht mit -j verwenden! -> race condition im make file
# statdessen: `make clean; make all -j` verwenden
NAME = app
NAMETEST = test
CFLAGS = -std=c++2a -O2 -g3 -pipe -Wall -rdynamic
CXX = g++
SRCF = src/
INCF = inc/
BUILDDIR = build/
TESTF = tests/
DEPF = $(BUILDDIR)deps/
INCLUDES = -I$(INCF)
LDFLAGS = -lpthread -lcrypto
SRCFILES = $(shell find $(SRCF) -name "*.cpp")
OBJFILES = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(patsubst %.cpp, %.o, $(SRCFILES)))
DEPFILES = $(wildcard $(DEPF)*.d)
SOURCEDIRS = $(shell find $(SRCF) -type d -printf "%p/\n")
BUILDDIRS = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(SOURCEDIRS))
OBJFILESTEST = $(filter-out $(BUILDDIR)main.o, $(OBJFILES))
INCLUDES += $(addprefix -I, $(SOURCEDIRS))
all: $(NAME) runtest
$(NAME): $(BUILDDIRS) $(DEPF) $(OBJFILES)
@echo "Linking $@"
@$(CXX) $(CFLAGS) -o $@ $(filter %.o, $^) $(LDFLAGS)
$(BUILDDIR)%.o: $(SRCF)%.cpp
@echo "Compiling: $@"
@$(CXX) $(CFLAGS) $(INCLUDES) $< -MM -MT $@ > $(DEPF)$(subst /,_,$*).d
@$(CXX) -c -o $@ $(CFLAGS) $(INCLUDES) $<
$(NAME)_strip: $(NAME)
@echo "Strip $<"
@strip -o $@ $<
%/:
mkdir -p $@
clean-depends:
$(RM) -r $(DEPF)
clean:
$(RM) -r $(NAME) $(BUILDDIR) $(NAMETEST)
$(NAMETEST): $(BUILDDIRS) $(DEPF) $(TESTF)*.cpp $(OBJFILESTEST)
@echo "Compiling tests"
@$(CXX) -o $@ $(filter %.o, $^) $(filter %.cpp, $^) $(CFLAGS) -I$(SRCF) $(INCLUDES) $(LDFLAGS)
runtest: $(NAMETEST)
@echo "Running tests"
./$<
# fix assets :
# find assets/ -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;
.PHONY: clean all $(NAMETEST) clean-depends runtest
include $(DEPFILES)

@ -0,0 +1,34 @@
#ifndef fileutility_hpp
#define fileutility_hpp
#include <openssl/sha.h>
#include <iostream>
#include <vector>
#include "settings.hpp"
class File;
class FileUtility;
class FileUtility {
public:
static std::vector<File> files;
static void prepfile(const std::string& filepath);
static File getFile(const std::string& hash);
static std::string hashblock(char* data, uint64_t size);
private:
static std::string hashfile(const std::string& filepath, uint64_t* filesize);
static std::string sha256_hash_string(
unsigned char hash[SHA256_DIGEST_LENGTH]);
};
class File {
public:
File(const std::string& filename,
const std::string& hash,
const uint64_t& filesize);
std::string filename;
std::string hash;
uint64_t filesize;
private:
};
#endif

@ -0,0 +1,31 @@
#pragma once
#ifndef packetmanager_hpp
#define packetmanager_hpp
#include <stdint.h>
#include "protocol.hpp"
struct Packet {
char identifier = p_identifier_req;
uint8_t pid = p_p_err;
char file_hash[64] = "";
};
struct FileInfoPacket : Packet {
char filename[256] = "";
uint8_t pid = p_p_info;
uint64_t filesize = 0;
};
struct FileDataPacket : Packet {
char data[blocksize] = "";
uint8_t pid = p_p_block;
uint32_t chunkid = 0;
char data_hash[65] = "";
};
class PacketManager {
public:
PacketManager();
void manageData(int fd, char* data, unsigned long size, void* client);
private:
};
#endif

@ -0,0 +1,11 @@
#ifndef protocol_hpp
#define protocol_hpp
#define DEF_PORT 8122
#define p_headersize 16
#define blocksize 65536
#define p_identifier_req '#'
#define p_identifier_send '!'
#define p_p_err '0'
#define p_p_info '1'
#define p_p_block '2'
#endif

@ -0,0 +1,12 @@
#pragma once
#ifndef Settings_hpp
#define Settings_hpp
#include <cstdint>
class Settings {
public:
static void readArgs(int argc, char* argv[]);
static int port;
static char* ep;
static bool running;
};
#endif

@ -0,0 +1,19 @@
#pragma once
#ifndef udpclient_hpp
#define udpclient_hpp
#include <iostream>
#include "packetmanager.hpp"
class UDPClient {
public:
UDPClient(const std::string& addr, int port);
UDPClient(const std::string& addr);
void requestInfo(const std::string& hash);
private:
void createSocket();
std::string addr;
int port;
int clientsocket;
};
#endif

@ -0,0 +1,16 @@
#pragma once
#ifndef udpserver_hpp
#define udpserver_hpp
#include "packetmanager.hpp"
class UDPServer {
public:
UDPServer();
~UDPServer();
void start();
private:
int serversocket;
PacketManager* pmgr;
};
#endif

@ -0,0 +1,78 @@
#include "fileutility.hpp"
#include <stdlib.h>
#include <string.h>
#include "openssl/sha.h"
std::vector<File> FileUtility::files;
void FileUtility::prepfile(const std::string& filepath) {
std::cout << "Preparing File: " << filepath << std::endl;
uint64_t size = 0;
std::string hash = hashfile(filepath, &size);
File f(filepath, hash, size);
files.push_back(f);
}
File FileUtility::getFile(const std::string& hash) {
for (auto it : files) {
if (it.hash == hash)
return it;
}
return File("", "", 0);
}
std::string FileUtility::hashblock(char* data, uint64_t size) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, size);
SHA256_Final(hash, &sha256);
return sha256_hash_string(hash);
}
std::string FileUtility::hashfile(const std::string& filepath,
uint64_t* filesize) {
std::cout << "Hashing File: " << filepath << std::endl;
std::string retval;
FILE* file = fopen(filepath.c_str(), "rb");
if (!file)
return "error!";
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
const int bufSize = 32768;
unsigned char* buffer = (unsigned char*)malloc(bufSize);
int bytesRead = 0;
if (!buffer)
return "error!";
uint64_t totalRead = 0;
while ((bytesRead = fread(buffer, 1, bufSize, file))) {
SHA256_Update(&sha256, buffer, bytesRead);
totalRead += bytesRead;
}
if (filesize != nullptr)
*filesize = totalRead;
SHA256_Final(hash, &sha256);
retval = sha256_hash_string(hash);
fclose(file);
free(buffer);
return retval;
}
std::string FileUtility::sha256_hash_string(
unsigned char hash[SHA256_DIGEST_LENGTH]) {
char outputBuffer[65];
int i = 0;
for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
return outputBuffer;
}
File::File(const std::string& filename,
const std::string& hash,
const uint64_t& filesize)
: filename(filename), hash(hash), filesize(filesize){};

@ -0,0 +1,32 @@
#include <unistd.h>
#include <iostream>
#include <thread>
#include "fileutility.hpp"
#include "settings.hpp"
#include "udpclient.hpp"
#include "udpserver.hpp"
UDPServer server;
void* startUDPServer();
int main(int argc, char* argv[]) {
Settings::readArgs(argc, argv);
std::cout << "Starting on Port " << Settings::port << "!" << std::endl;
Settings::running = true;
std::thread server(&startUDPServer);
FileUtility::prepfile("testfile");
UDPClient client("127.0.0.1", DEF_PORT);
usleep(10000);
for (auto it : FileUtility::files) {
std::cout << "Requesting info! " << it.hash << std::endl;
client.requestInfo(it.hash);
}
while (Settings::running) {
}
if (server.joinable())
server.join();
}
void* startUDPServer() {
server.start();
return 0;
}

@ -0,0 +1,101 @@
#include "packetmanager.hpp"
#include <netinet/in.h>
#include <string.h>
#include <fstream>
#include "fileutility.hpp"
#include "protocol.hpp"
PacketManager::PacketManager() {}
void PacketManager::manageData(int fd,
char* data,
unsigned long size,
void* client) {
struct sockaddr_in clientaddr = *((struct sockaddr_in*)client);
if (size >= sizeof(Packet)) {
Packet basic = *((Packet*)data);
if (basic.identifier == p_identifier_req) {
if ((basic.pid == p_p_block) && (size >= sizeof(FileDataPacket))) {
FileDataPacket packet = *((FileDataPacket*)data);
File f = FileUtility::getFile(packet.file_hash);
std::cout << "Block Request! -> " << packet.file_hash << std::endl;
if (f.hash != "") {
std::cout << "File Found! -> " << packet.file_hash << std::endl;
FileDataPacket toSend;
toSend.identifier = p_identifier_send;
toSend.chunkid = packet.chunkid;
memcpy(toSend.file_hash, packet.file_hash, sizeof(packet.file_hash));
std::ifstream is(f.filename, std::ifstream::binary);
if (is) {
if (toSend.chunkid <= 0)
is.seekg(0);
else
is.seekg(packet.chunkid * blocksize + 1);
is.read(packet.data, blocksize);
std::string hash = FileUtility::hashblock(toSend.data, blocksize);
memcpy(toSend.data_hash, hash.c_str(), hash.length());
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
} else {
std::cerr << "Couldn't read file! -> " << packet.file_hash
<< std::endl;
Packet toSend;
toSend.identifier = p_identifier_send;
memset(&toSend.file_hash, 0, sizeof(toSend.file_hash));
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
}
} else {
std::cout << "Couldn't read / find file! -> " << packet.file_hash
<< std::endl;
Packet toSend;
toSend.identifier = p_identifier_send;
memset(&toSend.file_hash, 0, sizeof(toSend.file_hash));
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
}
} else if ((basic.pid = p_p_info) && (size >= sizeof(FileInfoPacket))) {
FileInfoPacket packet = *((FileInfoPacket*)data);
File f = FileUtility::getFile(packet.file_hash);
std::cout << "info Request! -> " << packet.file_hash << std::endl;
if (f.hash != "") {
std::cout << "File found! -> " << packet.file_hash << std::endl;
FileInfoPacket toSend;
toSend.identifier = p_identifier_send;
memcpy(toSend.file_hash, f.hash.c_str(), f.hash.length());
memcpy(toSend.filename, f.filename.c_str(), f.filename.length());
toSend.filesize = f.filesize;
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
} else {
std::cerr << "Couldn't find file! -> " << packet.file_hash
<< std::endl;
Packet toSend;
toSend.identifier = p_identifier_send;
memset(&toSend.file_hash, 0, sizeof(toSend.file_hash));
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
}
} else {
std::cout << "Wtf?!" << std::endl;
Packet toSend;
toSend.identifier = p_identifier_send;
memset(&toSend.file_hash, 0, sizeof(toSend.file_hash));
sendto(fd, &toSend, sizeof(toSend), MSG_CONFIRM,
(const struct sockaddr*)&clientaddr, sizeof(clientaddr));
}
} else if (basic.identifier == p_identifier_send) {
}
}
}

@ -0,0 +1,35 @@
#include "settings.hpp"
#include <getopt.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include "protocol.hpp"
void Settings::readArgs(int argc, char* argv[]) {
static const struct option longopts[] = {
{"port", optional_argument, 0, 'p'},
{"endpoint", optional_argument, 0, 'e'},
0};
int index = 0;
int c;
std::stringstream str;
while ((c = getopt_long(argc, argv, "p:e:", longopts, &index)) != -1) {
switch (c) {
case 'p':
str << optarg;
str >> port;
break;
case 'e':
Settings::ep = optarg;
break;
default:
fprintf(stderr, "Usage: %s [--port port] [--endpoint ip]\n", argv[0]);
exit(EXIT_FAILURE);
break;
}
}
}
int Settings::port = DEF_PORT;
char* Settings::ep = nullptr;
bool Settings::running = false;

@ -0,0 +1,49 @@
#include "udpclient.hpp"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sstream>
UDPClient::UDPClient(const std::string& addr, int port)
: addr(addr), port(port) {
createSocket();
}
UDPClient::UDPClient(const std::string& addr) {
if (addr.find(':') <= addr.length()) {
std::string ip = addr.substr(0, addr.find(":"));
std::string port = addr.substr(addr.find(":") + 1, addr.length());
int portnum = -1;
std::stringstream ss;
ss << port;
ss >> portnum;
this->port = portnum;
this->addr = ip;
} else {
this->addr = addr;
this->port = DEF_PORT;
}
createSocket();
}
void UDPClient::createSocket() {
if ((clientsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
}
void UDPClient::requestInfo(const std::string& hash) {
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
inet_pton(AF_INET, addr.c_str(), &(serveraddr.sin_addr));
FileInfoPacket fip;
fip.identifier = p_identifier_req;
memcpy(fip.file_hash, hash.c_str(), hash.length());
sendto(clientsocket, &fip, sizeof(fip), MSG_CONFIRM,
(const struct sockaddr*)&serveraddr, sizeof(serveraddr));
}

@ -0,0 +1,55 @@
#include "udpserver.hpp"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include "protocol.hpp"
#include "settings.hpp"
UDPServer::UDPServer() {
pmgr = new PacketManager();
}
UDPServer::~UDPServer() {
delete pmgr;
}
void UDPServer::start() {
std::cout << "Starting UDP Server on Port " << Settings::port;
struct sockaddr_in serveraddr, clientaddr;
if ((serversocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&serveraddr, 0, sizeof(serveraddr));
memset(&clientaddr, 0, sizeof(serveraddr));
// Filling server information
serveraddr.sin_family = AF_INET; // IPv4
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(Settings::port);
// Bind the socket with the server address
if (bind(serversocket, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) <
0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
while (Settings::running) {
memset(&clientaddr, 0, sizeof(serveraddr));
char buffer[sizeof(FileDataPacket)];
socklen_t len;
int n;
len = sizeof(clientaddr); // len is value/result
n = recvfrom(serversocket, (char*)buffer, blocksize, MSG_WAITALL,
(struct sockaddr*)&clientaddr, &len);
if (n < 0)
std::cerr << "Error Reading!";
else
pmgr->manageData(serversocket, (char*)buffer, n, &clientaddr);
}
}
Loading…
Cancel
Save