<repo_name>wjkcow/SJTU489P<file_sep>/BitTorrent/ThreadObject.h
#ifndef THREAD_OBJECT_H
#define THREAD_OBJECT_H

#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <atomic>

class ThreadObject{
public:
    ThreadObject();
    virtual ~ThreadObject();
    bool add_task(std::function<void(void)> task);
    void stop();
    void stop_when_done();
    void join();
private:
    void handle_task();
    bool get_task();
    std::queue<std::function<void(void)>> tasks;
    std::function<void(void)> task;
    std::thread my_thread;
    
    std::mutex mtx;
    std::condition_variable cv;
    enum class ThreadState{
        RUNNING,
        FINISH_TASK_AND_DONE,
        DONE
    };
    std::atomic<ThreadState>  state;
    
};

#endif
<file_sep>/BitTorrent/TorrentServerMsgs.h

#ifndef TORRENT_SERVER_MESSAGES_H
#define TORRENT_SERVER_MESSAGES_H

// This file includes all the messages that could be received by TorrentServer

#include <memory>
#include "Message.h"
#include "TorrentServer.h"
#include "Connection.h"

class Connection;
class Torrent;

const int upload_torrent_ID_c = 1;
const int download_torrent_ID_c = 2;
const int list_torrent_ID_c = 3;

class TorrentServerMsg : public Message {
public:
    virtual void handle(std::shared_ptr<TorrentServerWorker>) = 0;
};

// Message send by uploader
class UploadTorrentRequest : public TorrentServerMsg,
public std::enable_shared_from_this<UploadTorrentRequest>
{
public:
    UploadTorrentRequest(std::shared_ptr<Torrent> torrent_ptr);
    UploadTorrentRequest(std::shared_ptr<Connection> connection);
    
    void handle(std::shared_ptr<TorrentServerWorker>) override;
    
    std::shared_ptr<Torrent> get_torrent(){
        return torrent_ptr;
    }
    
protected:
    char get_message_ID() override {return upload_torrent_ID_c;}
    
private:
    std::shared_ptr<Torrent> torrent_ptr;
};

// Message send by downloader
class DownloadTorrentRequest : public TorrentServerMsg,
public std::enable_shared_from_this<DownloadTorrentRequest>{
public:
    DownloadTorrentRequest(const std::string& torrent_id_);
    DownloadTorrentRequest(std::shared_ptr<Connection> connection);
    
    void handle(std::shared_ptr<TorrentServerWorker>) override;
    
    std::string get_torrent_id(){
        return torrent_id;
    }
protected:
    char get_message_ID() override {return download_torrent_ID_c;}

private:
    std::string torrent_id;

};

// Message send by downloader
class ListTorrentRequest : public TorrentServerMsg,
public std::enable_shared_from_this<ListTorrentRequest>{
public:
    void handle(std::shared_ptr<TorrentServerWorker>) override;
protected:
    char get_message_ID() override {return list_torrent_ID_c;}
};


#endif 
<file_sep>/BitTorrent/Server.cpp
#include "Server.h"
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <cstdint>
#include <iostream>
#include "Log.h"
#include <exception>


Server::Server(const char* port){
    int rc;
    
    addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    
    addrinfo *ai;
    getaddrinfo(nullptr, port, &hints, &ai);
    
    if (rc) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc));
        throw std::exception();
    }
    
    listen_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (listen_sock < 0) {
        logerr("creating socket");
        throw std::exception();
    }
    
    int yes = 1;
    rc = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    if (rc) {
        logerr("setsockopt failed");
        throw std::exception();
    }
    
    rc = bind(listen_sock, ai->ai_addr, ai->ai_addrlen);
    if (rc) {
        logerr("bind failed");
        throw std::exception();
    }
    
    freeaddrinfo(ai);
    
    rc = listen(listen_sock, 10);
    if (rc) {
        logerr("listen failed");
        throw std::exception();
    }
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    
    rc = getsockname(listen_sock, (struct sockaddr *)&addr, &len);
    if (rc) {
        logerr("getsockname failed");
        throw std::exception();
    }
    std::cout << "Server accepting connection " << ntohs(addr.sin_port) << std::endl;
    _thread = std::thread(&Server::accept_connection, this);
   // add_task(std::bind(&ServerConnection::accept_connection, this));
}

