--- a/src/proto2/NetworkConfig.hh Mon Nov 10 18:21:23 2008 +0000
+++ b/src/proto2/NetworkConfig.hh Mon Nov 10 19:57:57 2008 +0000
@@ -21,5 +21,6 @@
const std::string NETWORK_PORT_STR = "9338";
const size_t NETWORK_PACKET_SIZE = 1280;
+const int NETWORK_LISTEN_BACKLOG = 5;
#endif /* NETWORK_CONFIG_HH */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkNode.cc Mon Nov 10 19:57:57 2008 +0000
@@ -0,0 +1,36 @@
+
+#include "NetworkNode.hh"
+
+NetworkNode::NetworkNode (NetworkSession &session, NetworkTCPTransport *tcp, NetworkUDP &udp, const NetworkAddress &address) :
+ session(session), tcp(tcp), udp(udp), address(address) {
+
+ // connect signals
+
+}
+
+NetworkNode::~NetworkNode (void) {
+ delete tcp;
+}
+
+void NetworkNode::send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true) {
+ 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 Mon Nov 10 19:57:57 2008 +0000
@@ -0,0 +1,28 @@
+#ifndef NETWORK_NODE_HH
+#define NETWORK_NODE_HH
+
+#include "NetworkTCP.hh"
+
+class NetworkNode {
+ private:
+ NetworkSession &session;
+ NetworkTCPTransport *tcp;
+ NetworkUDP &udp;
+ const NetworkAddress address;
+
+ CL_SlotContainer slots;
+
+ private:
+ NetworkNode (NetworkSession &session, NetworkTCPTransport *tcp, NetworkUDP &udp, const NetworkAddress &address);
+
+ NetworkNode (const NetworkNode ©) { }
+ ~NetworkNode (void);
+ NetworkNode& operator= (const NetworkNode ©) { }
+
+ public:
+ void send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true);
+
+ const NetworkAddress& getRemoteAddress (void);
+};
+
+#endif /* NETWORK_NODE_HH */
--- a/src/proto2/NetworkPacket.cc Mon Nov 10 18:21:23 2008 +0000
+++ b/src/proto2/NetworkPacket.cc Mon Nov 10 19:57:57 2008 +0000
@@ -3,17 +3,27 @@
NetworkPacket::NetworkPacket (void) :
- size(NETWORK_PACKET_SIZE), offset(0) {
+ 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 CL_Error("not enough space to write");
+
+}
+
+void NetworkPacket::check_read_size (size_t item_size) {
+ if (offset + item_size > data_size)
+ throw CL_Error("not enough data to read");
+}
+
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");
+ check_read_size(sizeof(T));
// set value
val = *((T*) (buf + offset));
@@ -27,38 +37,37 @@
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");
+ check_write_size(sizeof(T));
// set value
*((T*) (buf + offset)) = val;
// update offset and size
offset += sizeof(T);
- size += sizeof(T);
+ data_size += sizeof(T);
}
-uint32_t NetworkPacket::read_uint32 (void) {
+uint32_t NetworkPacket::read_uint32 (void) const {
return ntohl(read_val<uint32_t>());
}
-uint16_t NetworkPacket::read_uint16 (void) {
+uint16_t NetworkPacket::read_uint16 (void) const {
return ntohs(read_val<uint16_t>());
}
-uint8_t NetworkPacket::read_uint8 (void) {
+uint8_t NetworkPacket::read_uint8 (void) const {
return read_val<uint8_t>();
}
-int32_t NetworkPacket::read_int32 (void) {
+int32_t NetworkPacket::read_int32 (void) const {
return ntohl(read_val<int32_t>());
}
-int16_t NetworkPacket::read_int16 (void) {
+int16_t NetworkPacket::read_int16 (void) const {
return ntohs(read_val<int16_t>());
}
-int8_t NetworkPacket::read_int8 (void) {
+int8_t NetworkPacket::read_int8 (void) const {
return read_val<int8_t>();
}
@@ -86,3 +95,14 @@
write_val<int8_t>(val);
}
+void 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();
+}
--- a/src/proto2/NetworkPacket.hh Mon Nov 10 18:21:23 2008 +0000
+++ b/src/proto2/NetworkPacket.hh Mon Nov 10 19:57:57 2008 +0000
@@ -6,7 +6,10 @@
class NetworkPacket {
private:
char buf[NETWORK_PACKET_SIZE];
- size_t size, offset;
+ 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);
@@ -15,19 +18,20 @@
NetworkPacket (void);
char* get_buf (void) { return buf; }
- size_t get_data_size (void) { return offset; }
- size_t get_buf_size (void) { return size; }
+ 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 = size; }
+ void set_data_size (size_t size) { offset = 0; data_size = size; }
// type-reads, handle network-endianlness
- uint32_t read_uint32 (void);
- uint16_t read_uint16 (void);
- uint8_t read_uint8 (void);
+ uint32_t read_uint32 (void) const;
+ uint16_t read_uint16 (void) const;
+ uint8_t read_uint8 (void) const;
- int32_t read_int32 (void);
- int16_t read_int16 (void);
- int8_t read_int8 (void);
+ int32_t read_int32 (void) const;
+ int16_t read_int16 (void) const;
+ int8_t read_int8 (void) const;
void write_uint32 (uint32_t val);
void write_uint16 (uint16_t val);
@@ -37,7 +41,7 @@
void write_int16 (int16_t val);
void write_int8 (int8_t val);
-
+ void write_packet (const NetworkPacket &pkt);
};
#endif /* NETWORK_PACKET_HH */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkSession.cc Mon Nov 10 19:57:57 2008 +0000
@@ -0,0 +1,78 @@
+
+#include "NetworkSession.hh"
+
+NetworkSession::NetworkSession (NetworkSessionMagic 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->sig_client, this, &NetworkSession::on_tcp_client);
+}
+
+NetworkNode* NetworkSession::connect (const NetworkAddress &addr) {
+ // create new UDP client if needed
+ if (udp_client == NULL)
+ udp_client = new NetworkUDP();
+
+ // connect
+ NetworkTCPClient *tcp_client = new NetworkTCPClient(addr);
+
+ // create node
+ NetworkNode *client_node = new NetworkNode(*this, tcp_client, udp_client, addr);
+
+ // add to nodes
+ nodes[addr] = client_node;
+
+ // bind signals
+ slots.connect(tcp_client->sig_disconnected, this, &NetworkSession::on_disconnect, client_node);
+}
+
+void NetworkSession::on_tcp_client (const NetworkTCPTransport *tcp_client) {
+ // get remote address manually, because NetworkTCPServer doesn't pass it in to us
+ NetworkAddress addr = tcp_client->getRemoteAddress();
+
+ // create node
+ NetworkNode *client_node = new NetworkNode(*this, tcp_client, udp_server, addr);
+
+ // add to nodes
+ nodes[addr] = client_node;
+
+ // bind signals
+ slots.connect(tcp_client->sig_disconnected, this, &NetworkSession::on_disconnect, client_node);
+
+ // fire signals
+ sig_node_connected(node);
+}
+
+void NetworkSession::on_disconnect (NetworkNode *node) {
+ // remove from nodes
+ nodes.erase(node->getRemoteAddress());
+
+ // fire signal
+ sig_node_disconnected(node);
+
+ // delete
+ delete node;
+}
+
+void NetworkSession::send_all (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable) {
+ send_all_except(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 Mon Nov 10 19:57:57 2008 +0000
@@ -0,0 +1,47 @@
+#ifndef NETWORK_SESSION_HH
+#define NETWORK_SESSION_HH
+
+#include "NetworkTCP.hh"
+#include "NetworkUDP.hh"
+
+#include <map>
+
+/*
+ * Should be set to some 8-char magic value to identify the application
+ */
+typedef char[8] NetworkSessionMagic;
+
+/*
+ * Used to separate packets, ID zero is reserved for NetworkSession use
+ */
+typedef uint16_t NetworkChannelID;
+
+class NetworkSession {
+ private:
+ NetworkSessionMagic magic;
+ NetworkTCPServer *tcp_srv;
+ NetworkUDP *udp_srv, *udp_client;
+
+ CL_SlotContainer slots;
+
+ std::map<NetworkAddress, NetworkNode*> nodes;
+
+ public:
+ NetworkSession (NetworkSessionMagic magic);
+
+ void listen (const NetworkAddress &addr);
+ NetworkNode* connect (const NetworkAddress &addr);
+
+ private:
+ void on_tcp_client (const NetworkTCPTransport *client);
+ void on_disconnect (NetworkNode *node);
+
+ 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;
+ CL_Signal_v1<NetworkNode*> sig_node_disconnected;
+};
+
+#endif /* NETWORK_SESSION_HH */
--- a/src/proto2/NetworkTCP.cc Mon Nov 10 18:21:23 2008 +0000
+++ b/src/proto2/NetworkTCP.cc Mon Nov 10 19:57:57 2008 +0000
@@ -249,6 +249,10 @@
sig_disconnect();
}
+NetworkAddress NetworkTCPTransport::getRemoteAddress (void) {
+ return socket.get_dest_address();
+}
+
void NetworkTCPTransport::write_packet (const NetworkPacket &packet) {
uint16_t prefix = packet.get_data_size();
@@ -278,12 +282,16 @@
NetworkSocket client_sock = socket.accept();
// create a new NetworkTCPTransport
- NetworkTCPTransport *client = new NetworkTCPTransport(client_sock);
-
+ NetworkTCPTransport *client = buildTransport(client_sock);
+
// let our user handle it
sig_client(client);
}
+virtual NetworkTCPTransport NetworkTCPServer::buildTransport (CL_Socket &socket) {
+ return new NetworkTCPTransport(client_sock);
+}
+
NetworkTCPClient::NetworkTCPClient (const NetworkAddress &connect_addr) :
NetworkTCPTransport(NetworkSocket(tcp, ipv4)) {
--- a/src/proto2/NetworkTCP.hh Mon Nov 10 18:21:23 2008 +0000
+++ b/src/proto2/NetworkTCP.hh Mon Nov 10 19:57:57 2008 +0000
@@ -51,7 +51,7 @@
CL_SlotContainer slots;
public:
- NetworkTCPTransport (CL_Socket socket);
+ NetworkTCPTransport (CL_Socket &socket);
private:
void on_read (void);
@@ -59,6 +59,8 @@
void on_disconnected (void);
public:
+ NetworkAddress getRemoteAddress (void);
+
void write_packet (const NetworkPacket &packet);
CL_Signal_v1<const NetworkPacket&> sig_packet;
@@ -75,6 +77,9 @@
private:
void on_accept (void);
+ protected:
+ virtual NetworkTCPTransport buildTransport (CL_Socket &socket);
+
public:
CL_Signal_v1<NetworkTCPTransport *> sig_client;
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/NetworkUDP.cc Mon Nov 10 19:57:57 2008 +0000
@@ -0,0 +1,64 @@
+
+#include "NetworkUDP.hh"
+
+NetworkUDP::NetworkUDP (void) :
+ socket(udp, ipv4) {
+
+ // do not bind
+
+ // connect signal
+ slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv);
+}
+
+NetworkUDP::NetworkUDP (const NetworkAddress &bind_addr) :
+ socket(udp, 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());
+
+ } 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;
+ }
+
+ // UDP shouldn't trim packets
+ assert(ret == packet.get_data_size());
+
+ // good
+ return true;
+}
+