File controller.hpp¶
File List > connection > controller.hpp
Go to the documentation of this file
/*
*
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* controller.hpp
*/
#ifndef _CONTROLLER_HPP_
#define _CONTROLLER_HPP_
#include "buffer.hpp"
#include "system_parameter.h"
#include "error_manager.h"
#include <string>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <utility>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
namespace cubconn::connection
{
template <typename RX, typename TX>
class controller
{
public:
controller ();
~controller ();
controller (const controller &) = delete;
controller &operator= (const controller &) = delete;
controller (controller &&) noexcept;
controller &operator= (controller &&) noexcept;
bool open (std::string path, int flags);
int get_fd ();
result recv (RX &data, sockaddr_un &peer, socklen_t &peerlen);
result send (TX &data, sockaddr_un &peer, socklen_t &peerlen);
private:
int m_ctrlfd;
std::string m_path;
};
template <typename RX, typename TX>
controller<RX, TX>::controller () :
m_ctrlfd (-1),
m_path ()
{
}
template <typename RX, typename TX>
controller<RX, TX>::controller (controller &&other) noexcept :
m_ctrlfd (other.m_ctrlfd),
m_path (std::move (other.m_path))
{
other.m_ctrlfd = -1;
other.m_path.clear ();
}
template <typename RX, typename TX>
controller<RX, TX> &controller<RX, TX>::operator= (controller &&other) noexcept
{
if (this != &other)
{
if (m_ctrlfd >= 0)
{
::close (m_ctrlfd);
}
if (!m_path.empty ())
{
::unlink (m_path.c_str());
}
m_ctrlfd = other.m_ctrlfd;
m_path = std::move (other.m_path);
other.m_ctrlfd = -1;
other.m_path.clear ();
}
return *this;
}
template <typename RX, typename TX>
controller<RX, TX>::~controller ()
{
if (m_ctrlfd >= 0)
{
::close (m_ctrlfd);
}
if (!m_path.empty ())
{
::unlink (m_path.c_str());
}
}
template <typename RX, typename TX>
bool controller<RX, TX>::open (std::string path, int flags)
{
sockaddr_un addr;
assert (flags & SOCK_NONBLOCK);
if (m_ctrlfd >= 0)
{
::close (m_ctrlfd);
m_ctrlfd = -1;
}
if (!m_path.empty ())
{
::unlink (m_path.c_str());
m_path.clear ();
}
/* remove the first one if a previous exists */
::unlink (path.c_str());
m_ctrlfd = ::socket (AF_UNIX, SOCK_DGRAM | flags, 0);
if (m_ctrlfd < 0)
{
er_log_debug (__FILE__, __LINE__, "controller: failed to make new socket: %s\n", strerror (errno));
return false;
}
addr.sun_family = AF_UNIX;
std::snprintf (addr.sun_path, sizeof (addr.sun_path), "%s", path.c_str ());
if (::bind (m_ctrlfd, reinterpret_cast<sockaddr *> (&addr), sizeof (addr)) < 0)
{
er_log_debug (__FILE__, __LINE__, "controller: bind failed: %s\n", strerror (errno));
::close (m_ctrlfd);
m_ctrlfd = -1;
return false;
}
m_path = path;
er_log_debug (__FILE__, __LINE__, "controller: bind unix to %s\n", m_path.c_str ());
return true;
}
template <typename RX, typename TX>
int controller<RX, TX>::get_fd ()
{
return m_ctrlfd;
}
template <typename RX, typename TX>
result controller<RX, TX>::recv (RX &data, sockaddr_un &peer, socklen_t &peerlen)
{
ssize_t bytes;
peerlen = sizeof (peer);
bytes = ::recvfrom (m_ctrlfd, &data, sizeof (data), MSG_TRUNC, reinterpret_cast<sockaddr *> (&peer), &peerlen);
if (bytes < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return result::Pending;
}
return result::Error;
}
if (bytes != sizeof (RX))
{
return result::Error;
}
return result::Ok;
}
template <typename RX, typename TX>
result controller<RX, TX>::send (TX &data, sockaddr_un &peer, socklen_t &peerlen)
{
ssize_t bytes;
bytes = ::sendto (m_ctrlfd, &data, sizeof (data), 0, reinterpret_cast<const sockaddr *> (&peer), peerlen);
if (bytes < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return result::Pending;
}
return result::Error;
}
if (bytes != sizeof (TX))
{
return result::Error;
}
return result::Ok;
}
}
#endif