Server::~Server(){
    log("Server connection is going to be closed");
    close(listen_sock);
}

void Server::drop_connection(std::shared_ptr<Connection> connection){
    connections.erase(std::find(connections.begin(), connections.end(), connection));
}

void Server::accept_connection(){
    while (true) {
        log("Server is accepting connection");
        int socket = accept(listen_sock, nullptr, 0);
        log("New connection accepted");
        connections.push_back(get_connection(socket));
    }
}
<file_sep>/BitTorrent/Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H

#include <stdio.h>

#endif 
<file_sep>/BitTorrent/UploaderMsgs.cpp
#include "UploaderMsgs.h"
<file_sep>/BitTorrent/DownloaderMsgs.h
#ifndef DOWNLOADER_MESSAGES_H
#define DOWNLOADER_MESSAGES_H

#include "Message.h"

// Message send by torrent server
class ListTorrentResponse : public Message {
public:
    void send_through(std::shared_ptr<Connection> connection);
};


// send by tracker, recv by downloader
class ListPeerResponse : public Message{
public:
    void send_through(std::shared_ptr<Connection> connection);
};

// send by uploader
class MsgHandShakeReply : public Message{
    
};

// send by uploader
class MsgBitField : public Message {
    
};

// send by uploader
class MsgReplyContent : public Message {
    
};

// send by uploader
class MsgHave : public Message {
    
};

#endif 
<file_sep>/BitTorrent/TorrentServerMsgs.cpp
#include "TorrentServerMsgs.h"

#include <string>
#include "TorrentServer.h"
#include "Torrent.h"
#include "Connection.h"

using namespace std;

UploadTorrentRequest::UploadTorrentRequest(std::shared_ptr<Torrent> torrent_ptr_) : torrent_ptr{torrent_ptr_} {
    append_str(torrent_ptr->to_string());
}

UploadTorrentRequest::UploadTorrentRequest(std::shared_ptr<Connection> connection) : torrent_ptr{make_shared<Torrent>(connection->get_str())}{
}

void UploadTorrentRequest::handle(std::shared_ptr<TorrentServerWorker> worker){
    worker->handle(shared_from_this());
}

DownloadTorrentRequest::DownloadTorrentRequest(const std::string& torrent_id_):
torrent_id{torrent_id_}{
    append_str(torrent_id);
}

DownloadTorrentRequest::DownloadTorrentRequest(std::shared_ptr<Connection> connection){
    torrent_id = connection->get_str();
    append_str(torrent_id);
}

void DownloadTorrentRequest::handle(std::shared_ptr<TorrentServerWorker> worker){
    worker->handle(shared_from_this());
}

void ListTorrentRequest::handle(std::shared_ptr<TorrentServerWorker> worker){
    worker->handle(shared_from_this());
}
<file_sep>/BitTorrent/ThreadObject.cpp
#include "ThreadObject.h"
#include <iostream>
#include "Log.h"
using namespace std;

ThreadObject::ThreadObject():my_thread{bind(&ThreadObject::handle_task, this)}, state{ThreadState::RUNNING}{}

ThreadObject::~ThreadObject() {
    stop();
    if (my_thread.joinable()) {
        my_thread.join();
    }
   // log("thread done");
}

bool ThreadObject::add_task(std::function<void(void)> task){
    unique_lock<mutex> lkg(mtx);
    if (state == ThreadState::DONE) {
        return false;
    }
    tasks.push(task);
    cv.notify_all();
    return true;
}

void ThreadObject::stop(){
    unique_lock<mutex> lkg(mtx);
    state = ThreadState::DONE;
    cv.notify_all();
}

void ThreadObject::stop_when_done(){
    unique_lock<mutex> lkg(mtx);
    state = ThreadState::FINISH_TASK_AND_DONE;
    cv.notify_all();
}

void ThreadObject::join(){
    return my_thread.join();
}

void ThreadObject::handle_task(){
    while (get_task()) task();
}

bool ThreadObject::get_task(){
    unique_lock<mutex> lkg(mtx);
    while (tasks.empty() && state == ThreadState::RUNNING) {
        cv.wait(lkg);
    }
    if (!tasks.empty() && state != ThreadState::DONE) {
        task = tasks.front();
        tasks.pop();
        return true;
    } else {
        state = ThreadState::DONE;
        return false;
    }
}<file_sep>/BitTorrent/TorrentServer.h
#ifndef TORRENT_SERVER_H
#define TORRENT_SERVER_H
#include "Server.h"
#include <memory>
#include <map>
#include <string>

