Work on TcpListener and TcpSocket.
This commit is contained in:
parent
4f9502df23
commit
533412d3d0
@ -47,5 +47,20 @@ inline double ntohd(double val)
|
||||
return val;
|
||||
}
|
||||
|
||||
//Windows and UNIX require some different headers.
|
||||
//We also need some compatibility defines for cross platform support.
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#define closesocket(x) close(x)
|
||||
#define INVALID_SOCKET 0
|
||||
#define SOCKET_ERROR -1
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#endif //FRNETLIB_NETWORKENCODING_H
|
||||
|
||||
@ -17,7 +17,7 @@ public:
|
||||
*
|
||||
* @return A string containing all of the data added to the packet
|
||||
*/
|
||||
inline const std::string &construct_packet()
|
||||
inline const std::string &construct_packet() const
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -6,11 +6,63 @@
|
||||
#define FRNETLIB_SOCKET_H
|
||||
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
class Socket
|
||||
{
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
Unknown = 0,
|
||||
Success = 1,
|
||||
ListenFailed = 2,
|
||||
BindFailed = 3
|
||||
};
|
||||
|
||||
private:
|
||||
/*!
|
||||
* Send a packet through the socket
|
||||
*
|
||||
* @param packet The packet to send
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
virtual bool send(const Packet &packet)=0;
|
||||
|
||||
/*!
|
||||
* Receive a packet through the socket
|
||||
*
|
||||
* @param packet The packet to receive
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
virtual bool receive(Packet &packet)=0;
|
||||
|
||||
/*!
|
||||
* Close the connection.
|
||||
*/
|
||||
virtual void close()=0;
|
||||
|
||||
/*!
|
||||
* Sets the socket's printable remote address
|
||||
*
|
||||
* @param addr The string address
|
||||
*/
|
||||
inline virtual void set_remote_address(const std::string &addr)
|
||||
{
|
||||
remote_address = addr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Gets the socket's printable remote address
|
||||
*
|
||||
* @return The string address
|
||||
*/
|
||||
inline virtual const std::string &get_remote_address()
|
||||
{
|
||||
return remote_address;
|
||||
}
|
||||
|
||||
protected:
|
||||
int socket_descriptor;
|
||||
std::string remote_address;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -4,12 +4,43 @@
|
||||
|
||||
#ifndef FRNETLIB_TCPLISTENER_H
|
||||
#define FRNETLIB_TCPLISTENER_H
|
||||
#include <string>
|
||||
#include <netdb.h>
|
||||
#include "TcpSocket.h"
|
||||
#include "Socket.h"
|
||||
#include "NetworkEncoding.h"
|
||||
|
||||
namespace fr
|
||||
{
|
||||
|
||||
class TcpListener
|
||||
{
|
||||
public:
|
||||
TcpListener();
|
||||
|
||||
/*!
|
||||
* Listens to the given port for connections
|
||||
*
|
||||
* @param port The port to bind to
|
||||
* @return If the operation was successful
|
||||
*/
|
||||
Socket::Status listen(const std::string &port);
|
||||
|
||||
/*!
|
||||
* Accepts a new connection.
|
||||
*
|
||||
* @param client Where to store the connection information
|
||||
* @return True on success. False on failure.
|
||||
*/
|
||||
Socket::Status accept(TcpSocket &client);
|
||||
|
||||
private:
|
||||
void *get_sin_addr(struct sockaddr *sa);
|
||||
addrinfo hints;
|
||||
int socket_descriptor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //FRNETLIB_TCPLISTENER_H
|
||||
|
||||
@ -5,12 +5,47 @@
|
||||
#ifndef FRNETLIB_TCPSOCKET_H
|
||||
#define FRNETLIB_TCPSOCKET_H
|
||||
|
||||
#include "Socket.h"
|
||||
|
||||
namespace fr
|
||||
{
|
||||
class TcpSocket
|
||||
{
|
||||
|
||||
};
|
||||
class TcpSocket : public Socket
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Send a packet through the socket
|
||||
*
|
||||
* @param packet The packet to send
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
virtual bool send(const Packet &packet);
|
||||
|
||||
/*!
|
||||
* Receive a packet through the socket
|
||||
*
|
||||
* @param packet The packet to receive
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
virtual bool receive(Packet &packet);
|
||||
|
||||
/*!
|
||||
* Close the connection.
|
||||
*/
|
||||
virtual void close();
|
||||
|
||||
/*!
|
||||
* Sets the socket file descriptor.
|
||||
*
|
||||
* @param descriptor The socket descriptor.
|
||||
*/
|
||||
void set_descriptor(int descriptor);
|
||||
|
||||
private:
|
||||
ssize_t read_recv();
|
||||
std::string unprocessed_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,3 +3,98 @@
|
||||
//
|
||||
|
||||
#include "TcpListener.h"
|
||||
|
||||
namespace fr
|
||||
{
|
||||
|
||||
const int yes = 1;
|
||||
const int no = 0;
|
||||
|
||||
TcpListener::TcpListener()
|
||||
{
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_UNSPEC; //IPv6 or IPv4. NOTE: Might want to make configurable.
|
||||
hints.ai_socktype = SOCK_STREAM; //TCP
|
||||
hints.ai_flags = AI_PASSIVE; //Have the IP filled in for us
|
||||
}
|
||||
|
||||
Socket::Status TcpListener::listen(const std::string &port)
|
||||
{
|
||||
addrinfo *info;
|
||||
if(int status = getaddrinfo(NULL, port.c_str(), &hints, &info) != 0)
|
||||
{
|
||||
return Socket::Status::Unknown;
|
||||
}
|
||||
//Try each of the results until we listen successfully
|
||||
addrinfo *c;
|
||||
for(c = info; c != nullptr; c = c->ai_next)
|
||||
{
|
||||
//Attempt to connect
|
||||
if((socket_descriptor = socket(c->ai_family, c->ai_socktype, c->ai_protocol)) == INVALID_SOCKET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//Set address re-use option
|
||||
if(setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int)) == SOCKET_ERROR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Attempt to bind
|
||||
if(bind(socket_descriptor, c->ai_addr, c->ai_addrlen) == SOCKET_ERROR)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//Check that we've actually bound
|
||||
if(c == nullptr)
|
||||
{
|
||||
return Socket::Status::BindFailed;
|
||||
}
|
||||
|
||||
//We're done with this now, cleanup
|
||||
freeaddrinfo(info);
|
||||
|
||||
//Listen to socket
|
||||
if(::listen(socket_descriptor, 10) == SOCKET_ERROR)
|
||||
{
|
||||
return Socket::ListenFailed;
|
||||
}
|
||||
return Socket::Success;
|
||||
}
|
||||
|
||||
Socket::Status TcpListener::accept(TcpSocket &client)
|
||||
{
|
||||
//Prepare to wait for the client
|
||||
sockaddr_storage client_addr;
|
||||
int client_descriptor;
|
||||
char client_printable_addr[INET6_ADDRSTRLEN];
|
||||
|
||||
//Accept one
|
||||
socklen_t client_addr_len = sizeof client_addr;
|
||||
client_descriptor = ::accept(socket_descriptor, (sockaddr*)&client_addr, &client_addr_len);
|
||||
if(client_descriptor == SOCKET_ERROR)
|
||||
return Socket::Unknown;
|
||||
|
||||
//Get printable address. If we failed then set it as just 'unknown'
|
||||
int err = getnameinfo((sockaddr*)&client_addr, client_addr_len, client_printable_addr, sizeof(client_printable_addr), 0,0,NI_NUMERICHOST);
|
||||
if(err != 0)
|
||||
strcpy(client_printable_addr, "unknown");
|
||||
|
||||
//Set client data
|
||||
client.set_descriptor(client_descriptor);
|
||||
client.set_remote_address(client_printable_addr);
|
||||
|
||||
return Socket::Success;
|
||||
}
|
||||
|
||||
void *TcpListener::get_sin_addr(struct sockaddr *sa)
|
||||
{
|
||||
if(sa->sa_family == AF_INET)
|
||||
return &(((sockaddr_in*)sa)->sin_addr);
|
||||
return &(((sockaddr_in6*)sa)->sin6_addr);
|
||||
}
|
||||
}
|
||||
@ -7,4 +7,44 @@
|
||||
namespace fr
|
||||
{
|
||||
|
||||
bool TcpSocket::send(const Packet &packet)
|
||||
{
|
||||
size_t send_index = 0;
|
||||
size_t sent = 0;
|
||||
|
||||
while(sent < packet.construct_packet().size())
|
||||
{
|
||||
ssize_t a = ::send(socket_descriptor, &packet.construct_packet()[send_index], packet.construct_packet().size(), 0);
|
||||
if(a < 1)
|
||||
return false;
|
||||
sent += a;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TcpSocket::receive(Packet &packet)
|
||||
{
|
||||
std::string recv_buffer;
|
||||
|
||||
//Read packet length
|
||||
uint32_t packet_length = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TcpSocket::close()
|
||||
{
|
||||
::close(socket_descriptor);
|
||||
}
|
||||
|
||||
ssize_t TcpSocket::read_recv()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TcpSocket::set_descriptor(int descriptor)
|
||||
{
|
||||
socket_descriptor = descriptor;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user