Преглед на файлове

Merge branch 'master' of git.rwth-aachen.de:tobias.wach/ccats into us09-1-file-transfer-client-server

Missingmew преди 5 години
родител
ревизия
022159cd8a
променени са 3 файла, в които са добавени 122 реда и са изтрити 54 реда
  1. 22 4
      Client-Server Protocol.md
  2. 10 0
      daemon/include/Server.h
  3. 90 50
      daemon/src/Server.cpp

+ 22 - 4
Client-Server Protocol.md

@@ -113,10 +113,19 @@ Client:
 	"cancel": bool
 }
 ```
-`data` is a base64 string and contains a piece of the file. The client will loop this until the file is completely sent.
+`data` is a base64 string and contains a piece of the file. The client will loop this until the file is completely sent and the server has to send and received message for every chunk.
 `remaining` is a counter how many chunks will follow and the transfer is over after it hits `0`.
 If `cancel` is `true` the file transfer will be canceled.
-
+<br /><br />
+Server:
+```
+{
+	"command": "put",
+	"recieved": int,
+	"cancel": bool
+}
+```
+If `cancel` is `false` then cancel the upload of the file.
 
 ### 2.4 Get command
 Client:
@@ -145,10 +154,19 @@ Server:
 	"cancel": bool
 }
 ```
-`data` is a base64 string and contains a piece of the file. The server will loop this until the file is completely sent.
+`data` is a base64 string and contains a piece of the file. The server will loop this until the file is completely sent and the client has to send a received message for every chunk.
 `remaining` is a counter how many chunks will follow and the transfer is over after it hits `0`.
 If `cancel` is `true` the file transfer will be canceled.
-
+<br /><br />
+Client:
+```
+{
+	"command": "get",
+	"recieved": int,
+	"cancel": bool
+}
+```
+If `cancel` is `false` then cancel the download of the file.
 
 ### TODO
 

+ 10 - 0
daemon/include/Server.h

@@ -52,6 +52,16 @@ private:
    */
   std::string putFileName;
 
+  /**
+   * Last chunk number which was sent.
+   */
+  int getFileRemaining;
+
+  /**
+   * Last chunk number which was received.
+   */
+  int putFileReceived;
+
 public:
   /**
    * Pointer to a con_handler.

+ 90 - 50
daemon/src/Server.cpp

@@ -65,7 +65,7 @@ void con_handler::handle_read_version(const boost::system::error_code &err,
     answer["version"] = this->protocolVersion;
 
     // check version string
-    if (root["version"].compare(this->protocolVersion) == 0) {
+    if (root["version"].asString().compare(this->protocolVersion) == 0) {
       answer["accept"] = true;
       const std::string answerString = Json::writeString(stringBuilder, answer);
 
@@ -120,8 +120,8 @@ void con_handler::handle_read_login(const boost::system::error_code &err,
 
     // user credentials
     // TODO check user credentials!!!
-    if (root["user"].compare("user") == 0 &&
-        root["pass"].compare("pass") == 0) {
+    if (root["user"].asString().compare("user") == 0 &&
+        root["pass"].asString().compare("pass") == 0) {
       answer["accept"] = true;
       const std::string answerString = Json::writeString(stringBuilder, answer);
 
@@ -175,7 +175,7 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
     Json::StreamWriterBuilder stringBuilder;
 
     // check command
-    if (root["command"].compare("status") == 0) {
+    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,
@@ -204,7 +204,7 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
                             boost::bind(&con_handler::handle_write,
                                         shared_from_this(), placeholders::error,
                                         placeholders::bytes_transferred));
-    } else if (root["command"].compare("list") == 0) {
+    } 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,
@@ -228,7 +228,7 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
                                         shared_from_this(), placeholders::error,
                                         placeholders::bytes_transferred));
 
-    } else if (root["command"].compare("put") == 0) {
+    } 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,
@@ -242,9 +242,10 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
         this->putFile.close();
         std::remove(this->putFileName.c_str());
 
-      } else if (this->putFile.is_open()) {
+      } 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());
@@ -253,11 +254,23 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
         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 (root["remaining"].asInt() == 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();
@@ -281,7 +294,8 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
           // 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) {
+          if (this->putFile.tellp() != std::ios::beg &&
+              root["file"].isString()) {
             // file already exists
             this->putFile.close();
             answer["accept"] = false;
@@ -309,7 +323,7 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
           }
         }
       }
-    } else if (root["command"].compare("get") == 0) {
+    } 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,
@@ -318,17 +332,50 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
 
       answer["command"] = "get";
 
-      // a get request is already being progressed
       if (this->getFile.is_open()) {
-        answer["accept"] = false;
+        // 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--;
 
-        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));
+            // 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();
@@ -365,8 +412,7 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
           } else {
             answer["accept"] = true;
 
-            const std::string answerString =
-                Json::writeString(stringBuilder, answer);
+            std::string answerString = Json::writeString(stringBuilder, answer);
 
             sock.async_write_some(buffer(answerString, max_length),
                                   boost::bind(&con_handler::handle_write,
@@ -381,38 +427,32 @@ void con_handler::handle_read_command(const boost::system::error_code &err,
             size_t size = this->getFile.tellg();
             this->getFile.seekg(std::ios::beg);
 
-            char fileBuffer[max_data_length + 1];
-            while (size_t read =
-                       this->getFile.readsome(fileBuffer, max_data_length)) {
-              fileBuffer[read] = 0;
-              size -= read;
-              int remaining = 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"] = remaining;
-              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));
-            }
+            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);
 
-            this->getFile.close();
+            // 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"].compare("close") == 0) {
+    } else if (root["command"].asString().compare("close") == 0) {
       answer["command"] = "close";
       answer["response"] = "bye";
       const std::string answerString = Json::writeString(stringBuilder, answer);