merge branches/no-netsession@89 into trunk
authorterom
Thu, 20 Nov 2008 23:51:46 +0000
changeset 89 825c4613e087
parent 88 7431cd0cf900
child 90 c1a072928790
merge branches/no-netsession@89 into trunk
src/proto2/Application.cc
src/proto2/Error.hh
src/proto2/Network.cc
src/proto2/Network.hh
src/proto2/NetworkAddress.hh
src/proto2/NetworkClient.cc
src/proto2/NetworkClient.hh
src/proto2/NetworkConfig.hh
src/proto2/NetworkNode.cc
src/proto2/NetworkNode.hh
src/proto2/NetworkObject.cc
src/proto2/NetworkObject.hh
src/proto2/NetworkPacket.cc
src/proto2/NetworkPacket.hh
src/proto2/NetworkServer.cc
src/proto2/NetworkServer.hh
src/proto2/NetworkSession.cc
src/proto2/NetworkSession.hh
src/proto2/NetworkSocket.hh
src/proto2/NetworkTCP.cc
src/proto2/NetworkTCP.hh
src/proto2/NetworkUDP.cc
src/proto2/NetworkUDP.hh
--- a/src/proto2/Application.cc	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/Application.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -1,5 +1,6 @@
 
 #include "Engine.hh"
+#include "Error.hh"
 
 #include <stdexcept>
 #include <cassert>
@@ -7,16 +8,9 @@
 #include <ClanLib/core.h>
 #include <ClanLib/application.h>
 
-class ArgumentError : public std::exception {
-    private:
-        const char *message;
-    
+class ArgumentError : public Error {
     public:
-        ArgumentError (const std::string &message) : message(message.c_str()) { }
-
-        virtual const char* what() const throw() {
-            return message;
-        }
+        ArgumentError (const std::string &message) : Error(message) { }
 };
 
 class Main : public CL_ClanApplication {
@@ -125,9 +119,13 @@
 
                 // XXX: handle --help
                 return 1;
+            } catch (CL_Error &e) {
+                std::cerr << "main: CL_Error:" << e.message << std::endl;
+
+                return 1;
 
             } catch (std::exception &e) {
-                std::cerr << e.what() << std::endl;
+                std::cerr << "FATAL [uncaught_exception] " << e.what() << std::endl;
 
                 return 1;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Error.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,19 @@
+#ifndef ERROR_HH
+#define ERROR_HH
+
+#include <stdexcept>
+#include <string>
+
+class Error : public std::exception {
+    private:
+        const char *message;
+    
+    public:
+        Error (const std::string &message) : message(message.c_str()) { }
+
+        virtual const char* what() const throw() {
+            return message;
+        }
+};
+
+#endif /* ERROR_HH */
--- a/src/proto2/Network.cc	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/Network.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -1,41 +1,29 @@
-
 #include "Network.hh"
+#include "NetworkAddress.hh"
+#include "NetworkSocket.hh"
 #include "Engine.hh"
 
-void writeVector (CL_NetPacket &pkt, const Vector &vec) {
-    pkt.output.write_float32(vec.x);
-    pkt.output.write_float32(vec.y);
+#include <sstream>
+#include <cstring>
 
-/*
-    int32_t x = vec.x * COORDINATE_MAX / MAP_WIDTH;
-    int32_t y = vec.y * COORDINATE_MAX / MAP_HEIGHT;
-    
-    Engine::log(DEBUG, "network.write_vector") 
-        << "vec=" << vec << " -> x=" << x << ", y=" << y;
+std::ostream& operator<< (std::ostream &s, const NetworkAddress &addr) {
+    s << "[" << addr.get_address() << ":" << addr.get_port() << "]";
 
-    pkt.output.write_int32(x);
-    pkt.output.write_int32(y);
-*/    
+    return s;
+
+}
+        
+std::string NetworkSocketError::build_str (const NetworkSocket &socket, const char *op, const char *err) {
+    std::stringstream ss;
+
+    ss << "socket #" << socket.get_socket() << " " << op << ": " << err;
+
+    return ss.str();
 }
 
-Vector readVector (CL_NetPacket &pkt) {
-    float fx = pkt.input.read_float32();
-    float fy = pkt.input.read_float32();
-
-    Vector vec(fx, fy);
-
-/*    
-    int32_t x = pkt.input.read_int32();
-    int32_t y = pkt.input.read_int32();
-
-    float fx = x * MAP_WIDTH / COORDINATE_MAX;
-    float fy = y * MAP_HEIGHT / COORDINATE_MAX;
+NetworkSocketError::NetworkSocketError (const NetworkSocket &socket, const char *op, const char *err) :
+    Error(build_str(socket, op, err)) {
     
-    Vector vec(fx, fy);
-
-    Engine::log(DEBUG, "network.read_vector") << "x=" << x << ", y=" << y << " -> " << vec;
-*/    
-
-    return vec;
+    // nothing
 }
 
--- a/src/proto2/Network.hh	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/Network.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -14,19 +14,20 @@
 
         CL_SlotContainer slots;
 
-        CL_NetSession netsession;
+        // constructor
+        NetworkCore (GameState &state) : state(state) { }
 
-        CL_NetObject_Controller netobjs;
-        
-        // constructor
-        NetworkCore (GameState &state) : state(state), netsession(NETWORK_APP_NAME), netobjs(&netsession, NETWORK_NETOBJ_CHAN) { }
+
 
 
 };
 
-// XXX: util methods
-void writeVector (CL_NetPacket &pkt, const Vector &vec);
-Vector readVector (CL_NetPacket &pkt);
+enum NetworkChannel {
+    /*
+     * Core channel used for NetworkSession
+     */
+    NETCHAN_CORE            = 0x01,
+};
 
 enum NetworkMessage {
     NETMSG_PACKET_INVALID   = 0x00,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkAddress.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,11 @@
+#ifndef NETWORK_ADDRESS_HH
+#define NETWORK_ADDRESS_HH
+
+#include <ClanLib/Network/Socket/ip_address.h>
+
+typedef CL_IPAddress NetworkAddress;
+
+// Network.cc
+std::ostream& operator<< (std::ostream &s, const NetworkAddress &addr);
+
+#endif /* NETWORK_ADDRESS_HH */
--- a/src/proto2/NetworkClient.cc	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/NetworkClient.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -5,17 +5,17 @@
 
 #include <cassert>
 
-NetworkClient::NetworkClient (GameState &state, const CL_IPAddress &connect_to) : 
-    NetworkCore(state), server(netsession.connect(connect_to)) {
+NetworkClient::NetworkClient (GameState &state, const NetworkAddress &connect_to) : 
+    NetworkCore(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)), netobjs(netsession, NETCHAN_CORE, server) {
     
     // connect slots
-    slots.connect(netobjs.sig_create_object(), this, &NetworkClient::on_create_object);
+    slots.connect(netobjs.sig_create(), this, &NetworkClient::on_create);
 
     // XXX: sig_disconnected
 }
 
-void NetworkClient::on_create_object (CL_NetObject_Client &obj, int msg_type, CL_NetPacket &pkt) {
-    switch (msg_type) {
+void NetworkClient::on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacket &pkt) {
+    switch (msg_id) {
         case NETMSG_SERVER_HELLO:
             on_server_hello(obj, pkt);
 
@@ -32,13 +32,13 @@
             break;
 
         default:
-            Engine::log(WARN, "client.on_create_object") << "unknown msg_type=" << msg_type << " for obj=" << obj;
+            Engine::log(WARN, "client.on_create_object") << "unknown msg_id=" << msg_id << " for obj=" << obj;
     }
 }
         
-void NetworkClient::on_server_hello (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacket &pkt) {
     // read the packet
-    Vector position = readVector(pkt);
+    Vector position = pkt.read_vector();
     
     Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << position;
 
@@ -49,9 +49,9 @@
     state.newLocalPlayer(player);
 }
         
-void NetworkClient::on_player_info (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacket &pkt) {
     // read the packet
-    Vector position = readVector(pkt);
+    Vector position = pkt.read_vector();
     
     Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << position;
 
@@ -63,9 +63,9 @@
 
 }
         
-void NetworkClient::on_player_join (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
+void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacket &pkt) {
     // read the packet
-    Vector position = readVector(pkt);
+    Vector position = pkt.read_vector();
     
     Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << position;
     
@@ -85,27 +85,27 @@
     //  delete player;
 }
 
-NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector position) :
+NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
     LocalPlayer(client.state, position, true), client(client), obj(obj) {
     
     // receive messages
-    slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientLocalPlayer::on_position);
+    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientLocalPlayer::on_position);
 }
         
 void NetworkClientLocalPlayer::applyForce (Vector force, uint16_t dt) {
     // always send move, in all cases
-    CL_NetPacket pkt;
-    writeVector(pkt, force);
-    pkt.output.write_uint16(dt);
+    NetworkPacket pkt;
+    pkt.write_vector(force);
+    pkt.write_uint16(dt);
 
-    obj.send(NETMSG_CLIENT_MOVE, pkt, false);
+    obj->send(NETMSG_CLIENT_MOVE, pkt, false);
     
     // do not handle locally
 }
         
