/* * Connection.h * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef MAD_NET_CONNECTION_H_ #define MAD_NET_CONNECTION_H_ #include #include #include #include #include "Packet.h" namespace Mad { namespace Net { class IPAddress; class Packet; class Connection { private: struct Transmission { unsigned long length; unsigned long transmitted; unsigned char *data; sigc::slot notify; }; enum State { DISCONNECTED, HANDSHAKE, CONNECTION_HEADER, PACKET_HEADER, PACKET_DATA, DISCONNECT, BYE } state; Transmission transR; std::queue transS; Packet::Data header; sigc::signal signal; void doHandshake(); void packetHeaderReceiveHandler(const void *data, unsigned long length); void packetDataReceiveHandler(const void *data, unsigned long length); void doReceive(); void doSend(); void doBye(); void doDisconnect(); bool receiveComplete() const { return (transR.length == transR.transmitted); } void bye() { if(state != DISCONNECT) return; state = BYE; doBye(); } // Prevent shallow copy Connection(const Connection &o); Connection& operator=(const Connection &o); protected: struct ConnectionHeader { unsigned char m; unsigned char a; unsigned char d; unsigned char type; unsigned char versionMajor; unsigned char versionMinor; unsigned char protVerMin; unsigned char protVerMax; }; int sock; gnutls_session_t session; IPAddress *peer; void handshake() { if(isConnected()) return; state = HANDSHAKE; doHandshake(); } virtual void connectionHeader() = 0; bool rawReceive(unsigned long length, const sigc::slot ¬ify); bool rawSend(const unsigned char *data, unsigned long length); bool enterReceiveLoop() { if(!isConnected() || isDisconnecting()) return false; state = PACKET_HEADER; return rawReceive(sizeof(Packet::Data), sigc::mem_fun(this, &Connection::packetHeaderReceiveHandler)); } public: Connection() : state(DISCONNECTED), peer(0) { transR.length = transR.transmitted = 0; transR.data = 0; } virtual ~Connection() { if(isConnected()) doDisconnect(); if(transR.data) delete [] transR.data; while(!sendQueueEmpty()) { delete [] transS.front().data; transS.pop(); } } bool isConnected() const {return (state != DISCONNECTED);} bool isConnecting() const { return (state == HANDSHAKE || state == CONNECTION_HEADER); } bool isDisconnecting() const { return (state == DISCONNECT || state == BYE); } const IPAddress* getPeer() {return peer;} int getSocket() const {return sock;} void disconnect() { if(isConnected() && !isDisconnecting()) { state = DISCONNECT; if(sendQueueEmpty()) bye(); } } struct pollfd getPollfd() const; bool send(const Packet &packet) { if(!isConnected() || isConnecting() || isDisconnecting()) return false; return rawSend(reinterpret_cast(packet.getRawData()), packet.getRawDataLength()); } void sendReceive(short events = POLLIN|POLLOUT); bool sendQueueEmpty() const {return transS.empty();} sigc::signal signalReceive() const {return signal;} static void init() { gnutls_global_init(); } static void deinit() { gnutls_global_deinit(); } }; } } #endif /*MAD_NET_CONNECTION_H_*/