From 7869ef2ace9a487abb0b489ca432b0a8878c5083 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 2 Nov 2013 03:19:24 +0100 Subject: First step of the connection skeleton Basic connect, socket creating, polling, recving, etc. --- src/libirc/irc_client.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++ src/libirc/irc_client.hpp | 67 ++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 src/libirc/irc_client.cpp create mode 100644 src/libirc/irc_client.hpp (limited to 'src/libirc') diff --git a/src/libirc/irc_client.cpp b/src/libirc/irc_client.cpp new file mode 100644 index 0000000..a29e588 --- /dev/null +++ b/src/libirc/irc_client.cpp @@ -0,0 +1,102 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +IrcClient::IrcClient() +{ + std::cout << "IrcClient()" << std::endl; + if ((this->socket = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) + throw std::runtime_error("Could not create socket"); +} + +IrcClient::~IrcClient() +{ + std::cout << "~IrcClient()" << std::endl; +} + +void IrcClient::on_recv() +{ + char buf[4096]; + + ssize_t size = ::recv(this->socket, buf, 4096, 0); + if (0 == size) + this->on_connection_close(); + else if (-1 == static_cast(size)) + throw std::runtime_error("Error reading from socket"); + else + { + this->in_buf += std::string(buf, size); + this->parse_in_buffer(); + } +} + +void IrcClient::on_send() +{ +} + +socket_t IrcClient::get_socket() const +{ + return this->socket; +} + +void IrcClient::connect(const std::string& address, const std::string& port) +{ + std::cout << "Trying to connect to " << address << ":" << port << std::endl; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = 0; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + struct addrinfo* addr_res; + const int res = ::getaddrinfo(address.c_str(), port.c_str(), &hints, &addr_res); + // Make sure the alloced structure is always freed at the end of the + // function + utils::ScopeGuard sg([&addr_res](){ freeaddrinfo(addr_res); }); + + if (res != 0) + { + perror("getaddrinfo"); + throw std::runtime_error("getaddrinfo failed"); + } + for (struct addrinfo* rp = addr_res; rp; rp = rp->ai_next) + { + std::cout << "One result" << std::endl; + if (::connect(this->socket, rp->ai_addr, rp->ai_addrlen) == 0) + { + std::cout << "Connection success." << std::endl; + return ; + } + std::cout << "Connection failed:" << std::endl; + perror("connect"); + } + std::cout << "All connection attempts failed." << std::endl; + this->close(); +} + +void IrcClient::on_connection_close() +{ + std::cout << "Connection closed by remote server." << std::endl; + this->close(); +} + +void IrcClient::close() +{ + this->poller->remove_socket_handler(this->get_socket()); + ::close(this->socket); +} + +void IrcClient::parse_in_buffer() +{ + std::cout << "Parsing: [" << this->in_buf << "]" << std::endl; +} diff --git a/src/libirc/irc_client.hpp b/src/libirc/irc_client.hpp new file mode 100644 index 0000000..73e7efd --- /dev/null +++ b/src/libirc/irc_client.hpp @@ -0,0 +1,67 @@ +#ifndef IRC_CLIENT_INCLUDED +# define IRC_CLIENT_INCLUDED + +#include + +#include + +/** + * Represent one IRC client, i.e. an endpoint connected to a single IRC + * server, through a TCP socket, receiving and sending commands to it. + * + * TODO: TLS support, maybe, but that's not high priority + */ +class IrcClient: public SocketHandler +{ +public: + explicit IrcClient(); + ~IrcClient(); + /** + * We read the data, try to parse it and generate some event if + * one or more full message is available. + */ + void on_recv(); + /** + * Just write as much data as possible on the socket. + */ + void on_send(); + socket_t get_socket() const; + /** + * Connect to the remote server + */ + void connect(const std::string& address, const std::string& port); + /** + * Close the connection, remove us from the poller + */ + void close(); + /** + * Called when we detect an orderly close by the remote endpoint. + */ + void on_connection_close(); + /** + * Parse the data we have received so far and try to get one or more + * complete messages from it. + */ + void parse_in_buffer(); + +private: + socket_t socket; + /** + * Where data read from the socket is added, until we can parse a whole + * IRC message, the used data is then removed from that buffer. + * + * TODO: something more efficient than a string. + */ + std::string in_buf; + /** + * Where data is added, when we want to send something to the client. + */ + std::string out_buf; + + IrcClient(const IrcClient&) = delete; + IrcClient(IrcClient&&) = delete; + IrcClient& operator=(const IrcClient&) = delete; + IrcClient& operator=(IrcClient&&) = delete; +}; + +#endif // IRC_CLIENT_INCLUDED -- cgit v1.2.3