add initial code written so far no-netsession
authorterom
Mon, 10 Nov 2008 16:49:09 +0000
branchno-netsession
changeset 31 d0d7489d4e8b
parent 30 0e6f454ecf0e
child 32 2ff929186c90
add initial code written so far
src/proto2/NetworkAddress.hh
src/proto2/NetworkPacket.cc
src/proto2/NetworkPacket.hh
src/proto2/NetworkSocket.hh
src/proto2/NetworkTCP.cc
src/proto2/NetworkTCP.hh
src/proto2/NetworkUDP.hh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkAddress.hh	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,8 @@
+#ifndef NETWORK_ADDRESS_HH
+#define NETWORK_ADDRESS_HH
+
+#include <ClanLib/Network/Socket/ip_address.h>
+
+typedef CL_IPAddress NetworkAddress;
+
+#endif /* NETWORK_ADDRESS_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkPacket.cc	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,88 @@
+
+#include "NetworkPacket.hh"
+
+
+NetworkPacket::NetworkPacket (void) :
+    size(0), offset(0) {
+    
+    // nothing
+}
+
+template <typename T> T NetworkPacket::read_val (void) {
+    T val;
+
+    // check size
+    if (offset + sizeof(T) > size)
+        throw CL_Error("not enough data to read");
+    
+    // set value
+    val = *((T*) (buf + offset));
+
+    // update offset
+    offset += sizeof(T);
+
+    // return
+    return val;
+}
+
+template <typename T> void NetworkPacket::write_val (const T &val) {
+    // check max size
+    if (offset + sizeof(T) > NETWORK_PACKET_SIZE)
+        throw CL_Error("not enough space to write");
+    
+    // set value
+    *((T*) (buf + offset)) = val;
+
+    // update offset and size
+    offset += sizeof(T);
+    size += sizeof(T);
+}
+
+uint32_t NetworkPacket::read_uint32 (void) {
+    return ntohl(read_val<uint32_t>());
+}
+
+uint16_t NetworkPacket::read_uint16 (void) {
+    return ntohs(read_val<uint16_t>());
+}
+
+uint8_t NetworkPacket::read_uint8 (void) {
+    return read_val<uint8_t>();
+}
+
+int32_t NetworkPacket::read_int32 (void) {
+    return ntohl(read_val<int32_t>());
+}
+
+int16_t NetworkPacket::read_int16 (void) {
+    return ntohs(read_val<int16_t>());
+}
+
+int8_t NetworkPacket::read_int8 (void) {
+    return read_val<int8_t>();
+}
+
+void NetworkPacket::write_uint32 (uint32_t val) {
+    write_val<uint32_t>(htonl(val));
+}
+
+void NetworkPacket::write_uint16 (uint16_t val) {
+    write_val<uint16_t>(htons(val));
+}
+
+void NetworkPacket::write_uint8 (uint8_t val) {
+    write_val<uint8_t>(val);
+}
+
+void NetworkPacket::write_int32 (int32_t val) {
+    write_val<int32_t>(htonl(val));
+}
+
+void NetworkPacket::write_int16 (int16_t val) {
+    write_val<int16_t>(htons(val));
+}
+
+void NetworkPacket::write_int8 (int8_t val) {
+    write_val<int8_t>(val);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkPacket.hh	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,40 @@
+#ifndef NETWORK_PACKET_HH
+#define NETWORK_PACKET_HH
+
+#include "NetworkConfig.hh"
+
+class NetworkPacket {
+    private:
+        char buf[NETWORK_PACKET_SIZE];
+        size_t size, offset;
+
+        template <typename T> T read_val (void);
+        template <typename T> void write_val (const T &val);
+ 
+    public:
+        NetworkPacket (void);
+        
+        char* get_buf (void) { return buf; }
+        size_t get_size (void) { return size; }
+       
+        // type-reads, handle network-endianlness
+        uint32_t read_uint32 (void);
+        uint16_t read_uint16 (void);
+        uint8_t read_uint8 (void);
+
+        int32_t read_int32 (void);
+        int16_t read_int16 (void);
+        int8_t read_int8 (void);
+
+        void write_uint32 (uint32_t val);
+        void write_uint16 (uint16_t val);
+        void write_uint8 (uint8_t val);
+
+        void write_int32 (int32_t val);
+        void write_int16 (int16_t val);
+        void write_int8 (int8_t val);
+
+
+};
+
+#endif /* NETWORK_PACKET_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkSocket.hh	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,9 @@
+#ifndef NETWORK_SOCKET_HH
+#define NETWORK_SOCKET_HH
+
+#include <ClanLib/Network/Socket/socket.h>
+#include <cerrno>
+
+typedef CL_Socket NetworkSocket;
+
+#endif /* NETWORK_SOCKET_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkTCP.cc	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,177 @@
+
+#include "NetworkTCP.hh"
+
+#include <cstdlib>
+#include <cassert>
+
+NetworkBuffer::NetworkBuffer (NetworkSocket &socket, size_t size_hint) :
+    socket(socket), buf(0), size(0), offset(0) {
+    
+    // allocate initial buffer
+    if ((buf = (char *) malloc(size_hint)) == NULL)
+       throw CL_Error("malloc failed");
+    
+    // remember size
+    size = size_hint;
+}
+
+void NetworkBuffer::resize (size_t new_size) {
+    // realloc buffer
+    if ((buf = (char *) realloc((void *) buf, new_size)) == NULL)
+        throw CL_Error("realloc failed");
+    
+    // update size
+    size = new_size;
+}
+        
+void NetworkBuffer::write (const char *buf_ptr, size_t buf_size) {
+    int ret;
+
+    // try and short-circuit writes unless we have already buffered data
+    if (offset == 0) {
+        try {
+            // attempt to send something
+            ret = socket.send(buf_ptr, buf_size);
+
+        } catch (CL_Error &e) {
+            // ignore EAGAIN, detect this by setting ret to -1
+            if (errno != EAGAIN)
+                throw;
+
+            ret = -1;
+        }
+        
+        // if we managed to send something, adjust buf/size and buffer
+        if (ret > 0) {
+            buf_ptr += ret;
+            buf_size -= ret;
+
+            // sanity-check
+            assert(buf_size >= 0);
+
+            // if that was all, we're done
+            if (buf_size == 0)
+                return;
+        }
+    }
+    
+    size_t new_size = size;
+    
+    // calcluate new buffer size
+    while (offset + buf_size > new_size)
+        new_size *= 2;
+    
+    // grow internal buffer if needed
+    if (new_size != size)
+        resize(new_size);
+
+    // copy into our internal buffer
+    memcpy(buf + offset, buf_ptr, buf_size);
+}
+        
+void NetworkBuffer::flush_write (void) {
+    int ret;
+
+    // ignore if we don't have any data buffered
+    if (offset == 0)
+        return;
+    
+    // attempt to write as much as possible
+    try {
+        ret = socket.send(buf, offset)
+
+    } catch (CL_Error &e) {
+        // ignore EAGAIN and just return
+        if (errno == EAGAIN)
+            return;
+
+        else
+            throw;
+    }
+
+    // update offset
+    offset -= ret;
+
+    // shift the buffer forwards from (buf + ret) -> (buf), copying (old_offset - ret) bytes
+    memmove(buf, buf + ret, offset);
+}
+
+NetworkTCPTransport::NetworkTCPTransport (CL_Socket socket) :
+    socket(socket), in(NETWORK_TCP_INITIAL_IN_BUF), out(NETWORK_TCP_INITIAL_OUT_BUF) {
+    
+    // use nonblocking sockets
+    socket.set_nonblocking(true);
+
+    // connect signals
+    slots.connect(socket.sig_read_triggered(), this, &NetworkTCPTransport::on_read);
+    slots.connect(socket.sig_write_triggered(), this, &NetworkTCPTransport::on_write);
+    slots.connect(socket.sig_disconnected_triggered(), this, &NetworkTCPTransport::on_disconnected);
+}
+
+
+void NetworkTCPTransport::on_read (void) {
+    NetworkPacket packet;
+
+    do {
+        size_t to_read = 0;
+
+        // guess how much data to receive based on either the given length prefix or our minimim chunk size
+        if (in.read_prefix<uint16_t>(to_read) == false || to_read < NETWORK_TCP_CHUNK_SIZE)
+            to_read = NETWORK_TCP_CHUNK_SIZE 
+        
+        // do the recv
+        if (in.recv(socket, to_read) == -1)
+        
+        // read out any packets
+        while (in.read_prefix_packet<uint16_t>(packet)) {
+            handle_packet(packet);
+        }
+    } while (...);
+}
+
+void NetworkTCPTransport::on_write (void) {
+    // just flush the output buffer
+    out.flush_write();
+}
+
+void NetworkTCPTransport::on_disconnected (void) {
+
+}
+        
+void NetworkTCPTransport::write_packet (const NetworkPacket &packet) {
+    // just write to the output buffer
+    out.write(packet.get_buf(), packet.get_size());
+}
+
+NetworkTCPServer::NetworkTCPServer (const NetworkAddress &listen_addr) :
+    socket(tcp, ipv4) {
+    
+    // bind
+    socket.bind(listen_addr);
+
+    // assign slots
+    slots.connect(socket.sig_read_triggered(), this, &NetworkTCPServer::on_accept);
+
+    // listen
+    socket.listen(NETWORK_LISTEN_BACKLOG);
+}
+
+
+void NetworkTCPServer::on_accept (void) {
+    // accept a new socket
+    NetworkSocket client_sock = socket.accept();
+
+    // create a new NetworkTCPTransport
+    NetworkTCPTransport *client = new NetworkTCPTransport(client_sock);
+
+    // let our user handle it
+    handle_client(client);
+}
+        
+NetworkTCPClient::NetworkTCPClient (const NetworkAddress &connect_addr) :
+    NetworkTCPTransport(NetworkSocket(tcp, ipv4)) {
+
+    // connect
+    socket.connect(connect_addr);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkTCP.hh	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,80 @@
+#ifndef NETWORK_TCP_HH
+#define NETWORK_TCP_HH
+
+#include "NetworkSocket.hh"
+#include "NetworkAddress.hh"
+
+const size_t NETWORK_TCP_CHUNK_SIZE = 1024;
+const size_t NETWORK_TCP_INITIAL_IN_BUF = 4096;
+const size_t NETWORK_TCP_INITIAL_OUT_BUF = 0;
+
+class NetworkDisconnectError : public exception {
+
+};
+
+class NetworkBuffer {
+    private:
+        char *buf;
+        size_t size, off;
+
+        NetworkSocket &socket;
+
+    public:
+        NetworkBuffer (NetworkSocket &socket, size_t size_hint);
+    
+    private:
+        void resize (size_t new_size);
+
+    public:    
+        void write (const char *buf, size_t size);
+        void read (char *buf, size_t size);
+
+        void flush_write (void);
+
+        template <typename T> bool read_prefix (T &val_ref);
+};
+
+class NetworkTCPTransport {
+    private:
+        NetworkSocket socket;
+
+        NetworkBuffer in, out;
+    
+    protected:
+        CL_SlotContainer slots; 
+    
+    public:
+        NetworkTCPTransport (CL_Socket socket);
+
+    private:
+        void on_read (void);
+        void on_write (void);
+        void on_disconnected (void);
+
+    protected:
+        void write_packet (const NetworkPacket &packet);
+        
+        virtual void handle_packet (const NetworkPacket &packet) = 0;
+        virtual void handle_disconnect (void) = 0;
+};
+
+class NetworkTCPServer {
+    private:
+        NetworkSocket socket;
+
+    public:
+        NetworkTCPServer (const NetworkAddress &listen_addr);
+
+    private:
+        void on_accept (void);
+
+    protected:
+        virtual void handle_client (NetworkTCPTransport *client) = 0;
+};
+
+class NetworkTCPClient : public NetworkTCPTransport {
+    public:
+        NetworkTCPClient (const NetworkAddress &connect_addr);
+};
+
+#endif /* NETWORK_TCP_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkUDP.hh	Mon Nov 10 16:49:09 2008 +0000
@@ -0,0 +1,23 @@
+#ifndef NETWORK_UDP_HH
+#define NETWORK_UDP_HH
+
+#include "NetworkSocket.hh"
+
+class NetworkUDP {
+    private:
+        NetworkSocket socket;
+
+    public:
+        NetworkUDP (void);
+        NetworkUDP (const NetworkAddress &bind_addr);
+
+    private:
+        void on_recv (void);
+
+    protected:
+        bool sendto (const NetworkPacket &packet, const NetworkAddress &dst);
+
+        void handle_packet (NetworkPacket &packet, const NetworkAddress &src);
+};
+
+#endif /* NETWORK_UDP_HH */