12#include <sys/socket.h>
16#include <netinet/in.h>
29#include <boost/noncopyable.hpp>
46using namespace internal;
53 sizeof(
struct sockaddr_storage) * 2;
94 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
99 if (
sizeof(impl.sock_un_.sun_path) - 1 < unix_file.length()) {
101 "File name for a UNIX domain socket is too long: " <<
104 impl.sock_un_.sun_family = AF_UNIX;
108 memset(&impl.sock_un_.sun_path, 0,
sizeof(impl.sock_un_.sun_path));
109 strncpy(impl.sock_un_.sun_path, unix_file.c_str(),
110 sizeof(impl.sock_un_.sun_path) - 1);
111 isc_throw_assert(impl.sock_un_.sun_path[
sizeof(impl.sock_un_.sun_path) - 1] ==
'\0');
112 impl.sock_un_len_ = offsetof(
struct sockaddr_un, sun_path) +
115 impl.sock_un_.sun_len = impl.sock_un_len_;
124 if (impl_->
fd_ != -1) {
132 if (impl_->
fd_ != -1) {
134 "endpoint " << impl_->
sock_un_.sun_path);
137 impl_->
fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
138 if (impl_->
fd_ == -1) {
143 int fcntl_flags = fcntl(impl_->
fd_, F_GETFL, 0);
144 if (fcntl_flags != -1) {
145 fcntl_flags |= O_NONBLOCK;
146 fcntl_flags = fcntl(impl_->
fd_, F_SETFL, fcntl_flags);
148 if (fcntl_flags == -1) {
151 "Failed to make UNIX domain socket non blocking: " <<
157 socklen_t sndbuf_size_len =
sizeof(sndbuf_size);
158 if (getsockopt(impl_->
fd_, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
159 &sndbuf_size_len) == -1 ||
165 "Failed to set send buffer size to " <<
173 "endpoint " << impl_->
sock_un_.sun_path <<
": " <<
180 if (impl_->
fd_ == -1) {
189 const struct sockaddr& local_end,
190 const struct sockaddr& remote_end,
191 const void* data,
size_t data_len)
193 if (impl_->
fd_ == -1) {
196 if ((local_end.sa_family != AF_INET && local_end.sa_family != AF_INET6) ||
197 (remote_end.sa_family != AF_INET && remote_end.sa_family != AF_INET6))
200 "AF_INET or AF_INET6; " <<
201 static_cast<int>(local_end.sa_family) <<
", " <<
202 static_cast<int>(remote_end.sa_family) <<
" given");
204 if (family != local_end.sa_family || family != remote_end.sa_family) {
206 <<
static_cast<int>(family) <<
"; "
207 <<
static_cast<int>(local_end.sa_family) <<
", "
208 <<
static_cast<int>(remote_end.sa_family) <<
" given");
210 if (data_len == 0 || data == NULL) {
237 const uint32_t data_len32 =
static_cast<uint32_t
>(data_len);
243 const struct iovec iov[2] = {
246 {
const_cast<void*
>(data), data_len }
248 const int cc = writev(impl_->
fd_, iov, 2);
252 "Write failed in forwarding a socket session: " <<
256 "Incomplete write in forwarding a socket session: " << cc <<
262 const sockaddr* local_end,
263 const sockaddr* remote_end,
264 const void* data,
size_t data_len) :
265 sock_(sock), family_(family), type_(type), protocol_(protocol),
266 local_end_(local_end), remote_end_(remote_end),
267 data_(data), data_len_(data_len)
269 if (local_end == NULL || remote_end == NULL) {
293 "Failed to set receive buffer size to " <<
321readFail(
int actual_len,
int expected_len) {
322 if (expected_len < 0) {
324 "SocketSessionForwarder: " << strerror(errno));
326 isc_throw(SocketSessionError,
"Incomplete data from "
327 "SocketSessionForwarder: " << actual_len <<
"/" <<
334struct ScopedSocket : boost::noncopyable {
335 ScopedSocket(
int fd) :
fd_(fd) {}
352 ScopedSocket passed_sock(
recv_fd(impl_->
fd_));
356 }
else if (passed_sock.fd_ < 0) {
361 const int cc_hlen = recv(impl_->
fd_, &header_len,
sizeof(header_len),
363 if (cc_hlen <
sizeof(header_len)) {
364 readFail(cc_hlen,
sizeof(header_len));
373 const int cc_hdr = recv(impl_->
fd_, &impl_->
header_buf_[0], header_len,
375 if (cc_hdr < header_len) {
376 readFail(cc_hdr, header_len);
381 const int family =
static_cast<int>(ibuffer.
readUint32());
382 if (family != AF_INET && family != AF_INET6) {
384 "Unsupported address family is passed: " << family);
386 const int type =
static_cast<int>(ibuffer.
readUint32());
387 const int protocol =
static_cast<int>(ibuffer.
readUint32());
388 const socklen_t local_end_len = ibuffer.
readUint32();
389 const socklen_t endpoint_minlen = (family == AF_INET) ?
390 sizeof(
struct sockaddr_in) :
sizeof(
struct sockaddr_in6);
391 if (local_end_len < endpoint_minlen ||
392 local_end_len >
sizeof(impl_->
ss_local_)) {
397 const socklen_t remote_end_len = ibuffer.
readUint32();
398 if (remote_end_len < endpoint_minlen ||
404 if (family != impl_->
sa_local_->sa_family ||
407 static_cast<int>(impl_->
sa_local_->sa_family) <<
", " <<
408 static_cast<int>(impl_->
sa_remote_->sa_family) <<
409 " given, must be " << family);
414 "Invalid socket session data size: " << data_len <<
420 const int cc_data = recv(impl_->
fd_, &impl_->
data_buf_[0], data_len,
422 if (cc_data < data_len) {
423 readFail(cc_data, data_len);
426 return (
SocketSession(passed_sock.release(), family, type, protocol,
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
void writeUint16At(uint16_t data, size_t pos)
Write an unsigned 16-bit integer in host byte order at the specified position of the buffer in networ...
const void * getDataAsVoidPtr() const
Return data as a pointer to void.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
void writeUint32(uint32_t data)
Write an unsigned 32-bit integer in host byte order into the buffer in network byte order.
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
size_t getLength() const
Return the length of data written in the buffer.
void clear()
Clear buffer content.
An exception indicating general errors that takes place in the socket session related class objects.
virtual ~SocketSessionForwarder()
The destructor.
virtual void close()
Close the connection to the receiver.
virtual void connectToReceiver()
Establish a connection to the receiver.
SocketSessionForwarder(const std::string &unix_file)
The constructor.
virtual void push(int sock, int family, int type, int protocol, const struct sockaddr &local_end, const struct sockaddr &remote_end, const void *data, size_t data_len)
Forward a socket session to the receiver.
~SocketSessionReceiver()
The destructor.
SocketSession pop()
Receive a socket session from the forwarder.
SocketSessionReceiver(int fd)
The constructor.
SocketSession(int sock, int family, int type, int protocol, const sockaddr *local_end, const sockaddr *remote_end, const void *data, size_t data_len)
The constructor.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Support to transfer file descriptors between processes.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
const struct sockaddr * convertSockAddr(const SAType *sa)
socklen_t getSALength(const struct sockaddr &sa)
const size_t INITIAL_BUFSIZE
const int FD_SYSTEM_ERROR
int recv_fd(const int sock)
Receives a file descriptor.
const size_t DEFAULT_HEADER_BUFLEN
int send_fd(const int sock, const int fd)
Sends a file descriptor.
const int SOCKSESSION_BUFSIZE
Defines the logger used by the top-level component of kea-lfc.
struct sockaddr_un sock_un_
struct sockaddr_storage ss_remote_
vector< uint8_t > data_buf_
struct sockaddr *const sa_remote_
struct sockaddr *const sa_local_
vector< uint8_t > header_buf_
struct sockaddr_storage ss_local_