class Connection;
class Torrent;

class UploadTorrentRequest;
class DownloadTorrentRequest;
class ListTorrentRequest;

class TorrentServer : public Server{
public:
    using torrents_t = std::map<std::string, std::shared_ptr<Torrent>>;
    static void start(char* port);
    static std::shared_ptr<TorrentServer> instance();
    
    void add_torrent(std::shared_ptr<Torrent> torrent);
    std::vector<std::string> list_torrent();
    std::shared_ptr<Torrent> get_torrent(const std::string t_hash);
    
protected:
    std::shared_ptr<Connection> get_connection(int sock_);
private:
    TorrentServer(char* port): Server(port){
    }
    

    torrents_t torrents;
    static std::shared_ptr<TorrentServer> _instance;
};

class TorrentServerWorker : public Connection,
public std::enable_shared_from_this<TorrentServerWorker>{
public:
    TorrentServerWorker(int sock_);
    void handle(std::shared_ptr<UploadTorrentRequest> request){}
    void handle(std::shared_ptr<DownloadTorrentRequest> request){}
    void handle(std::shared_ptr<ListTorrentRequest> request){}
    
private:
    void handle();
};
#endif
<file_sep>/BitTorrent/Log.h
#ifndef LOG_H
#define LOG_H

#include <string>

void log(const std::string& str);
void logerr(const std::string& str);

#endif 
<file_sep>/BitTorrent/DownloaderMsgs.cpp
#include "DownloaderMsgs.h"
<file_sep>/BitTorrent/Log.cpp
#include "Log.h"
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;

mutex log_mtx;

void log(const std::string& str){
    unique_lock<mutex> lk(log_mtx);
    cout << str << endl;
}

void logerr(const std::string& str){
    unique_lock<mutex> lk(log_mtx);
    cerr << str << endl;
}
<file_sep>/BitTorrent/Message.cpp
#include "Message.h"
#include "Connection.h"
#include "Log.h"
#include <iostream>

using namespace std;

const int reserve_size_c = sizeof(int32_t) + 1;

// <length> <message_ID> .<contents> ...
Message::Message() : data{reserve_size_c} {}

void Message::send_through(std::shared_ptr<Connection> connection){
    update_message_type();
    update_size();
    connection->send(data.data(), static_cast<int>(data.size()));
}


void Message::append_int32(int32_t i){
    char* value_ptr = reinterpret_cast<char*>(&i);
    data.insert(data.end(), value_ptr, value_ptr + sizeof(int32_t));
}

void Message::append_char(char c){
    data.push_back(c);
}

void Message::append_str(const char* c_str, int sz){
    data.insert(data.end(), c_str, c_str + sz);
}

void Message::append_str(const string& str){
    append_int32(static_cast<int32_t>(str.size()));
    append_str(str.c_str(), static_cast<int>(str.size()));
}

char* Message::get_buffer(int sz){
    int before_size = static_cast<int>(data.size());
    data.resize(before_size + sz);
    return &data[before_size];
}

void Message::update_size(){
    int sz = static_cast<int>(data.size()) - reserve_size_c;
    char* size_ptr = reinterpret_cast<char*>(&sz);
    copy(size_ptr, size_ptr + sizeof(int32_t), data.data());
}

void Message::update_message_type(){
    data[sizeof(int32_t)] = get_message_ID();
}
<file_sep>/BitTorrent/main.cpp
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

int main(int argc, const char * argv[]) {
    
    string str = "1";
    cout << str.size();
    return 0;
}
<file_sep>/BitTorrent/Message.h
#ifndef MESSAGE_H
#define MESSAGE_H

#include <vector>
#include <memory>
#include <exception>
#include <cstdint>

const char default_message_id_c = 0;
class Connection;

class Message {
public:
    Message();
    virtual ~Message(){}
    
    virtual void send_through(std::shared_ptr<Connection> connection);

    Message(const Message&) = delete;
    Message(Message&&) = delete;
    Message& operator=(const Message&) = delete;
    Message& operator=(Message&&) = delete;
    
protected:
    virtual char get_message_ID() {return default_message_id_c;}
    