-void NetworkClientLocalPlayer::on_position (CL_NetPacket &pkt) {
-    Vector position = readVector(pkt);
-    Vector velocity = readVector(pkt);
+void NetworkClientLocalPlayer::on_position (NetworkPacket &pkt) {
+    Vector position = pkt.read_vector();
+    Vector velocity = pkt.read_vector();
 
     Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
     
@@ -113,17 +113,17 @@
     updatePhysics(position, velocity);
 }
         
-NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector position) :
+NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
     RemotePlayer(client.state, position, true), client(client), obj(obj) {
     
     // receive messages
-    slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientRemotePlayer::on_position);
-    slots.connect(obj.sig_received_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
+    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientRemotePlayer::on_position);
+    slots.connect(obj->sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
 }
 
-void NetworkClientRemotePlayer::on_position (CL_NetPacket &pkt) {
-    Vector position = readVector(pkt);
-    Vector velocity = readVector(pkt);
+void NetworkClientRemotePlayer::on_position (NetworkPacket &pkt) {
+    Vector position = pkt.read_vector();
+    Vector velocity = pkt.read_vector();
 
     Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
     
@@ -131,7 +131,7 @@
     updatePhysics(position, velocity);
 }
 
-void NetworkClientRemotePlayer::on_quit (CL_NetPacket &pkt) {
+void NetworkClientRemotePlayer::on_quit (NetworkPacket &pkt) {
     // pkt is empty
     (void) pkt;
 
@@ -139,3 +139,4 @@
 
     client.player_quit(this);
 }
+
--- a/src/proto2/NetworkClient.hh	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/NetworkClient.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -3,6 +3,8 @@
 
 #include "Network.hh"
 #include "GameState.hh"
+#include "NetworkSession.hh"
+#include "NetworkObject.hh"
 
 // forward-declare
 class NetworkClientLocalPlayer;
@@ -13,17 +15,20 @@
     friend class NetworkClientRemotePlayer;
 
     private:
-        CL_NetComputer server;
+        NetworkSession netsession;
+        NetworkNode *server;
+
+        NetworkObject_ClientController netobjs;
         
     public:
-        NetworkClient (GameState &state, const CL_IPAddress &connect_to);
+        NetworkClient (GameState &state, const NetworkAddress &connect_to);
 
     private:
-        void on_create_object (CL_NetObject_Client &obj, int msg_type, CL_NetPacket &pkt);
+        void on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacket &pkt);
 
-        void on_server_hello (CL_NetObject_Client &obj, CL_NetPacket &pkt);
-        void on_player_info (CL_NetObject_Client &obj, CL_NetPacket &pkt);
-        void on_player_join (CL_NetObject_Client &obj, CL_NetPacket &pkt);
+        void on_server_hello (NetworkObject_Client *obj, NetworkPacket &pkt);
+        void on_player_info (NetworkObject_Client *obj, NetworkPacket &pkt);
+        void on_player_join (NetworkObject_Client *obj, NetworkPacket &pkt);
     
     public:
         void player_quit (NetworkClientRemotePlayer *player);
@@ -34,16 +39,16 @@
         NetworkClient &client;
 
         CL_SlotContainer slots;
-
-        CL_NetObject_Client obj;
+        
+        NetworkObject_Client *obj;
 
     public:
-        NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector initial_position);
+        NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
         
         virtual void applyForce (Vector force, uint16_t dt);
     
     private:
-        void on_position (CL_NetPacket &pkt);
+        void on_position (NetworkPacket &pkt);
 };
 
 class NetworkClientRemotePlayer : public RemotePlayer {
@@ -52,15 +57,15 @@
         
         CL_SlotContainer slots;
 
-        CL_NetObject_Client obj;
+        NetworkObject_Client *obj;
 
     public:
-        NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector initial_position);
+        NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
     
     private:
-        void on_position (CL_NetPacket &pkt);
+        void on_position (NetworkPacket &pkt);
 
-        void on_quit (CL_NetPacket &pkt);
+        void on_quit (NetworkPacket &pkt);
 };
 
 #endif
--- a/src/proto2/NetworkConfig.hh	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/NetworkConfig.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -18,10 +18,12 @@
 
 #include <string>
 
-const std::string NETWORK_APP_NAME = "KisnaGlista";
-
 const std::string NETWORK_PORT_STR = "9338";
 
-const std::string NETWORK_NETOBJ_CHAN = "_netobj";
+const size_t NETWORK_PACKET_SIZE = 1280;
+const int NETWORK_LISTEN_BACKLOG = 5;
+
+const char NETWORK_MAGIC_STR[8+1] = "KISNGLIS";
+const uint64_t NETWORK_MAGIC_ID = * ((const uint64_t *) NETWORK_MAGIC_STR);
 
 #endif /* NETWORK_CONFIG_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkNode.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,51 @@
