// // Created by Nathan Touroux on 29/06/2017. // #ifndef NETWORK_NETWORK_H #define NETWORK_NETWORK_H #ifdef WIN32 #include typedef int socklen_t; #define errno WSAGetLastError() #else #include #include #include #include #include #include #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define closesocket(s) close (s) typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; #endif // WIN32 #include #include #include #include #include #include #include #include #define size_data unsigned long struct Sock { SOCKADDR_IN sin; SOCKET sock = SOCKET_ERROR; socklen_t recsize = sizeof(sin); std::string IP = ""; std::string name = ""; int port = 0; }; //*********************************************** TCP DATA *********************************************** struct NetPacket{//should be created by NetData, contains length next to the data in "data", "size" is sizeof(size_data)+length of data void* data; size_data size; }; class NetData{ private: void* data; size_data size; void copy(void* data, size_data size); public: template::value>::type> NetData(T data); NetData(std::string str); NetData(const char *str); NetData(void *data, size_data size, bool copyData = true); NetData(const NetData ©); NetData& operator=(const NetData ©); ~NetData(); bool valid(); template::value>::type> operator T(); operator std::string(); void* getData(); size_data getSize(); NetPacket toPacket();//return a packet (the data inside should be freed) }; template NetData::NetData(T data): data(nullptr), size(sizeof(T)) { copy(&data, size); } template NetData::operator T() { if(!valid()) return T(); auto tmp = data; copy(data, size); return *static_cast(tmp); } //*********************************************** TCP CLIENT *********************************************** class TCPServer; class TCPClient{ private: Sock sock; TCPServer *server; struct Data{ void* data; size_data size; Data* next; }; Data *first, *last; int nbData; std::thread *asyncThread; std::atomic_bool asynchronous; std::atomic_bool connected; std::mutex mutex; bool invalid(); long unsafeSend(NetData data); NetData unsafeReceive(); static void asyncReceive(TCPClient *client); void push(void* data, size_data size); NetData pop(); public: TCPClient(bool asynchronous = true); TCPClient(const TCPClient &client);//just copy the asynchronous value ~TCPClient(); bool accept(TCPServer *server, bool receiveName = false);//if receive name is true, the server must send a string // (message doesn't import) to confirm that the name is accepted or else disconnect the client bool connect(std::string IP, int port, std::string name = "");//if a client is already connected with this name the // connection will fail void disconnect(bool removeFromServer = true); bool isConnected(); void enableAsynchronous(); //void disableAsynchronous(); bool asynchronousEnabled(); //WARNING: can't send/receive raw packet when asynchronous long rawSend(void *data, size_data sizeByte); long rawReceive(void *data, size_data sizeByte); long send(NetData data); NetData receive();//receive a packet with size next to the data so knowing the size isn't important std::string getIP() const; std::string getName() const; int getPort() const; int getNbData() const; }; //*********************************************** TCP SERVEUR *********************************************** class TCPServer{ private: #ifdef WIN32 WSADATA m_WSAData; #endif Sock hsock; std::vector clients; std::unordered_map clientsByIP; std::unordered_map clientsByName; std::thread *thread; int port; int error; std::atomic nbConnections; std::atomic nbConnected; bool useName; bool hosting; bool autoReconnect; unsigned int maxConnectionTry; static void waitHost(TCPServer *data); bool invalid(int client);//return true if there is a problem, false if everything is fine TCPClient empty; public: explicit TCPServer(int port, unsigned int nbConnections, bool useName = false, bool asynchronous = true); ~TCPServer(); bool host(bool waitConnections = false, bool autoReconnect = true, unsigned int maxConnectionTry = -1); bool acceptHost();//must not be called directly, it is used by host() method TCPClient& operator[](int index); TCPClient& operator[](std::string IP); TCPClient& operator()(std::string name); TCPClient& unavailable();//use this to compare against a client (ex: server[2] != server.unavailable()) void eraseClient(TCPClient &client); std::vector IPList(); std::vector namesList(); Sock getHostSock() const; int getNbConnected() const; }; //*********************************************** UDP *********************************************** class UDP{ private: std::string IP; int port; Sock sock; sockaddr from; socklen_t fromaddrsize; public: UDP(std::string IP, int port);// use "" for IP to receive from any IP ~UDP(); bool init(); long rawSend(void *data, size_data sizeByte); long rawReceive(void *data, size_data sizeByte); long send(NetData data); NetData receive();//receive a packet with size next to the data so knowing the size isn't important int getPort(); std::string getIP(); //************************************ STATIC ************************************ static long rawSendTo(std::string IP, int port, void *data, size_data sizeByte); static long sendTo(std::string IP, int port, NetData data); static long rawReceiveFrom(std::string IP, int port, void *data, size_data sizeByte); static long rawReceiveFrom(int port, void *data, size_data sizeByte);//TODO add possibility to know from wich ip it comes from static NetData receiveFrom(std::string IP, int port); static NetData receiveFrom(int port); }; #endif //NETWORK_NETWORK_H