普通文本  |  189行  |  5.44 KB

//
// 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