# HG changeset patch # User terom # Date 1227225106 0 # Node ID 825c4613e087f4cd025e8a5bf48b942f63ef9ac9 # Parent 7431cd0cf9000d83b87f7ead97f840d9d5b7e11a merge branches/no-netsession@89 into trunk diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/Application.cc --- 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 #include @@ -7,16 +8,9 @@ #include #include -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; } diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/Error.hh --- /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 +#include + +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 */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/Network.cc --- 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 +#include -/* - 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 } diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/Network.hh --- 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, diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkAddress.hh --- /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 + +typedef CL_IPAddress NetworkAddress; + +// Network.cc +std::ostream& operator<< (std::ostream &s, const NetworkAddress &addr); + +#endif /* NETWORK_ADDRESS_HH */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkClient.cc --- 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 -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); } + diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkClient.hh --- 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 diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkConfig.hh --- 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 -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 */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkNode.cc --- /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 + +#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; +} diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkNode.hh --- /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 ©); + ~NetworkNode (void); + NetworkNode& operator= (const NetworkNode ©); + + 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 */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkObject.cc --- /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 + +#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_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); +} + diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkObject.hh --- /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 + +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 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 _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& 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 > _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& 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 > _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& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; } +}; + +#endif /* NETWORK_OBJECT_HH */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkPacket.cc --- /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 + +#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 T NetworkPacket::read_val (void) { + T val; + + // read + read(&val, sizeof(T)); + + // return + return val; +} + +template void NetworkPacket::write_val (const T &val) { + // write + write(&val, sizeof(T)); +} + +uint32_t NetworkPacket::read_uint32 (void) { + return ntohl(read_val()); +} + +uint16_t NetworkPacket::read_uint16 (void) { + return ntohs(read_val()); +} + +uint8_t NetworkPacket::read_uint8 (void) { + return read_val(); +} + +int32_t NetworkPacket::read_int32 (void) { + return ntohl(read_val()); +} + +int16_t NetworkPacket::read_int16 (void) { + return ntohs(read_val()); +} + +int8_t NetworkPacket::read_int8 (void) { + return read_val(); +} + +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(htonl(val)); +} + +void NetworkPacket::write_uint16 (uint16_t val) { + write_val(htons(val)); +} + +void NetworkPacket::write_uint8 (uint8_t val) { + write_val(val); +} + +void NetworkPacket::write_int32 (int32_t val) { + write_val(htonl(val)); +} + +void NetworkPacket::write_int16 (int16_t val) { + write_val(htons(val)); +} + +void NetworkPacket::write_int8 (int8_t val) { + write_val(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(); +} + diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkPacket.hh --- /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 T read_val (void); + template 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 */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkServer.cc --- 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 -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::iterator it = server.players.begin(); it != server.players.end(); it++) { - NetworkServerPlayer *player = it->second; - CL_NetPacket player_pkt; + for (std::list::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); } diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkServer.hh --- 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 #include @@ -14,39 +16,35 @@ class NetworkServer : public NetworkCore { friend class NetworkServerPlayer; - private: - uint16_t pid_pool; - - public: - std::map players; + protected: + NetworkSession netsession; + NetworkObject_ServerController netobjs; + std::list 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); }; diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkSession.cc --- /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 + +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::iterator it = nodes.begin(); it != nodes.end(); it++) { + if (it->second == node) + continue; + + it->second->send(channel_id, pkt, reliable); + } +} diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkSession.hh --- /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 + +// 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 nodes; + std::map > _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 _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& sig_node_connected (void) { return _sig_node_connected; } + CL_Signal_v2& sig_chan_message (NetworkChannelID cid) { return _map_sig_chan_message[cid]; } +}; + +#endif /* NETWORK_SESSION_HH */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkSocket.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 +#include + +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 */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkTCP.cc --- /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 +#include + +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 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(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); +} diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkTCP.hh --- /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 + +#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 ©); + NetworkBuffer& operator= (const NetworkBuffer ©); + + 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 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 _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& 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 _sig_client; + + protected: + virtual NetworkTCPTransport* buildTransport (CL_Socket &socket); + + public: + CL_Signal_v1& sig_client (void) { return _sig_client; } +}; + +class NetworkTCPClient : public NetworkTCPTransport { + public: + NetworkTCPClient (const NetworkAddress &connect_addr); +}; + +#endif /* NETWORK_TCP_HH */ diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkUDP.cc --- /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 +#include + +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; +} + diff -r 7431cd0cf900 -r 825c4613e087 src/proto2/NetworkUDP.hh --- /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 _sig_packet; + + public: + bool sendto (const NetworkPacket &packet, const NetworkAddress &dst); + + CL_Signal_v2& sig_packet (void) { return _sig_packet; } +}; + +#endif /* NETWORK_UDP_HH */