Skip to content
Snippets Groups Projects
Commit c106fb14 authored by Armin Co's avatar Armin Co
Browse files

Socket an Protocol for communication.

parent 063106bb
No related branches found
No related tags found
No related merge requests found
/// @file Protocol.cpp
///
#include <com/Protocol.hpp>
IProtocol::IProtocol(DataSocket& socket)
: m_socket{socket}
{}
void ProtocolSimple::send_message(std::string const& url, std::string const& message)
{
m_socket.put_data(url.c_str(), url.size());
m_socket.put_data(message.c_str(), message.size());
m_socket.end_transmission();
}
/// @brief Resizeable string wrapper
///
class StringSizer
{
std::string& m_string_data;
std::size_t& m_current_size;
public:
StringSizer(std::string& string_data, std::size_t& size)
: m_string_data{string_data}
, m_current_size{size}
{
// resize to max size before more mem has to be allocated
m_string_data.resize(m_string_data.capacity());
}
~StringSizer()
{
m_string_data.resize(m_current_size);
}
void increment_size(std::size_t amount)
{
m_current_size += amount;
}
};
void ProtocolSimple::recv_message(std::string& message)
{
std::size_t data_read {0};
message.clear();
while(true)
{
StringSizer string_sizer(message, data_read);
std::size_t const data_max {message.capacity() - 1};
char* buffer = &message[0];
auto got = m_socket.get_data(buffer + data_read, data_max - data_read);
data_read += got;
if (got == 0)
{
break;
}
message.reserve(data_max * 1.5 + 10);
}
}
\ No newline at end of file
/// @file Protocol.hpp
///
#ifndef PROTOCOL_HPP
#define PROTOCOL_HPP
#include <string>
#include <com/Socket.hpp>
class IProtocol
{
public:
IProtocol(DataSocket& socket);
virtual void send_message(std::string const& url, std::string const& message) = 0;
virtual void recv_message(std::string& message) = 0;
protected:
DataSocket& m_socket;
};
class ProtocolSimple : public IProtocol
{
public:
using IProtocol::IProtocol;
void send_message(std::string const& url, std::string const& message) override;
void recv_message(std::string& message) override;
};
#endif
\ No newline at end of file
/// @file Socket.cpp
///
#include <Socket.hpp>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <strings.h>
#include <spdlog/spdlog.h>
Socket::Socket(int fd)
: m_fd{fd}
{
}
Socket::Socket(Socket&& move)
: m_fd(-1)
{
spdlog::debug("Socket is now unvalid.");
move.swap(*this);
}
Socket& Socket::operator=(Socket&& move)
{
move.swap(*this);
return *this;
}
void Socket::swap(Socket& other)
{
using std::swap;
swap(m_fd, other.m_fd);
}
Socket::~Socket()
{
if(m_fd != -1)
{
close();
}
}
int Socket::get_socket() const
{
return m_fd;
}
void Socket::close()
{
while (true)
{
int state = ::close(m_fd);
if (state == -1)
{
break;
}
else
{
switch (errno)
{
case EIO:
break;
default:
break;
}
}
}
m_fd = -1;
}
DataSocket::DataSocket(int fd)
: Socket(fd)
{
}
ConnectSocket::ConnectSocket(std::string const& host, int port)
: DataSocket(::socket(PF_INET, SOCK_STREAM, 0))
{
struct sockaddr_in serverAddr {};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = inet_addr(host.c_str());
if(::connect(get_socket(), (struct sockaddr*)&serverAddr, sizeof(serverAddr)) != 0)
{
close();
}
}
ServerSocket::ServerSocket(int port)
: Socket(::socket(PF_INET, SOCK_STREAM, 0))
{
struct sockaddr_in serverAddr;
bzero((char*)&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = INADDR_ANY;
if (::bind(get_socket(), (struct sockaddr *) &serverAddr, sizeof(serverAddr)) != 0)
{
close();
}
if (::listen(get_socket(), max_connections) != 0)
{
close();
}
}
DataSocket ServerSocket::accept()
{
struct sockaddr_storage serverStorage;
socklen_t addr_size = sizeof(serverStorage);
int new_socket = ::accept(get_socket(), (struct sockaddr*)&serverStorage, &addr_size);
return DataSocket(new_socket);
}
/// @brief Write data into socket, unitl everything is written
/// or an error occured.
///
void DataSocket::put_data(char const* data, std::size_t size)
{
std::size_t data_written {0};
while (data_written < size)
{
auto put = write(get_socket(), data + data_written, size - data_written);
if (put != -1)
{
data_written += put;
}
else
{
break;
}
}
}
std::size_t DataSocket::get_data(char* data, std::size_t size)
{
std::size_t data_read {0};
while (data_read < size)
{
auto get = read(get_socket(), data + data_read, size - data_read);
if (get != -1)
{
data_read += get;
if (get == 0) {break;}
}
else
{
spdlog::debug("Socket read returned -1");
switch (errno)
{
case ENXIO:
spdlog::error("ENXIO: Fatal programming bug");
break;
case ENOMEM:
spdlog::error("ENOMEM: Ressource acquisition failuire");
break;
case ENOTCONN:
spdlog::debug("ENOTCONN: Connection is broken.");
get = 0;
break;
case EAGAIN:
spdlog::debug("EAGAIN: Trying again.");
continue;
default:
spdlog::error("Unknown error with id <{}> occured. Check errno-base.h for more information.", errno);
break;
}
break;
}
}
return data_read;
}
void DataSocket::end_transmission()
{
if (::shutdown(get_socket(), SHUT_WR) != 0)
{
spdlog::error("shutting down transmission was not successfull.");
}
}
\ No newline at end of file
/// @file Socket.hpp
/// Whats is going on
#ifndef SOCKET_HPP
#define SOCKET_HPP
#include <string>
class Socket
{
public:
Socket(Socket&& move);
Socket& operator=(Socket&& move);
virtual ~Socket();
void close();
void swap(Socket& other);
protected:
Socket(int fd);
int get_socket() const;
private:
Socket(Socket const&) = delete;
Socket& operator=(Socket const&) = delete;
int m_fd;
};
class DataSocket : public Socket
{
public:
DataSocket(int fd);
std::size_t get_data(char* data, std::size_t size);
void put_data(char const* data, std::size_t size);
void end_transmission();
};
class ConnectSocket : public DataSocket
{
public:
ConnectSocket(std::string const& host, int port);
};
class ServerSocket : public Socket
{
static constexpr int max_connections {5};
public:
ServerSocket(int port);
DataSocket accept();
};
#endif
\ No newline at end of file
/// @file sample_client.cpp
///
#include <com/Socket.hpp>
#include <com/Protocol.hpp>
#include <spdlog/spdlog.h>
int main(int argc, char** argv)
{
spdlog::set_level(spdlog::level::info);
if (argc != 3)
{
spdlog::error("Usage: client <host> <Message>");
std::exit(1);
}
ConnectSocket connect{argv[1], 8080};
ProtocolSimple simple_connect{connect};
simple_connect.send_message("", argv[2]);
std::string message;
simple_connect.recv_message(message);
// spdlog::info("RECV: {}", message);
return 0;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment