123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- #include "../include/Server.h"
- #include "../include/base64.h"
- #include <iostream>
- #include <json/json.h>
- using namespace boost::asio;
- using ip::tcp;
- /***************
- * con_handler *
- ***************/
- con_handler::con_handler(
- basic_socket_acceptor<ip::tcp>::executor_type &io_service)
- : sock(io_service) {}
- con_handler::~con_handler() {}
- con_handler::pointer
- con_handler::create(basic_socket_acceptor<ip::tcp>::executor_type &io_service) {
- return pointer(new con_handler(io_service));
- }
- tcp::socket &con_handler::socket() { return sock; }
- void con_handler::start() {
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_version,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- }
- void con_handler::handle_read(const boost::system::error_code &err,
- size_t bytes_transferred) {
- if (!err) {
- std::cout << this->data << std::endl;
- } else {
- std::cerr << "error: " << err.message() << std::endl;
- sock.close();
- }
- }
- void con_handler::handle_read_version(const boost::system::error_code &err,
- size_t bytes_transferred) {
- if (!err) {
- // set up json stuff
- JSONCPP_STRING err;
- Json::Value root;
- Json::CharReaderBuilder builder;
- const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
- // parse data
- if (!reader->parse(this->data, this->data + bytes_transferred, &root,
- &err)) {
- std::cerr << "Json error: " << err << std::endl << "data: " << this->data;
- sock.close();
- }
- // create answer
- Json::Value answer;
- Json::StreamWriterBuilder stringBuilder;
- answer["version"] = this->protocolVersion;
- // check version string
- if (root["version"].asString().compare(this->protocolVersion) == 0) {
- answer["accept"] = true;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_login,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- } else {
- answer["accept"] = false;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- // close connection
- sock.close();
- }
- } else {
- std::cerr << "error: " << err.message() << std::endl;
- sock.close();
- }
- }
- void con_handler::handle_read_login(const boost::system::error_code &err,
- size_t bytes_transferred) {
- if (!err) {
- // set up json stuff
- JSONCPP_STRING err;
- Json::Value root;
- Json::CharReaderBuilder builder;
- const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
- // parse data
- if (!reader->parse(this->data, this->data + bytes_transferred, &root,
- &err)) {
- std::cerr << "Json error: " << err << std::endl << "data: " << this->data;
- sock.close();
- }
- Json::Value answer;
- Json::StreamWriterBuilder stringBuilder;
- // user credentials
- // TODO check user credentials!!!
- if (root["user"].asString().compare("user") == 0 &&
- root["pass"].asString().compare("pass") == 0) {
- answer["accept"] = true;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_command,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- } else {
- answer["accept"] = false;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- // close connection
- sock.close();
- }
- } else {
- std::cerr << "error: " << err.message() << std::endl;
- sock.close();
- }
- }
- void con_handler::handle_read_command(const boost::system::error_code &err,
- size_t bytes_transferred) {
- if (!err) {
- // set up json stuff
- JSONCPP_STRING err;
- Json::Value root;
- Json::CharReaderBuilder builder;
- const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
- // parse data
- if (!reader->parse(this->data, this->data + bytes_transferred, &root,
- &err)) {
- std::cerr << "Json error: " << err << std::endl << "data: " << this->data;
- sock.close();
- }
- Json::Value answer;
- Json::StreamWriterBuilder stringBuilder;
- // check command
- if (root["command"].asString().compare("status") == 0) {
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_command,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- answer["command"] = "status";
- // TODO answer a real status message
- std::string response;
- if (this->getFile.is_open() && this->putFile.is_open()) {
- response = "download and upload running";
- } else if (this->putFile.is_open()) {
- response = "upload running";
- } else if (this->getFile.is_open()) {
- response = "download running";
- } else {
- response = "ok";
- }
- answer["response"] = response;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- } else if (root["command"].asString().compare("list") == 0) {
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_command,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- answer["command"] = "list";
- // TODO look for real data
- Json::Value array;
- array.append("some");
- array.append("important");
- array.append("data");
- answer["names"] = array;
- answer["remaining"] = 0;
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- } else if (root["command"].asString().compare("put") == 0) {
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_command,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- answer["command"] = "put";
- if (this->putFile.is_open() && root["cancel"].asBool() == true) {
- // cancel upload
- this->putFile.close();
- std::remove(this->putFileName.c_str());
- } else if (this->putFile.is_open() &&
- (this->putFile.tellp() == std::ios::beg ||
- root["remaining"].asInt() == this->putFileReceived - 1)) {
- // upload chunks
- // decode base64 string
- const std::vector<char> data =
- base64::decodeVector(root["data"].asString());
- // write the vector data to the output file
- std::ostream_iterator<char> output_iterator(putFile);
- std::copy(data.begin(), data.end(), output_iterator);
- this->putFileReceived = root["remaining"].asInt();
- // close file if put sends remaining = 0
- if (this->putFileReceived == 0) {
- this->putFile.close();
- }
- answer["cancel"] = false;
- answer["received"] = this->putFileReceived;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(
- buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write, shared_from_this(),
- placeholders::error, placeholders::bytes_transferred));
- } else {
- // start upload
- const std::string filename = root["file"].asString();
- if (filename.find("/") != std::string::npos) {
- // slashes in file names are illegal
- answer["accept"] = false;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- } else {
- // build file path
- this->putFileName = this->fileDirectory;
- this->putFileName.append(filename);
- // open file and test if it already exists
- this->putFile.open(this->putFileName,
- std::ios::app | std::ios::binary);
- if (this->putFile.tellp() != std::ios::beg &&
- root["file"].isString()) {
- // file already exists
- this->putFile.close();
- answer["accept"] = false;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- } else {
- // accept file
- answer["accept"] = true;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- }
- }
- }
- } else if (root["command"].asString().compare("get") == 0) {
- // read next data
- sock.async_read_some(buffer(data, max_length),
- boost::bind(&con_handler::handle_read_command,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- answer["command"] = "get";
- if (this->getFile.is_open()) {
- // a get request is already being progressed
- if (root["received"].asInt() == this->getFileRemaining) {
- if (root["cancel"].asBool()) {
- // cancel get
- this->getFile.close();
- } else if (this->getFileRemaining > 0) {
- char fileBuffer[max_data_length];
- size_t read = this->getFile.readsome(fileBuffer, max_data_length);
- this->getFileRemaining--;
- // store binary data in vector because a string whould end with
- // '\0'
- std::vector<char> data;
- data.assign(fileBuffer, fileBuffer + read);
- answer["remaining"] = this->getFileRemaining;
- answer["cancel"] = false;
- answer["data"] = base64::encodeVector(data);
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- } else {
- // remaining 0 and received by client so you can close the file
- this->getFile.close();
- }
- } else {
- answer["accept"] = false;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- }
- } else {
- // open file
- const std::string filename = root["file"].asString();
- if (filename.find("/") != std::string::npos) {
- // slashes in file names are illegal
- answer["accept"] = false;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- } else {
- std::string file = this->fileDirectory;
- file.append(filename);
- this->getFile = std::ifstream(file, std::ios::ate | std::ios::binary);
- if (this->getFile.is_open() == 0) {
- // file does not exist or cannot be opened
- answer["accept"] = false;
- const std::string answerString =
- Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- } else {
- answer["accept"] = true;
- std::string answerString = Json::writeString(stringBuilder, answer);
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- answer = Json::Value();
- answer["command"] = "get";
- // get size of file
- size_t size = this->getFile.tellg();
- this->getFile.seekg(std::ios::beg);
- char fileBuffer[max_data_length];
- size_t read = this->getFile.readsome(fileBuffer, max_data_length);
- size -= read;
- this->getFileRemaining =
- size / max_data_length + (size % max_data_length == 0 ? 0 : 1);
- // store binary data in vector because a string whould end with
- // '\0'
- std::vector<char> data;
- data.assign(fileBuffer, fileBuffer + read);
- answer["remaining"] = this->getFileRemaining;
- answer["cancel"] = false;
- answer["data"] = base64::encodeVector(data);
- answerString = Json::writeString(stringBuilder, answer);
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(),
- placeholders::error,
- placeholders::bytes_transferred));
- }
- }
- }
- } else if (root["command"].asString().compare("close") == 0) {
- answer["command"] = "close";
- answer["response"] = "bye";
- const std::string answerString = Json::writeString(stringBuilder, answer);
- // send answer
- sock.async_write_some(buffer(answerString, max_length),
- boost::bind(&con_handler::handle_write,
- shared_from_this(), placeholders::error,
- placeholders::bytes_transferred));
- // close connection
- sock.close();
- } else {
- // TODO handle error
- // close connection
- sock.close();
- }
- } else {
- std::cerr << "error: " << err.message() << std::endl;
- sock.close();
- }
- }
- void con_handler::handle_write(const boost::system::error_code &err,
- size_t bytes_transferred) {
- if (!err) {
- std::cout << "Hello World!" << std::endl;
- } else {
- std::cerr << "error: " << err.message() << std::endl;
- sock.close();
- }
- }
- /**********
- * Server *
- **********/
- void Server::start_accept() {
- auto executor = acceptor_.get_executor();
- con_handler::pointer connection = con_handler::create(executor);
- acceptor_.async_accept(connection->socket(),
- boost::bind(&Server::handle_accept, this, connection,
- placeholders::error));
- }
- Server::Server(io_service &io_service)
- : acceptor_(io_service, tcp::endpoint(tcp::v4(), 1234)) {
- start_accept();
- }
- Server::~Server() {}
- void Server::handle_accept(con_handler::pointer connection,
- const boost::system::error_code &err) {
- if (!err) {
- connection->start();
- }
- start_accept();
- }
|