    void append_int32(int32_t i);
    void append_char(char c);
    void append_str(const char* c_str, int sz);
    void append_str(const std::string& str);

    char* get_buffer(int sz);
private:
    void update_size();
    void update_message_type();
    
    std::vector<char> data;
};

#endif
<file_sep>/BitTorrent/ClientConnection.cpp
#include "ClientConnection.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <exception>
#include "Log.h"

ClientConnection::ClientConnection(char* host, char* port) :
Connection(setup_connection(host, port)){

}

int ClientConnection::setup_connection(char* host, char* port){
    int rc;
    
    addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    
    addrinfo *ai;
    rc = getaddrinfo(host, port, &hints, &ai);
    if (rc) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc));
        throw std::exception();
    }
    
    int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (sock < 0) {
        logerr("creating socket");
        throw std::exception();
    }
    
    rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
    if (rc) {
        logerr("failed to connect");
        throw std::exception();
    }
    
    freeaddrinfo(ai);
    
    return sock;
}
<file_sep>/BitTorrent/Uploader.cpp
#include "Uploader.h"
<file_sep>/BitTorrent/TrackerMsgs.cpp
#include "TrackerMsgs.h"

#include "Tracker.h"

using namespace std;

ServeTorrentRequest::ServeTorrentRequest(const std::string& torrent_id_) :
torrent_id{torrent_id_}{
    append_str(torrent_id);
}

void ServeTorrentRequest::handle(shared_ptr<TrackerWorker> worker){
    worker->handle(shared_from_this());
}

void ListPeerRequest::handle(shared_ptr<TrackerWorker> worker){
    worker->handle(shared_from_this());
}

void HeartBeat::handle(shared_ptr<TrackerWorker> worker){
    worker->handle(shared_from_this());
}
<file_sep>/BitTorrent/Address.h
#ifndef ADDRESS_H
#define ADDRESS_H

#include <Memory>
#include <string>

class Address{
public:
    
    std::string to_string(){
        return std::string();
    }
    
    static std::shared_ptr<Address> from_string(const std::string& str){
        return std::make_shared<Address>();
    }
};
#endif
<file_sep>/BitTorrent/TrackerMsgs.h
#ifndef TRACKER_MESSAGES_H
#define TRACKER_MESSAGES_H
// This file includes all the messages that could be received by Tracker
#include <memory>
#include <string>
#include "Message.h"

const char serve_torrent_ID_c = 1;
const char list_peer_ID_c = 2;
const char heartbeat_ID_c = 3;

class Connection;
class TrackerWorker;

class TrackerMsg : public Message {
public:
    virtual void handle(std::shared_ptr<TrackerWorker>) = 0;
};

// send by uploader
class ServeTorrentRequest : public TrackerMsg,
public std::enable_shared_from_this<ServeTorrentRequest>{
public:
    ServeTorrentRequest(const std::string& torrent_id_);
    void handle(std::shared_ptr<TrackerWorker>) override;
    
protected:
    std::string torrent_id;
    char get_message_ID() override {return serve_torrent_ID_c;}
    
};

// send by downloaer
class ListPeerRequest : public TrackerMsg,
public std::enable_shared_from_this<ListPeerRequest>{
public:
    void handle(std::shared_ptr<TrackerWorker>) override;
protected:
    char get_message_ID() override {return list_peer_ID_c;}
    

};

// send by uploader
class HeartBeat : public TrackerMsg,
public std::enable_shared_from_this<HeartBeat>{
public:
    void handle(std::shared_ptr<TrackerWorker>) override;
protected:
    char get_message_ID() override {return heartbeat_ID_c;}
};


#endif 
<file_sep>/BitTorrent/Tracker.h
#ifndef TRACKER_H
#define TRACKER_H

#include "Server.h"
#include "Peer.h"
#include <vector>
#include <mutex>
#include <memory>
#include <map>

class Connection;
class ServeTorrentRequest;
class ListPeerRequest;
class HeartBeat;

class Tracker : public Server{
public:
    
protected:
    std::shared_ptr<Connection> get_connection(int sock_);
private:
    std::mutex peer_mtx;
    std::map<std::string, Peer> torrent_peer;
    std::vector<Peer> peers;
    std::vector<Peer> time_out_peers;
    
};

class TrackerWorker : public Connection{
public:
    TrackerWorker(int sock_);
    
