Apache Mesos
socket.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_POSIX_SOCKET_HPP__
14 #define __STOUT_OS_POSIX_SOCKET_HPP__
15 
16 #include <array>
17 
18 #include <errno.h>
19 #include <unistd.h>
20 
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 
24 #include <stout/error.hpp>
25 #include <stout/nothing.hpp>
26 #include <stout/try.hpp>
27 
28 #include <stout/os/int_fd.hpp>
29 #include <stout/os/fcntl.hpp>
30 
31 namespace net {
32 
33 // Import `socket` functions into `net::` namespace.
39 
40 
41 // Returns a socket file descriptor for the specified options.
42 // NOTE: on OS X, the returned socket will have the SO_NOSIGPIPE option set.
43 inline Try<int_fd> socket(int family, int type, int protocol)
44 {
45  int_fd s;
46  if ((s = ::socket(family, type, protocol)) < 0) {
47  return ErrnoError();
48  }
49 
50 #ifdef __APPLE__
51  // Disable SIGPIPE via setsockopt because OS X does not support
52  // the MSG_NOSIGNAL flag on send(2).
53  const int enable = 1;
54  if (setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &enable, sizeof(int)) == -1) {
55  return ErrnoError();
56  }
57 #endif // __APPLE__
58 
59  return s;
60 }
61 
62 
63 // The error indicates the last socket operation has been
64 // interupted, the operation can be restarted immediately.
65 inline bool is_restartable_error(int error)
66 {
67  return (error == EINTR);
68 }
69 
70 
71 // The error indicates the last socket function on a non-blocking socket
72 // cannot be completed. This is a temporary condition and the caller can
73 // retry the operation later.
74 inline bool is_retryable_error(int error)
75 {
76  return (error == EWOULDBLOCK || error == EAGAIN);
77 }
78 
79 
80 inline bool is_inprogress_error(int error)
81 {
82  return (error == EINPROGRESS);
83 }
84 
85 
86 inline bool is_socket(int fd)
87 {
88  struct stat statbuf;
89  if (::fstat(fd, &statbuf) < 0) {
90  return false;
91  }
92 
93  return S_ISSOCK(statbuf.st_mode) != 0;
94 }
95 
96 
97 inline Try<std::array<int_fd, 2>> socketpair(int family, int type, int protocol)
98 {
99  std::array<int_fd, 2> result;
100 
101 #if __APPLE__ || !defined(SOCK_CLOEXEC)
102  auto close = [](const std::array<int_fd, 2>& fds) {
103  int errsav = errno;
104  ::close(fds[0]);
105  ::close(fds[1]);
106  errno = errsav;
107  };
108 #endif
109 
110 #if defined(SOCK_CLOEXEC)
111  type |= SOCK_CLOEXEC;
112 #endif
113 
114  if (::socketpair(family, type, 0, result.data()) != 0) {
115  return ErrnoError();
116  }
117 
118 #if !defined(SOCK_CLOEXEC)
120 
121  cloexec = os::cloexec(result[0]);
122  if (cloexec.isError()) {
123  close(result);
124  return Error("Failed to cloexec socket: " + cloexec.error());
125  }
126 
127  cloexec = os::cloexec(result[1]);
128  if (cloexec.isError()) {
129  close(result);
130  return Error("Failed to cloexec socket: " + cloexec.error());
131  }
132 #endif
133 
134 #ifdef __APPLE__
135  // Disable SIGPIPE to be consistent with net::socket().
136  const int enable = 1;
137 
138  if (::setsockopt(
139  result[0],
140  SOL_SOCKET,
141  SO_NOSIGPIPE,
142  &enable,
143  sizeof(enable)) == -1) {
144  close(result);
145  return ErrnoError("Failed to clear sigpipe");
146  }
147 
148  if (::setsockopt(
149  result[1],
150  SOL_SOCKET,
151  SO_NOSIGPIPE,
152  &enable,
153  sizeof(enable)) == -1) {
154  close(result);
155  return ErrnoError("Failed to clear sigpipe");
156  }
157 #endif // __APPLE__
158 
159  return result;
160 }
161 
162 } // namespace net {
163 
164 #endif // __STOUT_OS_POSIX_SOCKET_HPP__
Try< int_fd > socket(int family, int type, int protocol)
Definition: socket.hpp:43
Definition: nothing.hpp:16
bool is_socket(int fd)
Definition: socket.hpp:86
Definition: errorbase.hpp:36
Try< Nothing > enable(const std::string &hierarchy, const std::string &cgroup)
Definition: check.hpp:33
bool is_inprogress_error(int error)
Definition: socket.hpp:80
bool S_ISSOCK(const int mode)
Definition: windows.hpp:230
Definition: errorbase.hpp:50
int bind(const int_fd &fd, const sockaddr *addr, socklen_t addrlen)
Definition: socket.hpp:143
Try< Nothing > cloexec(const InputFileDescriptors &stdinfds, const OutputFileDescriptors &stdoutfds, const OutputFileDescriptors &stderrfds)
Definition: subprocess.hpp:186
Try< std::array< int_fd, 2 > > socketpair(int family, int type, int protocol)
Definition: socket.hpp:97
int_fd accept(const int_fd &fd, sockaddr *addr, socklen_t *addrlen)
Definition: socket.hpp:132
bool is_restartable_error(int error)
Definition: socket.hpp:65
ssize_t send(const int_fd &fd, const void *buf, size_t len, int flags)
Definition: socket.hpp:159
Try< Nothing > cloexec(int fd)
Definition: fcntl.hpp:27
Definition: ip.hpp:70
ssize_t recv(const int_fd &fd, void *buf, size_t len, int flags)
Definition: socket.hpp:168
Try< hashmap< std::string, uint64_t > > stat(const std::string &hierarchy, const std::string &cgroup, const std::string &file)
static Try error(const E &e)
Definition: try.hpp:43
bool isError() const
Definition: try.hpp:78
std::string error(const std::string &msg, uint32_t code)
Try< uint32_t > type(const std::string &path)
int connect(const int_fd &fd, const sockaddr *address, socklen_t addrlen)
Definition: socket.hpp:151
int int_fd
Definition: int_fd.hpp:35
bool is_retryable_error(int error)
Definition: socket.hpp:74