add compressed read/write NetworkPacket API and move zlib stuff out of NetworkServer/Client
authorTero Marttila <terom@fixme.fi>
Tue, 13 Jan 2009 21:14:12 +0200
changeset 391 59c2499fe7bb
parent 390 3c8078b96469
child 392 6c4dc68360eb
add compressed read/write NetworkPacket API and move zlib stuff out of NetworkServer/Client
.hgignore
src/Network/Client.cc
src/Network/Packet.cc
src/Network/Packet.hh
src/Network/Server.cc
--- a/.hgignore	Tue Jan 13 20:21:28 2009 +0200
+++ b/.hgignore	Tue Jan 13 21:14:12 2009 +0200
@@ -2,3 +2,4 @@
 
 ^build/(CMake|cmake|Makefile|data|doc|src|install_manifest\.txt)
 \.[^/]+\.sw[op]$
+^doc/kishna.(aux|log|pdf|toc)$
--- a/src/Network/Client.cc	Tue Jan 13 20:21:28 2009 +0200
+++ b/src/Network/Client.cc	Tue Jan 13 21:14:12 2009 +0200
@@ -6,7 +6,6 @@
 #include "../Logger.hh"
 
 #include <cassert>
-#include <zlib.h>
 
 NetworkClient::NetworkClient (Engine &engine, GameState &state, const NetworkEndpoint &connect_to) : 
     engine(engine), state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)),
@@ -36,16 +35,10 @@
     // the terrain byte array
     size_t terrain_size = map_w * map_h;
     uint8_t terrain_buf[map_w][map_h];
+
+    // read uncompressed terrain data
+    size_t inflate_size = pkt.read_uncompressed(terrain_buf, terrain_size);
     
-    // compressed packet data
-    unsigned long inflate_size = terrain_size;
-    unsigned long deflate_size = pkt.tell_remaining();
-    const uint8_t *deflate_ptr = (const uint8_t *) pkt.read_ptr(deflate_size);
-    
-    // uncompress the rest of the packet data
-    if (uncompress((uint8_t *) terrain_buf, &inflate_size, deflate_ptr, deflate_size) != Z_OK)
-        throw Error("uncompress");
-
     // invalid data?
     if (inflate_size != terrain_size)
         throw Error("Corrupt terrain data");
--- a/src/Network/Packet.cc	Tue Jan 13 20:21:28 2009 +0200
+++ b/src/Network/Packet.cc	Tue Jan 13 21:14:12 2009 +0200
@@ -4,6 +4,8 @@
 
 #include "Packet.hh"
 
+#include <zlib.h>
+
 // XXX: assumes that sizeof(float32) == sizeof(int32);
 
 /*
@@ -60,6 +62,24 @@
 
     return Vector(fx, fy);
 }
+        
+size_t NetworkPacketInput::read_uncompressed (void *buf, size_t len) {
+    // given len
+    unsigned long inflate_size = len;
+
+    // read deflate size
+    unsigned long deflate_size = read_uint32();
+
+    // pointer to packet data
+    const void *deflate_ptr = read_ptr(deflate_size);
+
+    // uncompress the rest of the packet data
+    if (uncompress((uint8_t *) buf, &inflate_size, (const uint8_t *) deflate_ptr, deflate_size) != Z_OK)
+        throw Error("uncompress");
+    
+    // return inflated size
+    return inflate_size;
+}
 
 /*
  * NetworkPacketOutput
@@ -113,6 +133,31 @@
     // just write() it
     write(pkt.get_buf(), pkt.get_data_size());
 }
+        
+void NetworkPacketOutput::write_compressed (const void *ptr, uint32_t len) {
+    // full compression buffer size, including header
+    unsigned long deflate_buf_size = write_compressed_size(len);
+
+    // size of compressed data area after header
+    unsigned long deflate_size = deflate_buf_size - sizeof(uint32_t);
+    
+    // packet buffer
+    void *deflate_buf = write_ptr(deflate_buf_size);
+
+    // compress
+    if (compress((uint8_t *) deflate_buf + sizeof(uint32_t), &deflate_size, (const uint8_t *) ptr, len) != Z_OK)
+       throw Error("compress failed"); 
+
+    // write data size
+    *((uint32_t *) deflate_buf) = htonl(deflate_size);
+    
+    // adjust final area
+    write_ptr_adjust(deflate_buf_size, sizeof(uint32_t) + deflate_size);
+}
+        
+size_t NetworkPacketOutput::write_compressed_size (uint32_t len) {
+    return sizeof(uint32_t) + compressBound(len);
+}
 
 /*
  * NetworkPacketBuffer
@@ -138,7 +183,7 @@
        
 const void* NetworkPacketBuffer::read_ptr (size_t len) {
     // check buffer overflow
-    check_write_size(len);
+    check_read_size(len);
 
     // pointer value...
     const void *ptr = buf_ptr + offset;
@@ -181,6 +226,14 @@
     memcpy(output_ptr, ptr, len);
 }
         
+void NetworkPacketBuffer::write_ptr_adjust (size_t buf_len, size_t data_len) {
+    assert(data_len <= buf_len);
+    
+    // adjust offset backwards
+    offset -= (buf_len - data_len);
+    data_size -= (buf_len - data_len);
+}
+
 size_t NetworkPacketBuffer::tell_remaining (void) {
     // number of bytes in total - number of bytes read
     return data_size - offset;
--- a/src/Network/Packet.hh	Tue Jan 13 20:21:28 2009 +0200
+++ b/src/Network/Packet.hh	Tue Jan 13 21:14:12 2009 +0200
@@ -35,6 +35,13 @@
                 void *ptr,      //<<< where to copy
                 size_t len      //<<< number of bytes to copy
         ) = 0;
+
+        /**
+         * Abstract method to get the number of input bytes remaining.
+         *
+         * @return number of input bytes still readable
+         */
+        virtual size_t tell_remaining (void) = 0;
       
         /**
          * Convenience function to read() and return the value of the given type
@@ -81,17 +88,22 @@
         Vector read_vector (void);
 
         /**
-         * Abstract method to get the number of input bytes remaining.
-         *
-         * @return number of input bytes still readable
+         * Read compressed data written with write_compressed. The given buffer must be the same size as passed to
+         * write_compressed. Returns the number of bytes that were decompressed into buf.
          */
