//
// Copyright (C) 2012 The Android Open Source Project
//
// 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.
//
#include "shill/net/sockets.h"
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
namespace shill {
Sockets::Sockets() {}
Sockets::~Sockets() {}
// Some system calls can be interrupted and return EINTR, but will succeed on
// retry. The HANDLE_EINTR macro retries a call if it returns EINTR. For a
// list of system calls that can return EINTR, see 'man 7 signal' under the
// heading "Interruption of System Calls and Library Functions by Signal
// Handlers".
int Sockets::Accept(int sockfd,
struct sockaddr* addr,
socklen_t* addrlen) const {
return HANDLE_EINTR(accept(sockfd, addr, addrlen));
}
int Sockets::AttachFilter(int sockfd, struct sock_fprog* pf) const {
return setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, pf, sizeof(*pf));
}
int Sockets::Bind(int sockfd,
const struct sockaddr* addr,
socklen_t addrlen) const {
return bind(sockfd, addr, addrlen);
}
int Sockets::BindToDevice(int sockfd, const std::string& device) const {
char dev_name[IFNAMSIZ];
CHECK_GT(sizeof(dev_name), device.length());
memset(&dev_name, 0, sizeof(dev_name));
snprintf(dev_name, sizeof(dev_name), "%s", device.c_str());
return setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, &dev_name,
sizeof(dev_name));
}
int Sockets::ReuseAddress(int sockfd) const {
int value = 1;
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
}
int Sockets::AddMulticastMembership(int sockfd, in_addr_t addr) const {
ip_mreq mreq;
mreq.imr_multiaddr.s_addr = addr;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
return setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
}
int Sockets::Close(int fd) const {
return IGNORE_EINTR(close(fd));
}
int Sockets::Connect(int sockfd,
const struct sockaddr* addr,
socklen_t addrlen) const {
return HANDLE_EINTR(connect(sockfd, addr, addrlen));
}
int Sockets::Error() const {
return errno;
}
std::string Sockets::ErrorString() const {
return std::string(strerror(Error()));
}
int Sockets::GetSockName(int sockfd,
struct sockaddr* addr,
socklen_t* addrlen) const {
return getsockname(sockfd, addr, addrlen);
}
int Sockets::GetSocketError(int sockfd) const {
int error;
socklen_t optlen = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &optlen) == 0) {
return error;
}
return -1;
}
int Sockets::Ioctl(int d, int request, void* argp) const {
return HANDLE_EINTR(ioctl(d, request, argp));
}
int Sockets::Listen(int sockfd, int backlog) const {
return listen(sockfd, backlog);
}
ssize_t Sockets::RecvFrom(int sockfd,
void* buf,
size_t len,
int flags,
struct sockaddr* src_addr,
socklen_t* addrlen) const {
return HANDLE_EINTR(recvfrom(sockfd, buf, len, flags, src_addr, addrlen));
}
int Sockets::Select(int nfds,
fd_set* readfds,
fd_set* writefds,
fd_set* exceptfds,
struct timeval* timeout) const {
return HANDLE_EINTR(select(nfds, readfds, writefds, exceptfds, timeout));
}
ssize_t Sockets::Send(int sockfd,
const void* buf,
size_t len,
int flags) const {
return HANDLE_EINTR(send(sockfd, buf, len, flags));
}
ssize_t Sockets::SendTo(int sockfd,
const void* buf,
size_t len,
int flags,
const struct sockaddr* dest_addr,
socklen_t addrlen) const {
return HANDLE_EINTR(sendto(sockfd, buf, len, flags, dest_addr, addrlen));
}
int Sockets::SetNonBlocking(int sockfd) const {
return HANDLE_EINTR(
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK));
}
int Sockets::SetReceiveBuffer(int sockfd, int size) const {
// Note: kernel will set buffer to 2*size to allow for struct skbuff overhead
return setsockopt(sockfd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
}
int Sockets::ShutDown(int sockfd, int how) const {
return HANDLE_EINTR(shutdown(sockfd, how));
}
int Sockets::Socket(int domain, int type, int protocol) const {
return socket(domain, type, protocol);
}
ScopedSocketCloser::ScopedSocketCloser(Sockets* sockets, int fd)
: sockets_(sockets),
fd_(fd) {}
ScopedSocketCloser::~ScopedSocketCloser() {
sockets_->Close(fd_);
fd_ = Sockets::kInvalidFileDescriptor;
}
int ScopedSocketCloser::Release() {
int fd = fd_;
fd_ = Sockets::kInvalidFileDescriptor;
return fd;
}
} // namespace shill