188 lines
5.4 KiB
C++
188 lines
5.4 KiB
C++
//
|
|
// 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
|