+
+#include <cassert>
+
+#include "NetworkNode.hh"
+
+NetworkNode::NetworkNode (NetworkSession &session, NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &address) :
+    session(session), tcp(tcp), udp(udp), address(address) {
+    
+    // connect signals
+    slots.connect(tcp->sig_disconnect(), this, &NetworkNode::on_disconnect);
+    slots.connect(tcp->sig_packet(), &session, &NetworkSession::handle_message, this);
+    
+}
+
+NetworkNode::~NetworkNode (void) {
+    delete tcp;
+}
+
+void NetworkNode::on_disconnect (void) {
+    // tell session
+    session.handle_disconnect(this);
+
+    // fire signal
+    _sig_disconnected();
+    
+    // delete
+//    delete this;
+}
+
+void NetworkNode::send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable) {
+    assert(channel_id > 0);
+    
+    // add our header
+    NetworkPacket pkt2;
+    pkt2.write_uint16(channel_id);
+    pkt2.write_packet(pkt);
+    
+    // either tcp or udp
+    if (reliable) {
+        assert(tcp);
+
+        tcp->write_packet(pkt2);
+
+    } else {
+        udp->sendto(pkt2, address);
+    }
+}
+        
+const NetworkAddress& NetworkNode::getRemoteAddress (void) {
+    return address;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkNode.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,45 @@
+#ifndef NETWORK_NODE_HH
+#define NETWORK_NODE_HH
+
+// forward-declare
+class NetworkNode;
+
+enum NetworkNodeType {
+    NETWORK_NODE_SERVER_CLIENT,
+    NETWORK_NODE_CLIENT_SERVER
+};
+
+#include "NetworkTCP.hh"
+#include "NetworkUDP.hh"
+#include "NetworkSession.hh"
+
+class NetworkNode {
+    private:
+        NetworkSession &session;
+        NetworkTCPTransport *tcp;
+        NetworkUDP *udp;
+        const NetworkAddress address;
+
+        CL_SlotContainer slots;
+    
+    public:
+        NetworkNode (NetworkSession &session, NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &address);
+        
+    private:
+        NetworkNode (const NetworkNode &copy);
+        ~NetworkNode (void);
+        NetworkNode& operator= (const NetworkNode &copy);
+        
+        void on_disconnect (void);
+         
+        CL_Signal_v0 _sig_disconnected;
+
+    public:
+        void send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true);
+
+        const NetworkAddress& getRemoteAddress (void);
+        
+        CL_Signal_v0& sig_disconnected (void) { return _sig_disconnected; }
+};
+
+#endif /* NETWORK_NODE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkObject.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,148 @@
+
+#include <cassert>
+
+#include "NetworkObject.hh"
+
+/* 
+ * NetworkObject_Controller 
+ */
+NetworkObjectController::NetworkObjectController (NetworkSession &session, NetworkChannelID channel_id) :
+    session(session), channel_id(channel_id) {
+    
+    // setup signals
+    slot_message = session.sig_chan_message(channel_id).connect(this, &NetworkObjectController::on_message);
+}
+
+void NetworkObjectController::on_message (NetworkPacket &pkt, NetworkNode *node) {
+    uint32_t obj_id = pkt.read_uint32();
+    uint16_t msg_id = pkt.read_uint16();
+    
+    // lookup object
+    NetworkObject *obj = objects[obj_id];
+
+    if (obj) {
+        obj->handle_packet(node, msg_id, pkt);
+
+    } else {
+        handle_create(obj_id, msg_id, pkt, node);
+    }
+}
+
+/* 
+ * NetworkObject_ServerController 
+ */
+NetworkObject_ServerController::NetworkObject_ServerController (NetworkSession &session, NetworkChannelID channel_id) :
+    NetworkObjectController(session, channel_id), id_pool(0) {
+
+}
+
+NetworkObjectID NetworkObject_ServerController::getObjectID (void) {
+    return ++id_pool;
+}
+        
+void NetworkObject_ServerController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) {
+    (void) obj_id;
+    (void) msg_id;
+    (void) pkt;
+    (void) node;
+
+    // XXX: fail
+    throw CL_Error("clients cannot create objects");
+}
+        
+/* 
+ * NetworkObject_ClientController *
+ */
+NetworkObject_ClientController::NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode *server) :
+    NetworkObjectController(session, channel_id), server(server) {
+
+
+}
+        
+void NetworkObject_ClientController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) {
+    // we only communicate with the server
+    assert(node == server);
+    
+    // create new object
+    NetworkObject_Client *obj = new NetworkObject_Client(*this, obj_id);
+    
+    // signal
+   _sig_create(obj, msg_id, pkt); 
+}
+
+/* 
+ * NetworkObject 
+ */
+NetworkObject::NetworkObject (NetworkObjectController &controller, NetworkObjectID obj_id) :
+    obj_id(obj_id) {
+    
+    assert(obj_id);
+
+    controller.objects[obj_id] = this;
+}
+        
+void NetworkObject::buildPacket (NetworkPacket &pkt, NetworkMessageID msg_id, const NetworkPacket &payload) {
+    pkt.write_uint32(obj_id);
+    pkt.write_uint16(msg_id);
+    pkt.write_packet(payload);
+}
+
+std::ostream& operator<< (std::ostream &s, const NetworkObject &obj) {
+    return s << "<NetworkObject #" << obj.obj_id << ">";
+}
+
+/* 
+ * NetworkObject_Server 
+ */
+NetworkObject_Server::NetworkObject_Server (NetworkObject_ServerController &controller) :
+    NetworkObject(controller, controller.getObjectID()), controller(controller) {
+    
+}
+
+void NetworkObject_Server::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) {
+    _map_sig_message[msg_id](node, pkt);
+}
+
+void NetworkObject_Server::send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable) {
+    NetworkPacket pkt_out;
+
+    buildPacket(pkt_out, msg_id, pkt);
+
+    dst->send(controller.channel_id, pkt_out, reliable);
+}
+
+void NetworkObject_Server::send_all (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable) {
+    send_all_except(msg_id, pkt, NULL, reliable);
+}
+
+void NetworkObject_Server::send_all_except (NetworkMessageID msg_id, const NetworkPacket &pkt, NetworkNode *black_sheep, bool reliable) {
+    NetworkPacket pkt_out;
+
+    buildPacket(pkt_out, msg_id, pkt);
+    
+    controller.session.send_all_except(controller.channel_id, pkt_out, black_sheep, reliable);
+}
+ 
+/* 
+ * NetworkObject_Client 
+ */
+NetworkObject_Client::NetworkObject_Client (NetworkObject_ClientController &controller, NetworkObjectID id) :
+    NetworkObject(controller, id), controller(controller) { 
+    
+    // nothing
+}
+
+void NetworkObject_Client::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) {
+    assert(node == controller.server);
+
+    _map_sig_message[msg_id](pkt);
+}
+       
+void NetworkObject_Client::send (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable) {
+    NetworkPacket pkt_out;
+
+    buildPacket(pkt_out, msg_id, pkt);
+
+    controller.server->send(controller.channel_id, pkt_out, reliable);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkObject.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,132 @@
+#ifndef NETWORK_OBJECT_HH
+#define NETWORK_OBJECT_HH
+
+#include "NetworkSession.hh"
+#include "NetworkNode.hh"
+#include "Logger.hh"
+
+#include <map>
+
+typedef uint32_t NetworkObjectID;
+typedef uint16_t NetworkMessageID;
+
+// forward-declare
+class NetworkObject;
+class NetworkObject_Client;
+class NetworkObject_Server;
+
+class NetworkObjectController {
+    friend class NetworkObject;
+    friend class NetworkObject_Server;
+    friend class NetworkObject_Client;
+
+    private:
+        NetworkSession &session;
+        NetworkChannelID channel_id;
+
+        std::map<NetworkObjectID, NetworkObject*> objects;
+
+        CL_Slot slot_message;
+    
+    protected:
+        NetworkObjectController (NetworkSession &session, NetworkChannelID channel_id);
+    
+    private:
+        void on_message (NetworkPacket &pkt, NetworkNode *node);
+
+    protected:
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) = 0; 
+};
+
+class NetworkObject_ServerController : public NetworkObjectController {
+    friend class NetworkObject_Server;
+
+    private:
+        NetworkObjectID id_pool;
+    
+    public:
+        NetworkObject_ServerController (NetworkSession &session, NetworkChannelID channel_id);
+
+    protected:
+        NetworkObjectID getObjectID (void);
+
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node);
+};
+
+class NetworkObject_ClientController : public NetworkObjectController {
+    friend class NetworkObject_Client;
+
+    private:
+        NetworkNode *server;
+
+        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacket&> _sig_create;
+    
+    public:
+        NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode *server);
+
+    protected:
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node);
+    
+    public:  
+        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacket&>& sig_create (void) { return _sig_create; }
+};
+
+class NetworkObject {
+    friend class NetworkObjectController;
+    friend std::ostream& operator<< (std::ostream &s, const NetworkObject &obj);
+
+    protected:
+        NetworkObjectID obj_id;
+
+    protected:
+        NetworkObject (NetworkObjectController &controller, NetworkObjectID obj_id);
+        
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) = 0;
+
+        void buildPacket (NetworkPacket &pkt, NetworkMessageID msg_id, const NetworkPacket &payload);
+};
+
+std::ostream& operator<< (std::ostream &s, const NetworkObject &obj);
+
+class NetworkObject_Server : public NetworkObject {
+    friend class NetworkObject_ServerController;
+
+    private:
+        NetworkObject_ServerController &controller;
+
+        std::map<NetworkMessageID, CL_Signal_v2<NetworkNode*, NetworkPacket&> > _map_sig_message;
+
+    public:
+        NetworkObject_Server (NetworkObject_ServerController &controller);
+    
+    protected:
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt);
+
+    public:
+        void send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
+        void send_all (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
+        void send_all_except (NetworkMessageID msg_id, const NetworkPacket &pkt, NetworkNode *black_sheep, bool reliable = true);
+    
+        CL_Signal_v2<NetworkNode*, NetworkPacket&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
+};
+
+class NetworkObject_Client : public NetworkObject {
+    friend class NetworkObject_ClientController;
+
+    private:
+        NetworkObject_ClientController &controller;
+
+        std::map<NetworkMessageID, CL_Signal_v1<NetworkPacket&> > _map_sig_message;
+
+    protected:
+        NetworkObject_Client (NetworkObject_ClientController &controller, NetworkObjectID id);
+        
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt);
+
+    public:
+        void send (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
+        
+        CL_Signal_v1<NetworkPacket&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
+};
+
+#endif /* NETWORK_OBJECT_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkPacket.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,143 @@
+
+#include <cassert>
+
+#include "NetworkPacket.hh"
+
+
+NetworkPacket::NetworkPacket (void) :
+    buf_size(NETWORK_PACKET_SIZE), data_size(0), offset(0) {
+    
+    // nothing
+}
+
+void NetworkPacket::check_write_size (size_t item_size) {
+     if (offset + item_size > buf_size)
+        throw NetworkPacketError("not enough space to write");
+
+}
+        
+void NetworkPacket::check_read_size (size_t item_size) {
+    if (offset + item_size > data_size)
+        throw NetworkPacketError("not enough data to read");
+}
+
+void NetworkPacket::write (const void *ptr, size_t len) {
+    // check buffer overflow
+    check_write_size(len);
+
+    // set value
+    memcpy(buf + offset, ptr, len);
+
+    // update offset and size
+    offset += len;
+    data_size += len;
+}
+
+void NetworkPacket::read (void *ptr, size_t len) {
+    // check buffer underflow
+    check_read_size(len);
+
+    // set value
+    memcpy(ptr, buf + offset, len);
+
+    // update offset
+    offset += len;
+}
+
+template <typename T> T NetworkPacket::read_val (void) {
+    T val;
+
+    // read
+    read(&val, sizeof(T));
+
+    // return
+    return val;
+}
+
+template <typename T> void NetworkPacket::write_val (const T &val) {
+    // write
+    write(&val, 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>();
+}
+        
+float NetworkPacket::read_float32 (void) {
+    int32_t ival = read_int32();
+
+    return *((float *) &ival);
+}
+
+Vector NetworkPacket::read_vector (void) {
+    float fx = read_float32();
+    float fy = read_float32();
+
+    return Vector(fx, fy);
+}
+
+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);
+}
+        
+void NetworkPacket::write_float32 (float val) {
+    write_int32(*((int32_t *) &val));
+}
+
+void NetworkPacket::write_vector (const Vector &vec) {
+    write_float32(vec.x);
+    write_float32(vec.y);
+}
+
+void NetworkPacket::write_packet (const NetworkPacket &pkt) {
+    // check buffer size
+    check_write_size(pkt.get_data_size());
+
+    // copy
+    memcpy(buf + offset, pkt.get_buf(), pkt.get_data_size());
+
+    // update offset/data_size
+    offset += pkt.get_data_size();
+    data_size += pkt.get_data_size();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkPacket.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,66 @@
+#ifndef NETWORK_PACKET_HH
+#define NETWORK_PACKET_HH
+
+#include "NetworkConfig.hh"
+#include "Vector.hh"
+#include "Error.hh"
+
+class NetworkPacketError : public Error {
+    public:
+        NetworkPacketError (const std::string &message) : Error(message) { }
+};
+
+class NetworkPacket {
+    private:
+        char buf[NETWORK_PACKET_SIZE];
+        size_t buf_size, data_size, offset;
+        
+        void check_write_size (size_t item_size);
+        void check_read_size (size_t item_size);
+
+        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; }
+        const char* get_buf (void) const { return buf; }
+        size_t get_data_size (void) const { return data_size; }
+        size_t get_buf_size (void) const { return buf_size; }
+
+        void set_data_size (size_t size) { offset = 0; data_size = size; }
+
+        // raw
+        void write (const void *ptr, size_t len);
+        void read (void *ptr, size_t len);
+       
+        // 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);
+        
+        float read_float32 (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);
+        
+        void write_float32 (float val);
+
+        // complex
+        Vector read_vector (void);
+        void write_vector (const Vector &vec);
+        void write_packet (const NetworkPacket &pkt);
+};
+
+#endif /* NETWORK_PACKET_HH */
--- a/src/proto2/NetworkServer.cc	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/NetworkServer.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -4,99 +4,94 @@
 
 #include <cassert>
 