    void handle(std::shared_ptr<ServeTorrentRequest>){}
    void handle(std::shared_ptr<ListPeerRequest>){}
    void handle(std::shared_ptr<HeartBeat>){}

private:
    void handle();
};


#endif
<file_sep>/BitTorrent/Uploader.h
#ifndef UPLOADER_H
#define UPLOADER_H



#endif
<file_sep>/BitTorrent/Connection.cpp
#include "Connection.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <cstdint>

Connection::~Connection(){
    close(sock);
}

int Connection::get_int32(){
    int32_t i;
    if (!force_receive(&i, sizeof(int32_t))) {
        throw UnableToReadFromConnection();
    }
    return i;
}

char Connection::get_char(){
    char c;
    ssize_t read_len = recv(sock, &c, sizeof(char), 0);
    if (read_len != sizeof(char)) {
        throw UnableToReadFromConnection();
    }
    return c;
}

void Connection::get_c_str(char* buffer, int sz){
    
    if (!force_receive(buffer, sz)) {
        throw UnableToReadFromConnection();
    }
}

std::string Connection::get_str(){
    int32_t str_size = get_int32();
    char buffer[str_size];
    get_c_str(buffer, str_size);
    return std::string{buffer, static_cast<size_t>(str_size)};
}

void Connection::send(char* buffer, int size){
    ::send(sock, buffer, size, 0);
}

bool Connection::force_receive(void* buffer, int sz){
    ssize_t read_len{0};
    while (read_len < sz) {
        ssize_t new_read_len = recv(sock, (char *)buffer + read_len, sz - read_len, 0);
        if (new_read_len == 0) {
            return false;
        }
        read_len += new_read_len;
    }
    return true;
}

<file_sep>/BitTorrent/Peer.h
#ifndef PEER_H
#define PEER_H

#include "Address.h"

using Peer = Address;

#endif 
<file_sep>/BitTorrent/ClientConnection.h
#ifndef CLIENT_CONNECTION_H
#define CLIENT_CONNECTION_H

#include "Connection.h"
class ClientConnection : public Connection{
public:
    ClientConnection(char* host, char* port);
private:
    int setup_connection(char* host, char* port);
};

#endif 
<file_sep>/BitTorrent/Torrent.cpp
#include "Torrent.h"
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <iterator>
#include <cassert>
#include "hashlibpp.h"
#include "Log.h"

using namespace::std;
const int size_4m_c = 4 << 20;

Torrent::Torrent(const string& filename_, Address tracker_address): filename{filename_}, tracker(tracker_address){
    std::ifstream infile(filename_, ifstream::ate | std::ifstream::binary);
    if (!infile){
        cerr << "file cannot be opened" << endl;
        throw exception();
    }
    file_size = static_cast<int>(infile.tellg());
    infile.seekg(0);
    unique_ptr<char []> buffer{new char[size_4m_c]};
    int tmp_size{file_size};
    shared_ptr<hashwrapper> sha1 = make_shared<sha1wrapper>();
    while (tmp_size) {
        int read_size{tmp_size < size_4m_c ? tmp_size : size_4m_c};
        tmp_size -= read_size;
        infile.read(buffer.get(), read_size);
        if (!infile){
            assert(0);
        }
        filehash.push_back(sha1->getHashFromMemory(buffer.get(), read_size));
    }
    infile.close();
}

Torrent::Torrent(const std::string& content){
    stringstream ss(content);
    ss >> filename;
    ss >> file_size;
    int pieces;
    ss >> pieces;
    string hash;
    for (int i = 0; i < pieces; ++i) {
        ss >> hash;
        filehash.push_back(hash);
    }
    tracker = *Address::from_string(content.substr(ss.tellg()));
    if(!ss){
        logerr("Parsing error");
        throw exception();
    }
}

string Torrent::to_string(){
    stringstream ss;
    ss << filename << endl << file_size << endl << filehash.size()  << endl;
    for (auto ite =filehash.begin(); ite != filehash.end(); ++ ite) {
        ss << *ite << endl;
    }
    ss << tracker.to_string();
    return ss.str();
}



string Torrent::hash(){
    shared_ptr<hashwrapper> sha1 = make_shared<sha1wrapper>();
    return sha1->getHashFromString(to_string());
}