-        virtual size_t tell_remaining (void) = 0;
+        size_t read_uncompressed (void *buf, size_t len);
 };
 
 /**
  * Write-interface for network packets
  */
 class NetworkPacketOutput {
+    protected:
+        /**
+         * Adjust size of the most recent write_ptr area of buf_len bytes to data_len bytes.
+         */
+        virtual void write_ptr_adjust (size_t buf_len, size_t data_len) = 0;
+
     public:    
         /**
          * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the write offset
@@ -144,6 +156,17 @@
          * @param pkt the sub-packet to write()
          */
         void write_packet (const NetworkPacketBuffer &pkt);
+
+        /**
+         * This will compress the given data buffer into this packet for reading with read_compressed. The compressed
+         * data will use at most write_compressed_size(len) bytes of data.
+         */
+        void write_compressed (const void *ptr, uint32_t len);
+
+        /**
+         * Return upper bound on packet size of compressed data, including header.
+         */
+        static size_t write_compressed_size (uint32_t len);
 };
 
 /**
@@ -231,6 +254,8 @@
          */
         virtual void write (const void *ptr, size_t len);
         
+        virtual void write_ptr_adjust (size_t buf_len, size_t data_len);
+        
         /**
          * Returns our data_size - read-offset
          */
--- a/src/Network/Server.cc	Tue Jan 13 20:21:28 2009 +0200
+++ b/src/Network/Server.cc	Tue Jan 13 21:14:12 2009 +0200
@@ -6,7 +6,6 @@
 #include "../Logger.hh"
 
 #include <cassert>
-#include <zlib.h>
 
 NetworkServer::NetworkServer (GameState &state, const NetworkEndpoint &listen_addr) : 
     state(state), netsession(NETWORK_MAGIC_ID), controller(netsession, NETCHAN_CORE) {
@@ -250,19 +249,16 @@
         }
     }
 
-    // compress the terrain buffer
-    unsigned long deflate_size = compressBound(terrain_size);
-    uint8_t deflate_buf[deflate_size];
-
-    // and compress
-    if (compress(deflate_buf, &deflate_size, (const uint8_t *) terrain_buf, terrain_size) != Z_OK)
-       throw Error("compress failed"); 
-    
     // allocate our packet...
     BigNetworkPacket pkt (
-        NETWORK_SESSION_HEADER_SIZE     // NetworkChannel header
-        + 3 * sizeof(uint32_t)          // our own header
-        + deflate_size                  // compressed terrain buffer
+        // NetworkChannel header
+        NETWORK_SESSION_HEADER_SIZE     
+
+        // our own header
+        + 2 * sizeof(uint32_t)          
+
+        // compressed terrain buffer
+        + NetworkPacketOutput::write_compressed_size(terrain_size)
     );
     
     // write netsession header
@@ -272,8 +268,8 @@
     pkt.write_uint32(map.x);
     pkt.write_uint32(map.y);
 
-    // write compressed data
-    pkt.write(deflate_buf, deflate_size);
+    // write compressed terrain data
+    pkt.write_compressed(terrain_buf, terrain_size);
 
     // send
     node->send_raw(pkt, true);