-NetworkServer::NetworkServer (GameState &state, const std::string &listen_port) : 
-    NetworkCore(state), pid_pool(0) {
+NetworkServer::NetworkServer (GameState &state, const NetworkAddress &listen_addr) : 
+    NetworkCore(state), netsession(NETWORK_MAGIC_ID), netobjs(netsession, NETCHAN_CORE) {
     
     // connect slots
-    slots.connect(netsession.sig_computer_connected(), this, &NetworkServer::on_connect);
-    slots.connect(netsession.sig_computer_disconnected(), this, &NetworkServer::on_disconnect);
+    slots.connect(netsession.sig_node_connected(), this, &NetworkServer::on_node_connected);
     
     // and then we listen
-    netsession.start_listen(listen_port);
+    netsession.listen(listen_addr);
 
-    Engine::log(INFO, "server") << "running, listen_port=" << listen_port;
+    Engine::log(INFO, "server") << "running, listen_addr=" << listen_addr;
 }
 
-void NetworkServer::on_connect (CL_NetComputer &computer) {
-    // assign a pid
-    uint16_t pid = ++pid_pool;
-    
+void NetworkServer::on_node_connected (NetworkNode *node) {
     // create the player object (it logs it)
-    NetworkServerPlayer *player = new NetworkServerPlayer(*this, computer, pid);
+    NetworkServerPlayer *player = new NetworkServerPlayer(*this, node);
+
+    // add to players
+    players.push_back(player);
     
-    // map computer to it
-    players[computer] = player;
-
     // add to GameState
     state.newRemotePlayer(player);
 }
-
-void NetworkServer::on_disconnect (CL_NetComputer &computer) {
-    NetworkServerPlayer *player = players[computer];
-    
-    // remove from players
-    players.erase(computer);
-
+        
+void NetworkServer::handle_disconnect (NetworkServerPlayer *player) {
     // remove from state
     state.removePlayer(player);
 
-    // remove from game
-    player->disconnected();
-
-    // delete
-    delete player;
+    // remove from list
+    players.remove(player);
 }
         
-NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, CL_NetComputer &computer, uint16_t pid) : 
-    RemotePlayer(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), server(server), computer(computer), obj(&server.netobjs), pid(pid) {
+NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, NetworkNode *node) : 
+    RemotePlayer(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), server(server), obj(server.netobjs), node(node) {
     
     // log
-    Engine::log(INFO, "server_player.connected") << "computer=" << computer << ", obj=" << obj;
+    Engine::log(INFO, "server_player.connected") << "node=" << node << ", obj=" << obj;
 
     // messages
-    slots.connect(obj.sig_received_message(NETMSG_CLIENT_MOVE), this, &NetworkServerPlayer::on_move);   
+    slots.connect(node->sig_disconnected(), this, &NetworkServerPlayer::on_disconnected);
+    slots.connect(obj.sig_message(NETMSG_CLIENT_MOVE), this, &NetworkServerPlayer::on_move);
 
     // the initial NETMSG_PLAYER_HELLO
-    CL_NetPacket hello_pkt;
-    writeVector(hello_pkt, position);
+    NetworkPacket hello_pkt;
+    hello_pkt.write_vector(position);
 
-    obj.send(computer, NETMSG_SERVER_HELLO, hello_pkt, true);
+    obj.send_to(node, NETMSG_SERVER_HELLO, hello_pkt, true);
 
     // send other player objects
-    for (std::map<CL_NetComputer, NetworkServerPlayer*>::iterator it = server.players.begin(); it != server.players.end(); it++) {
-        NetworkServerPlayer *player = it->second;
-        CL_NetPacket player_pkt;
+    for (std::list<NetworkServerPlayer*>::iterator it = server.players.begin(); it != server.players.end(); it++) {
+        NetworkServerPlayer *player = *it;
+        NetworkPacket player_pkt;
         
         // player is not in players list yet
         assert(player != this);
+        
+        player_pkt.write_vector(player->position);
 
-        writeVector(player_pkt, player->position);
-
-        player->obj.send(computer, NETMSG_PLAYER_INFO, player_pkt, true);
+        player->obj.send_to(node, NETMSG_PLAYER_INFO, player_pkt, true);
     }
 
-
-    // broadcast NETMSG_PLAYER_JOIN to all clients
-    obj.send(server.netsession.get_all(), NETMSG_PLAYER_JOIN, hello_pkt, true);
+    // broadcast NETMSG_PLAYER_JOIN to all clients except current
+    obj.send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true);
 }
 
-void NetworkServerPlayer::disconnected (void) {
-    CL_NetPacket pkt;
+void NetworkServerPlayer::on_disconnected (void) {
+    NetworkPacket pkt;
     
-    Engine::log(INFO, "server_player.disconnected") << "computer=" << computer << ", obj=" << obj;
+    Engine::log(INFO, "server_player.disconnected") << "node=" << node << ", obj=" << obj;
+    
+    // remove from server
+    server.handle_disconnect(this);
+    
+    // tell other clients
+    obj.send_all(NETMSG_PLAYER_QUIT, pkt, true);
 
-    obj.send(server.netsession.get_all(), NETMSG_PLAYER_QUIT, pkt, true);
+    // free
+//    delete this;
 }
 
-void NetworkServerPlayer::on_move (CL_NetComputer &from, CL_NetPacket &pkt) {
+void NetworkServerPlayer::on_move (NetworkNode *src, NetworkPacket &pkt) {
     // sanity-check
-    if (!(from == computer))
+    if (src != node)
         return;
     
-    Vector impulse_force = readVector(pkt);    
-    uint16_t impulse_ms = pkt.input.read_uint16();
+    Vector impulse_force = pkt.read_vector();
+    uint16_t impulse_ms = pkt.read_uint16();
 
-    Engine::log(INFO, "server_player.on_move") << "obj=" << obj << ", old_pos=" << position << ", impulse=" << impulse_force << "@" << impulse_ms << "ms";
+    Engine::log(INFO, "server_player.on_move") << "player=" << obj << ", old_pos=" << position << ", impulse=" << impulse_force << "@" << impulse_ms << "ms";
     
     // apply force
     applyForce(impulse_force, impulse_ms);
@@ -106,12 +101,12 @@
 }
         
 void NetworkServerPlayer::send_position_update (void) {
-    CL_NetPacket pkt;
-    writeVector(pkt, position);
-    writeVector(pkt, velocity);
+    NetworkPacket pkt;
+    pkt.write_vector(position);
+    pkt.write_vector(velocity);
 
     Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity;
 
-    obj.send(server.netsession.get_all(), NETMSG_PLAYER_POSITION, pkt, false);
+    obj.send_all(NETMSG_PLAYER_POSITION, pkt, false);
 }
 
--- a/src/proto2/NetworkServer.hh	Thu Nov 20 23:20:44 2008 +0000
+++ b/src/proto2/NetworkServer.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -3,6 +3,8 @@
 
 #include "Network.hh"
 #include "GameState.hh"
+#include "NetworkSession.hh"
+#include "NetworkObject.hh"
 
 #include <list>
 #include <map>
@@ -14,39 +16,35 @@
 class NetworkServer : public NetworkCore {
     friend class NetworkServerPlayer;
 
-    private:
-        uint16_t pid_pool;
-    
-    public:
-        std::map<CL_NetComputer, NetworkServerPlayer*> players;
+    protected:
+        NetworkSession netsession;
+        NetworkObject_ServerController netobjs;
+        std::list<NetworkServerPlayer *> players;
 
     public:
-        NetworkServer (GameState &state, const std::string &listen_port);
+        NetworkServer (GameState &state, const NetworkAddress &listen_addr);
+    
+    protected:
+        void handle_disconnect (NetworkServerPlayer *player);
 
     private:
-        void on_connect (CL_NetComputer &computer);
-        void on_disconnect (CL_NetComputer &computer);
-
-    
+        void on_node_connected (NetworkNode *node);
 };
 
 class NetworkServerPlayer : public RemotePlayer {
     private:
         NetworkServer &server;
-        CL_NetComputer &computer;
-        CL_NetObject_Server obj;
+        NetworkObject_Server obj;
+        NetworkNode *node;
 
         CL_SlotContainer slots;
-
-        uint16_t pid;
         
     public:
-        NetworkServerPlayer (NetworkServer &server, CL_NetComputer &computer, uint16_t pid);
-
-        void disconnected (void);
+        NetworkServerPlayer (NetworkServer &server, NetworkNode *node);
 
     private:
-        void on_move (CL_NetComputer &from, CL_NetPacket &pkt);
+        void on_disconnected (void);
+        void on_move (NetworkNode *node, NetworkPacket &pkt);
 
         void send_position_update (void);
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkSession.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,107 @@
+
+#include "NetworkSession.hh"
+#include "Engine.hh"
+
+#include <cassert>
+
+NetworkSession::NetworkSession (uint64_t magic) :
+    magic(magic), tcp_srv(NULL), udp_srv(NULL), udp_client(NULL) {
+   
+    // nothing
+}
+        
+void NetworkSession::listen (const NetworkAddress &addr) {
+    assert(tcp_srv == NULL && udp_srv == NULL);
+    
+    // create TCP/UDP servers
+    tcp_srv = new NetworkTCPServer(addr);
+    udp_srv = new NetworkUDP(addr);
+    
+    // connect signals
+    slots.connect(tcp_srv->sig_client(), this, &NetworkSession::on_tcp_client);
+    slots.connect(udp_srv->sig_packet(), this, &NetworkSession::on_udp_packet);
+}
+        
+NetworkNode *NetworkSession::build_node (NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &addr, enum NetworkNodeType type) {
+    // XXX: unused
+    (void) type;
+
+    // create node
+    return new NetworkNode(*this, tcp, udp, addr);
+}
+
+NetworkNode* NetworkSession::connect (const NetworkAddress &addr) {
+    // XXX: only one connect
+    assert(!udp_client);
+
+    // connect TCP
+    NetworkTCPClient *tcp_client = new NetworkTCPClient(addr);
+        
+    // create UDP socket on same address
+    udp_client = new NetworkUDP(tcp_client->getLocalAddress());
+    
+    // build client
+    NetworkNode *client_node = build_node(tcp_client, udp_client, addr, NETWORK_NODE_CLIENT_SERVER);
+
+    // add to nodes
+    nodes[addr] = client_node;
+
+    // connect signals
+    slots.connect(udp_client->sig_packet(), this, &NetworkSession::on_udp_packet);
+        
+    // return the "server" node
+    return client_node;
+}
+                
+void NetworkSession::handle_disconnect (NetworkNode *node) {
+    // remove from nodes
+    nodes.erase(node->getRemoteAddress());
+}
+        
+void NetworkSession::handle_message (NetworkPacket &pkt, NetworkNode *node) {
+    // read the channel id
+    NetworkChannelID channel_id = pkt.read_uint16();
+
+    // fire signal
+    _map_sig_chan_message[channel_id](pkt, node);
+}
+ 
+void NetworkSession::on_tcp_client (NetworkTCPTransport *tcp_client) {
+    // get remote address manually, because NetworkTCPServer doesn't pass it in to us
+    NetworkAddress addr = tcp_client->getRemoteAddress();
+
+    // build client
+    NetworkNode *client_node = build_node(tcp_client, udp_srv, addr, NETWORK_NODE_SERVER_CLIENT);
+
+    // add to nodes
+    nodes[addr] = client_node;
+    
+    // fire signals
+    _sig_node_connected(client_node);
+}
+        
+void NetworkSession::on_udp_packet (NetworkPacket &pkt, const NetworkAddress &addr) {
+    NetworkNode *node = nodes[addr];
+    
+    // drop from unknown sources
+    if (!node) {
+        Engine::log(WARN, "net_session.on_udp_packet") << "dropping unsolicted UDP packet from " << addr;
+        return;
+    }
+
+    // handle
+    handle_message(pkt, node);
+}
+       
+void NetworkSession::send_all (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable) {
+    send_all_except(channel_id, pkt, NULL, reliable);
+}
+        
+void NetworkSession::send_all_except (NetworkChannelID channel_id, const NetworkPacket &pkt, const NetworkNode *node, bool reliable) {
+    for (std::map<NetworkAddress, NetworkNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+        if (it->second == node)
+            continue;
+
+        it->second->send(channel_id, pkt, reliable);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkSession.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,57 @@
+#ifndef NETWORK_SESSION_HH
+#define NETWORK_SESSION_HH
+
+#include <map>
+
+// forward-declare
+class NetworkSession;
+
+/*
+ * Used to separate packets, ID zero is reserved for NetworkSession use
+ */
+typedef uint16_t NetworkChannelID;
+
+#include "NetworkTCP.hh"
+#include "NetworkUDP.hh"
+#include "NetworkNode.hh"
+
+class NetworkSession {
+    friend class NetworkNode;
+
+    private:
+        uint64_t magic;
+        NetworkTCPServer *tcp_srv;
+        NetworkUDP *udp_srv, *udp_client;
+
+        CL_SlotContainer slots;
+
+        std::map<NetworkAddress, NetworkNode*> nodes;
+        std::map<NetworkChannelID, CL_Signal_v2<NetworkPacket&, NetworkNode *> > _map_sig_chan_message;
+    
+    public:
+        NetworkSession (uint64_t magic);
+
+        void listen (const NetworkAddress &addr);
+        NetworkNode* connect (const NetworkAddress &addr);
+    
+    protected:
+        virtual NetworkNode *build_node (NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &addr, enum NetworkNodeType type);
+        
+        void handle_disconnect (NetworkNode *node);
+        void handle_message (NetworkPacket &pkt, NetworkNode *node);
+
+    private:
+        void on_tcp_client (NetworkTCPTransport *client);
+        void on_udp_packet (NetworkPacket &pkt, const NetworkAddress &addr);
+
+        CL_Signal_v1<NetworkNode*> _sig_node_connected;
+
+    public:
+        void send_all (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true);
+        void send_all_except (NetworkChannelID channel_id, const NetworkPacket &pkt, const NetworkNode *node, bool reliable = true);
+
+        CL_Signal_v1<NetworkNode*>& sig_node_connected (void) { return _sig_node_connected; }
+        CL_Signal_v2<NetworkPacket&, NetworkNode *>& sig_chan_message (NetworkChannelID cid) { return _map_sig_chan_message[cid]; }
+};
+
+#endif /* NETWORK_SESSION_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkSocket.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,31 @@
+#ifndef NETWORK_SOCKET_HH
+#define NETWORK_SOCKET_HH
+
+#include "Error.hh"
+
+#include <ClanLib/Network/Socket/socket.h>
+#include <cerrno>
+
+typedef CL_Socket NetworkSocket;
+
+// Network.cc
+class NetworkSocketError : public Error {
+    protected:
+        std::string build_str (const NetworkSocket &socket, const char *op, const char *err);
+
+        NetworkSocketError (const NetworkSocket &socket, const char *op, const char *err);
+};
+
+class NetworkSocketOSError : public NetworkSocketError {
+    public:
+        NetworkSocketOSError (const NetworkSocket &socket, const char *op) :
+            NetworkSocketError(socket, op, strerror(errno)) { }
+};
+
+class NetworkSocketEOFError : public NetworkSocketError {
+    public:
+        NetworkSocketEOFError (const NetworkSocket &socket, const char *op) :
+            NetworkSocketError(socket, op, "EOF") { }
+};
+
+#endif /* NETWORK_SOCKET_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkTCP.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,325 @@
+
+#include "NetworkTCP.hh"
+#include "Engine.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 NetworkBufferError("malloc failed");
+    
+    // remember size
+    size = size_hint;
+}
+        
+NetworkBuffer::~NetworkBuffer (void) {
+    free(buf);
+}
+
+void NetworkBuffer::resize (size_t item_size) {
+    size_t new_size = size;
+
+    // grow new_size until item_size fits
+    while (offset + item_size > new_size)
+        new_size *= 2;
+    
+    // grow if needed
+    if (new_size != size) {
+        // realloc buffer
+        if ((buf = (char *) realloc((void *) buf, new_size)) == NULL)
+            throw NetworkBufferError("realloc failed");
+
+        // update size
+        size = new_size;
+
+    } else if (new_size > (offset + item_size) * 4) {
+        // XXX: shrink?
+    }
+}
+        
+void NetworkBuffer::trim (size_t prefix_size) {
+    // update offset
+    offset -= prefix_size;
+
+    // shift the buffer forwards from (buf + prefix) -> (buf), copying (old_offset - prefix) bytes
+    memmove(buf, buf + prefix_size, offset);
+}
+     
+bool NetworkBuffer::try_read (size_t item_size) {
+    int ret;
+    size_t to_read = item_size;
+
+    // keept reads at at least NETWORK_CHUNK_SIZE bytes
+    if (to_read < NETWORK_TCP_CHUNK_SIZE)
+        to_read = NETWORK_TCP_CHUNK_SIZE;
+
+    // resize buffer if needed
+    resize(to_read);
+
+    // read once
+    try {
+        ret = socket.recv(buf + offset, to_read);
+
+    } catch (CL_Error &e) {
+        if (errno == EAGAIN)
+            return false;
+
+        else
+            throw NetworkSocketOSError(socket, "recv");
+    }
+    
+    // handle EOF
+    if (ret == 0)
+        throw NetworkSocketEOFError(socket, "recv");
+
+    assert(ret >= 0);
+
+    // update offset
+    offset += ret;
+
+    // did we get enough?
+    if ((unsigned int) ret < item_size)
+        return false;
+    else
+        return true;
+} 
+        
+bool NetworkBuffer::peek_prefix (uint16_t &ref) {
+    if (offset < sizeof(uint16_t))
+        return false;
+
+    ref = ntohs(*((uint16_t *) (buf)));
+
+    return true;
+}
+    
+bool NetworkBuffer::peek_prefix (uint32_t &ref) {
+    if (offset < sizeof(uint32_t))
+        return false;
+
+    ref = ntohl(*((uint32_t *) (buf)));
+
+    return true;
+}
+
+template <typename PrefixType> PrefixType NetworkBuffer::read_prefix (char *buf_ptr, size_t buf_max) {
+    PrefixType prefix = 0;
+    size_t missing = 0;
+    
+    do {    
+        // do we have the prefix?
+        if (peek_prefix(prefix)) {
+            // do we already have the payload?
+            if (offset >= sizeof(PrefixType) + prefix) {
+                break;
+
+            } else {
+                missing = (sizeof(PrefixType) + prefix) - offset;
+            }
+
+        } else {
+            missing = sizeof(PrefixType);
+        }
+
+        // sanity-check
+        assert(missing);
+        
+        // try and read the missing data
+        if (try_read(missing) == false) {
+            // if unable to read what we need, return zero.
+            return 0;
+        }
+        
+        // assess the situation again
+    } while (true);
+    
+    // copy the data over, unless it's too large
+    if (prefix <= buf_max) {
+        // ...don't copy the prefix, though
+        memcpy(buf_ptr, buf + sizeof(PrefixType), prefix);
+    
+        // trim the bytes out
+        trim(sizeof(PrefixType) + prefix);
+        
+        // return
+        return prefix;
+
+    } else {
+        // trim the bytes out
+        trim(sizeof(PrefixType) + prefix);
+        
+        throw NetworkBufferError("recv prefix overflow");   
+    }
+}
+   
+void NetworkBuffer::push_write (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 NetworkSocketOSError(socket, "send");
+
+            ret = -1;
+        }
+        
+        // if we managed to send something, adjust buf/size and buffer
+        if (ret > 0) {
+            // sanity-check
+            assert(buf_size >= (unsigned int) ret);
+
+            buf_ptr += ret;
+            buf_size -= ret;
+
+            // if that was all, we're done
+            if (buf_size == 0)
+                return;
+        }
+    }
+    
+    // resize to fit buf_size more bytes
+    resize(buf_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 NetworkSocketOSError(socket, "send");
+    }
+
+    // trim the buffer
+    trim(ret);
+}
+        
+void NetworkBuffer::write_prefix (char *buf, uint16_t prefix) {
+    uint16_t nval = htons(prefix);
+
+    push_write((char*) &nval, sizeof(uint16_t)); 
+    push_write(buf, prefix);
+}
+
+void NetworkBuffer::write_prefix (char *buf, uint32_t prefix) {
+    uint32_t nval = htonl(prefix);
+
+    push_write((char*) &nval, sizeof(uint32_t)); 
+    push_write(buf, prefix);
+}
+
+NetworkTCPTransport::NetworkTCPTransport (NetworkSocket socket) :
+    socket(socket), in(socket, NETWORK_TCP_INITIAL_IN_BUF), out(socket, NETWORK_TCP_INITIAL_OUT_BUF) {
+    
+    // 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(), this, &NetworkTCPTransport::on_disconnected);
+}
+
+
+void NetworkTCPTransport::on_read (void) {
+    uint16_t prefix;
+    NetworkPacket packet;
+    
+    // let the in stream read length-prefixed packets and pass them on to handle_packet
+    while ((prefix = in.read_prefix<uint16_t>(packet.get_buf(), packet.get_buf_size())) > 0) {
+        packet.set_data_size(prefix);
+        _sig_packet(packet);
+    }
+}
+
+void NetworkTCPTransport::on_write (void) {
+    // just flush the output buffer
+    out.flush_write();
+}
+
+void NetworkTCPTransport::on_disconnected (void) {
+    // pass right through
+    _sig_disconnect();
+}
+        
+void NetworkTCPTransport::write_packet (const NetworkPacket &packet) {
+    uint16_t prefix = packet.get_data_size();
+    
+    if (prefix != packet.get_data_size())
+        throw CL_Error("send prefix overflow");
+    
+    try {
+        // just write to the output buffer
+        out.write_prefix((char *) packet.get_buf(), prefix);
+
+    } catch (Error &e) {
+        const char *err = e.what();
+
+        Engine::log(ERROR, "tcp.write_packet") << err;
+        
+        throw;    
+    }
+}
+
+NetworkTCPServer::NetworkTCPServer (const NetworkAddress &listen_addr) :
+    socket(CL_Socket::tcp, CL_Socket::ipv4) {
+    
+    // bind
+    socket.bind(listen_addr);
+
+    // assign slots
+    slots.connect(socket.sig_read_triggered(), this, &NetworkTCPServer::on_accept);
+
+    // listen
+    socket.listen(NETWORK_LISTEN_BACKLOG);
+    
+    // use nonblocking sockets
+    socket.set_nonblocking(true);
+}
+
+
+void NetworkTCPServer::on_accept (void) {
+    // accept a new socket
+    NetworkSocket client_sock = socket.accept();
+
+    // create a new NetworkTCPTransport
+    NetworkTCPTransport *client = buildTransport(client_sock);
+        
+    // let our user handle it
+    _sig_client(client);
+}
+        
+NetworkTCPTransport* NetworkTCPServer::buildTransport (CL_Socket &socket) {
+    return new NetworkTCPTransport(socket);
+}
+        
+NetworkTCPClient::NetworkTCPClient (const NetworkAddress &connect_addr) :
+    NetworkTCPTransport(NetworkSocket(CL_Socket::tcp, CL_Socket::ipv4)) {
+
+    // connect
+    socket.connect(connect_addr);
+    
+    // use nonblocking sockets
+    socket.set_nonblocking(true);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkTCP.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,105 @@
+#ifndef NETWORK_TCP_HH
+#define NETWORK_TCP_HH
+
+#include <ClanLib/core.h>
+
+#include "NetworkSocket.hh"
+#include "NetworkAddress.hh"
+#include "NetworkPacket.hh"
+#include "Error.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 NetworkBufferError : public Error {
+    public:
+        NetworkBufferError (const std::string &message) : Error(message) { }
+};
+
+class NetworkBuffer {
+    private:
+        NetworkSocket socket;
+
+        char *buf;
+        size_t size, offset;
+    
+    public:
+        NetworkBuffer (NetworkSocket &socket, size_t size_hint);
+        ~NetworkBuffer (void);
+    
+    private:
+        NetworkBuffer (const NetworkBuffer &copy);
+        NetworkBuffer& operator= (const NetworkBuffer &copy);
+
+        void resize (size_t item_size);
+        void trim (size_t prefix_size);
+
+    public:    
+        void push_write (char *buf_ptr, size_t buf_size);
+        void flush_write (void);
+        void write_prefix (char *buf, uint16_t prefix);
+        void write_prefix (char *buf, uint32_t prefix);
+        
+        bool try_read (size_t item_size);
+        bool peek_prefix (uint16_t &ref);
+        bool peek_prefix (uint32_t &ref);
+        template <typename PrefixType> PrefixType read_prefix (char *buf_ptr, size_t buf_max);
+};
+
+class NetworkTCPTransport {
+    protected:
+        NetworkSocket socket;
+
+        NetworkBuffer in, out;
+    
+        CL_SlotContainer slots; 
+    
+    public:
+        NetworkTCPTransport (NetworkSocket socket);
+
+    private:
+        void on_read (void);
+        void on_write (void);
+        void on_disconnected (void);
+
+        CL_Signal_v1<NetworkPacket &> _sig_packet;
+        CL_Signal_v0 _sig_disconnect;
+
+    public:
+        NetworkAddress getLocalAddress (void) { return socket.get_source_address(); }
+        NetworkAddress getRemoteAddress (void) { return socket.get_dest_address(); }
+
+        void write_packet (const NetworkPacket &packet);
+        
+        CL_Signal_v1<NetworkPacket&>& sig_packet (void) { return _sig_packet; }
+        CL_Signal_v0& sig_disconnect (void) { return _sig_disconnect; }
+};
+
+class NetworkTCPServer {
+    private:
+        NetworkSocket socket;
+
+        CL_SlotContainer slots; 
+
+    public:
+        NetworkTCPServer (const NetworkAddress &listen_addr);
+
+    private:
+        void on_accept (void);
+
+        CL_Signal_v1<NetworkTCPTransport *> _sig_client;
+
+    protected:
+        virtual NetworkTCPTransport* buildTransport (CL_Socket &socket);
+
+    public:
+        CL_Signal_v1<NetworkTCPTransport *>& sig_client (void) { return _sig_client; }
+};
+
+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.cc	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,69 @@
+
+#include "NetworkUDP.hh"
+
+#include <ClanLib/core.h>
+#include <cassert>
+
+NetworkUDP::NetworkUDP (void) : 
+    socket(CL_Socket::udp, CL_Socket::ipv4) {
+    
+    // do not bind
+
+    // connect signal
+    slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv);
+}
+
+NetworkUDP::NetworkUDP (const NetworkAddress &bind_addr) :
+    socket(CL_Socket::udp, CL_Socket::ipv4) {
+    
+    // bind socket
+    socket.bind(bind_addr);
+
+    // connect signal
+    slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv);
+}
+        
+void NetworkUDP::on_recv (void) {
+    int ret;
+    NetworkPacket pkt;
+    NetworkAddress src;
+    
+    // attempt to recv
+    try {
+        ret = socket.recv(pkt.get_buf(), pkt.get_buf_size(), src);
+
+    } catch (CL_Error &e) {
+        if (errno == EAGAIN)
+            return;
+        else
+            throw;
+    }
+    
+    // set packet data size
+    pkt.set_data_size(ret);
+
+    // handle packet
+    _sig_packet(pkt, src);
+}
+        
+bool NetworkUDP::sendto (const NetworkPacket &packet, const NetworkAddress &dst) {
+    int ret;
+
+    // XXX: shouldn't get trimmed
+    try {
+        ret = socket.send(packet.get_buf(), packet.get_data_size(), dst);
+
+    } catch (CL_Error &e) {
+        // XXX: catch some errors, but not others?
+        return false;
+    }
+
+    assert(ret > 0);
+    
+    // UDP shouldn't trim packets
+    assert((unsigned int) ret == packet.get_data_size());
+    
+    // good
+    return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkUDP.hh	Thu Nov 20 23:51:46 2008 +0000
@@ -0,0 +1,29 @@
+#ifndef NETWORK_UDP_HH
+#define NETWORK_UDP_HH
+
+#include "NetworkSocket.hh"
+#include "NetworkAddress.hh"
+#include "NetworkPacket.hh"
+
+class NetworkUDP {
+    private:
+        NetworkSocket socket;
+
+        CL_SlotContainer slots;
+
+    public:
+        NetworkUDP (void);
+        NetworkUDP (const NetworkAddress &bind_addr);
+
+    private:
+        void on_recv (void);
+
+        CL_Signal_v2<NetworkPacket &, const NetworkAddress&> _sig_packet;
+
+    public:
+        bool sendto (const NetworkPacket &packet, const NetworkAddress &dst);
+        
+        CL_Signal_v2<NetworkPacket &, const NetworkAddress&>& sig_packet (void) { return _sig_packet; }
+};
+
+#endif /* NETWORK_UDP_HH */