memgraph/include/io/network/socket.hpp

199 lines
4.0 KiB
C++
Raw Normal View History

2015-10-28 03:21:28 +08:00
#pragma once
#include <stdexcept>
#include <cstring>
#include <cstdio>
#include <cassert>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include "io/network/addrinfo.hpp"
2015-10-28 03:21:28 +08:00
#include "utils/likely.hpp"
2016-08-02 05:14:09 +08:00
#include "logging/default.hpp"
#include <iostream>
2015-10-28 03:21:28 +08:00
namespace io
{
class Socket
{
2016-08-02 05:14:09 +08:00
protected:
2015-10-28 03:21:28 +08:00
Socket(int family, int socket_type, int protocol)
{
socket = ::socket(family, socket_type, protocol);
}
public:
2016-08-02 05:14:09 +08:00
using byte = uint8_t;
Socket(int socket = -1) : socket(socket) {}
2015-10-28 03:21:28 +08:00
Socket(const Socket&) = delete;
2015-10-28 03:21:28 +08:00
Socket(Socket&& other)
{
*this = std::forward<Socket>(other);
2015-10-28 03:21:28 +08:00
}
~Socket()
{
if(socket == -1)
return;
#ifndef NDEBUG
logging::debug("DELETING SOCKET");
#endif
2016-08-02 05:14:09 +08:00
::close(socket);
}
void close()
{
::close(socket);
socket = -1;
2015-10-28 03:21:28 +08:00
}
Socket& operator=(Socket&& other)
{
this->socket = other.socket;
other.socket = -1;
return *this;
}
2015-10-28 03:21:28 +08:00
bool is_open()
{
return socket != -1;
}
2016-03-14 04:51:04 +08:00
static Socket connect(const std::string& addr, const std::string& port)
{
return connect(addr.c_str(), port.c_str());
}
static Socket connect(const char* addr, const char* port)
{
auto info = AddrInfo::get(addr, port);
for(struct addrinfo* it = info; it != nullptr; it = it->ai_next)
{
auto s = Socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if(!s.is_open())
continue;
if(::connect(s, it->ai_addr, it->ai_addrlen) == 0)
2016-08-02 05:14:09 +08:00
return s;
2016-03-14 04:51:04 +08:00
}
throw NetworkError("Unable to connect to socket");
}
static Socket bind(const std::string& addr, const std::string& port)
{
return bind(addr.c_str(), port.c_str());
}
static Socket bind(const char* addr, const char* port)
2015-10-28 03:21:28 +08:00
{
2015-10-29 07:34:43 +08:00
auto info = AddrInfo::get(addr, port);
2015-10-28 03:21:28 +08:00
for(struct addrinfo* it = info; it != nullptr; it = it->ai_next)
{
auto s = Socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if(!s.is_open())
continue;
2015-10-29 07:34:43 +08:00
int on = 1;
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
continue;
2015-10-28 03:21:28 +08:00
if(::bind(s, it->ai_addr, it->ai_addrlen) == 0)
2016-08-02 05:14:09 +08:00
return s;
2015-10-28 03:21:28 +08:00
}
throw NetworkError("Unable to bind to socket");
}
void set_non_blocking()
{
auto flags = fcntl(socket, F_GETFL, 0);
if(UNLIKELY(flags == -1))
throw NetworkError("Cannot read flags from socket");
flags |= O_NONBLOCK;
auto status = fcntl(socket, F_SETFL, flags);
if(UNLIKELY(status == -1))
throw NetworkError("Cannot set NON_BLOCK flag to socket");
}
void listen(int backlog)
{
auto status = ::listen(socket, backlog);
if(UNLIKELY(status == -1))
throw NetworkError("Cannot listen on socket");
}
Socket accept(struct sockaddr* addr, socklen_t* len)
{
return Socket(::accept(socket, addr, len));
}
operator int() { return socket; }
int id() const
{
return socket;
}
2016-08-02 05:14:09 +08:00
int write(const std::string& str)
2016-03-14 04:51:04 +08:00
{
2016-08-02 05:14:09 +08:00
return write(str.c_str(), str.size());
2016-03-14 04:51:04 +08:00
}
2016-08-02 05:14:09 +08:00
int write(const char* data, size_t len)
2016-03-14 04:51:04 +08:00
{
2016-08-02 05:14:09 +08:00
return write(reinterpret_cast<const byte*>(data), len);
}
int write(const byte* data, size_t len)
{
// TODO: use logger
2016-08-02 05:14:09 +08:00
#ifndef NDEBUG
std::stringstream stream;
for(size_t i = 0; i < len; ++i)
stream << fmt::format("{:02X} ", static_cast<byte>(data[i]));
auto str = stream.str();
logging::debug("[Write {}B] {}", len, str);
#endif
2016-03-14 04:51:04 +08:00
return ::write(socket, data, len);
}
2016-08-02 05:14:09 +08:00
int read(void* buffer, size_t len)
2016-03-14 04:51:04 +08:00
{
return ::read(socket, buffer, len);
}
2016-08-02 05:14:09 +08:00
protected:
Logger logger;
2015-10-28 03:21:28 +08:00
int socket;
};
}