summaryrefslogtreecommitdiff
path: root/net/sockets.cc
blob: 1aade95d28efca601353188d7b0f080703349139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//
// 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