<file_sep>/BitTorrent/Connection.h
#ifndef CONNECTION_H
#define CONNECTION_H

#include <memory>
#include <exception>
#include <string>
class Message;

class Connection :
public std::enable_shared_from_this<Connection>{
public:
    virtual ~Connection();
    Connection(int sock_) : sock{sock_} {}
  //  std::shared_ptr<Message> recv_message();
    
    int  get_int32();
    char get_char();
    void get_c_str(char* buffer, int sz);
    std::string get_str();
    
    void send(char* buffer, int sz);
private:
    int sock;
    bool force_receive(void* buffer, int sz);

    class UnableToReadFromConnection : public std::exception{
        const char* what() const noexcept
        {return "Unable to read from this connection \n";}
    };
    
    class UnableToSendToConnection : public std::exception{
        const char* what() const noexcept
        {return "Unable to send to this connection \n";}
    };
};


#endif
<file_sep>/BitTorrent/Torrent.h
#ifndef TORRENT_H
#define TORRENT_H

#include <memory>
#include <string>
#include <vector>
#include "Address.h"

class Connection;

class Torrent{
public:

    Torrent(const std::string& file, Address tracker_address);
    Torrent(const std::string& content);
        
    std::string to_string();
    
    Address get_tracker();
    
    std::string get_filename(){
        return filename;
    }
    
    int get_file_size(){
        return file_size;
    }
    
    int get_piece_number(){
        return static_cast<int>(filehash.size());
    }
    
    std::string get_hash(int piece){
        return filehash[piece];
    }
    
    std::string hash();
    
private:
    Address tracker;
    int file_size;
    std::string filename;
    std::vector<std::string> filehash;
};

#endif 
<file_sep>/BitTorrent/TorrentServer.cpp
#include "TorrentServer.h"
#include <algorithm>
#include <iterator>
#include "Connection.h"
#include "Torrent.h"
#include "Log.h"

using namespace std;

std::shared_ptr<TorrentServer> TorrentServer::_instance{nullptr};

void TorrentServer::start(char* port){
    if (!_instance) {
        _instance.reset(new TorrentServer(port)); // cannot use make shared as constructor is private
    }
}

shared_ptr<TorrentServer> TorrentServer::instance(){
    if (!_instance) {
        logerr("Torrent Server has not been started");
    }
    return _instance;
}

void TorrentServer::add_torrent(shared_ptr<Torrent> torrent){
    if (torrents.count(torrent->hash())) {
        logerr("Already have the same torrent");
    }
    torrents[torrent->hash()] = torrent;
}

vector<string> TorrentServer::list_torrent(){
    vector<string> torrent_list;
    transform(torrents.begin(), torrents.end(),
              insert_iterator<vector<string>>(torrent_list, torrent_list.end()),
              mem_fn(&torrents_t::value_type::first));
    return torrent_list;
}

shared_ptr<Torrent> TorrentServer::get_torrent(const string t_hash){
    auto ite = torrents.find(t_hash);
    if (ite != torrents.end()) {
        return ite->second;
    }
    return nullptr;
}

shared_ptr<Connection> TorrentServer::get_connection(int sock_){
    return make_shared<TorrentServerWorker>(sock_);
}

TorrentServerWorker::TorrentServerWorker(int sock_) : Connection{sock_}{
}

void TorrentServerWorker::handle(){

}


<file_sep>/BitTorrent/UploaderMsgs.h
#ifndef UPLOADER_MESSAGES_H
#define UPLOADER_MESSAGES_H
// This file includes all the messages that could be received by Uploader
#include "Message.h"

class UploaderMsg : public Message{
public:
    virtual void handle();
};


class MsgHandshake : public UploaderMsg {
    
};

class MsgRequestContent : public UploaderMsg {
    
};



#endif 
<file_sep>/BitTorrent/Server.h
#ifndef SERVER_H
#define SERVER_H

#include <thread>
#include <memory>
#include <vector>
#include "Connection.h"
class Server {
public:
    Server(const char* port);
    virtual ~Server();
    void drop_connection(std::shared_ptr<Connection> connection);
protected:
    virtual std::shared_ptr<Connection> get_connection(int sock_) = 0;
private:
    int listen_sock;
    void accept_connection();

    std::vector<std::shared_ptr<Connection>> connections;
    std::thread _thread;
};

#endif
