diff options
author | Florent Le Coz <louiz@louiz.org> | 2013-11-02 23:12:16 +0100 |
---|---|---|
committer | Florent Le Coz <louiz@louiz.org> | 2013-11-02 23:39:00 +0100 |
commit | 358b53faef288d40ed28532953dc1a4183bc96c9 (patch) | |
tree | ea601464eeefa802ada7fa5443c212bb96cc0553 /src/network/socket_handler.cpp | |
parent | 7f580dbc0e529d200662e676119a3dcb966f67f9 (diff) | |
download | biboumi-358b53faef288d40ed28532953dc1a4183bc96c9.tar.gz biboumi-358b53faef288d40ed28532953dc1a4183bc96c9.tar.bz2 biboumi-358b53faef288d40ed28532953dc1a4183bc96c9.tar.xz biboumi-358b53faef288d40ed28532953dc1a4183bc96c9.zip |
Move the basic socket implementation into the SocketHandler class
(that is, the read/write/connect/etc)
Because this code is actually common for both the IrcClient and
XmppComponent class. These two classes have to implement some higher level
callbacks (parsing the data provided in the buffers, doing stuff when the
connection is done) instead of doing the read/write/connect low level
things.
Diffstat (limited to 'src/network/socket_handler.cpp')
-rw-r--r-- | src/network/socket_handler.cpp | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/network/socket_handler.cpp b/src/network/socket_handler.cpp new file mode 100644 index 0000000..e738302 --- /dev/null +++ b/src/network/socket_handler.cpp @@ -0,0 +1,113 @@ +#include <network/socket_handler.hpp> + +#include <utils/scopeguard.hpp> +#include <network/poller.hpp> + +#include <sys/types.h> +#include <sys/socket.h> +#include <cstring> +#include <netdb.h> +#include <unistd.h> + +#include <iostream> + +SocketHandler::SocketHandler(): + poller(nullptr) +{ + if ((this->socket = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) + throw std::runtime_error("Could not create socket"); +} + +void SocketHandler::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; + this->on_connected(); + return ; + } + std::cout << "Connection failed:" << std::endl; + perror("connect"); + } + std::cout << "All connection attempts failed." << std::endl; + this->close(); +} + +void SocketHandler::set_poller(Poller* poller) +{ + this->poller = poller; +} + +void SocketHandler::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<ssize_t>(size)) + throw std::runtime_error("Error reading from socket"); + else + { + this->in_buf += std::string(buf, size); + this->parse_in_buffer(); + } +} + +void SocketHandler::on_send() +{ + const ssize_t res = ::send(this->socket, this->out_buf.data(), this->out_buf.size(), 0); + if (res == -1) + { + perror("send"); + this->close(); + } + else + { + this->out_buf = this->out_buf.substr(res, std::string::npos); + if (this->out_buf.empty()) + this->poller->stop_watching_send_events(this); + } +} + +void SocketHandler::close() +{ + this->poller->remove_socket_handler(this->get_socket()); + ::close(this->socket); +} + +socket_t SocketHandler::get_socket() const +{ + return this->socket; +} + +void SocketHandler::send_data(std::string&& data) +{ + this->out_buf += std::move(data); + if (!this->out_buf.empty()) + { + this->poller->watch_send_events(this); + } +} |