1c6290174STrond Norbye/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2c6290174STrond Norbye/*
3c6290174STrond Norbye *     Copyright 2017 Couchbase, Inc.
4c6290174STrond Norbye *
5c6290174STrond Norbye *   Licensed under the Apache License, Version 2.0 (the "License");
6c6290174STrond Norbye *   you may not use this file except in compliance with the License.
7c6290174STrond Norbye *   You may obtain a copy of the License at
8c6290174STrond Norbye *
9c6290174STrond Norbye *       http://www.apache.org/licenses/LICENSE-2.0
10c6290174STrond Norbye *
11c6290174STrond Norbye *   Unless required by applicable law or agreed to in writing, software
12c6290174STrond Norbye *   distributed under the License is distributed on an "AS IS" BASIS,
13c6290174STrond Norbye *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14c6290174STrond Norbye *   See the License for the specific language governing permissions and
15c6290174STrond Norbye *   limitations under the License.
16c6290174STrond Norbye */
17c6290174STrond Norbye
18efea6ba7SBen Huddleston#include <platform/platform_socket.h>
19c6290174STrond Norbye#include <platform/socket.h>
20c6290174STrond Norbye
21c29955eaSTrond Norbye#include <event2/util.h>
22c29955eaSTrond Norbye
23c29955eaSTrond Norbye#include <cerrno>
24341d07b5STrond Norbye#include <gsl/gsl>
25c6290174STrond Norbye
26c6290174STrond Norbye#ifndef WIN32
27c6290174STrond Norbye#include <netdb.h>
2811d8eb5fSTrond Norbye#include <unistd.h>
29c6290174STrond Norbye#endif
30c6290174STrond Norbye
31c6290174STrond Norbyenamespace cb {
32c6290174STrond Norbyenamespace net {
33c6290174STrond Norbye
34c6290174STrond NorbyeCBSOCKET_PUBLIC_API
35c6290174STrond Norbyeint closesocket(SOCKET s) {
36c29955eaSTrond Norbye#ifdef WIN32
37c29955eaSTrond Norbye    return ::closesocket(s);
38c29955eaSTrond Norbye#else
39c29955eaSTrond Norbye    return ::close(s);
40c29955eaSTrond Norbye#endif
41c29955eaSTrond Norbye
42c6290174STrond Norbye}
43c6290174STrond Norbye
44c6290174STrond NorbyeCBSOCKET_PUBLIC_API
45c6290174STrond Norbyeint get_socket_error() {
46c6290174STrond Norbye#ifdef WIN32
47c6290174STrond Norbye    return WSAGetLastError();
48c6290174STrond Norbye#else
49c6290174STrond Norbye    return errno;
50c6290174STrond Norbye#endif
51c6290174STrond Norbye}
52c6290174STrond Norbye
53c6290174STrond NorbyeCBSOCKET_PUBLIC_API
54c6290174STrond Norbyeint bind(SOCKET sock, const struct sockaddr* name, socklen_t namelen) {
55c6290174STrond Norbye    return ::bind(sock, name, namelen);
56c6290174STrond Norbye}
57c6290174STrond Norbye
5811d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
5911d8eb5fSTrond Norbyeint listen(SOCKET sock, int backlog) {
6011d8eb5fSTrond Norbye    return ::listen(sock, backlog);
6111d8eb5fSTrond Norbye}
6211d8eb5fSTrond Norbye
6311d8eb5fSTrond Norbye
64c6290174STrond NorbyeCBSOCKET_PUBLIC_API
65c6290174STrond NorbyeSOCKET accept(SOCKET sock, struct sockaddr* addr, socklen_t* addrlen) {
66341d07b5STrond Norbye    return ::accept(sock, addr, addrlen);
67c6290174STrond Norbye}
68c6290174STrond Norbye
69c6290174STrond NorbyeCBSOCKET_PUBLIC_API
700f8ec9fbSTim Bradgateint connect(SOCKET sock, const struct sockaddr* name, size_t namelen) {
71341d07b5STrond Norbye#ifdef WIN32
72341d07b5STrond Norbye    return ::connect(sock, name, gsl::narrow<int>(namelen));
73341d07b5STrond Norbye#else
740f8ec9fbSTim Bradgate    return ::connect(sock, name, gsl::narrow<socklen_t>(namelen));
75341d07b5STrond Norbye#endif
76c6290174STrond Norbye}
77c6290174STrond Norbye
78c6290174STrond NorbyeCBSOCKET_PUBLIC_API
79c6290174STrond NorbyeSOCKET socket(int domain, int type, int protocol) {
80341d07b5STrond Norbye    return ::socket(domain, type, protocol);
81c6290174STrond Norbye}
82c6290174STrond Norbye
83c6290174STrond NorbyeCBSOCKET_PUBLIC_API
84c6290174STrond Norbyeint shutdown(SOCKET sock, int how) {
85c6290174STrond Norbye    return ::shutdown(sock, how);
86c6290174STrond Norbye}
87c6290174STrond Norbye
88c6290174STrond NorbyeCBSOCKET_PUBLIC_API
89c6290174STrond Norbyessize_t send(SOCKET sock, const void* buffer, size_t length, int flags) {
90c6290174STrond Norbye#ifdef WIN32
91ba000bbfSTim Bradgate    return ::send(sock, static_cast<const char*>(buffer), gsl::narrow<int>(length), flags);
92c6290174STrond Norbye#else
93341d07b5STrond Norbye    return ::send(sock, buffer, length, flags);
94c6290174STrond Norbye#endif
95c6290174STrond Norbye}
96c6290174STrond Norbye
97c6290174STrond NorbyeCBSOCKET_PUBLIC_API
98c6290174STrond Norbyessize_t sendmsg(SOCKET sock, const struct msghdr* message, int flags) {
99c6290174STrond Norbye    return ::sendmsg(sock, message, flags);
100c6290174STrond Norbye}
101c6290174STrond Norbye
102c6290174STrond NorbyeCBSOCKET_PUBLIC_API
103c6290174STrond Norbyessize_t sendto(SOCKET sock,
104c6290174STrond Norbye               const void* buffer,
105c6290174STrond Norbye               size_t length,
106c6290174STrond Norbye               int flags,
107c6290174STrond Norbye               const struct sockaddr* dest_addr,
108c6290174STrond Norbye               socklen_t dest_len) {
109c6290174STrond Norbye#ifdef WIN32
110c6290174STrond Norbye    return ::sendto(sock,
111c6290174STrond Norbye                    static_cast<const char*>(buffer),
112c6290174STrond Norbye                    int(length),
113c6290174STrond Norbye                    flags,
114c6290174STrond Norbye                    dest_addr,
115c6290174STrond Norbye                    dest_len);
116c6290174STrond Norbye#else
117c6290174STrond Norbye    return ::sendto(sock, buffer, length, flags, dest_addr, dest_len);
118c6290174STrond Norbye#endif
119c6290174STrond Norbye}
120c6290174STrond Norbye
121c6290174STrond NorbyeCBSOCKET_PUBLIC_API
122c6290174STrond Norbyessize_t recv(SOCKET sock, void* buffer, size_t length, int flags) {
123c6290174STrond Norbye#ifdef WIN32
124ba000bbfSTim Bradgate    return ::recv(sock, static_cast<char*>(buffer), gsl::narrow<int>(length), flags);
125c6290174STrond Norbye#else
126341d07b5STrond Norbye    return ::recv(sock, buffer, length, flags);
127c6290174STrond Norbye#endif
128c6290174STrond Norbye}
129c6290174STrond Norbye
130c6290174STrond NorbyeCBSOCKET_PUBLIC_API
131c6290174STrond Norbyessize_t recvfrom(SOCKET sock,
132c6290174STrond Norbye                 void* buffer,
133c6290174STrond Norbye                 size_t length,
134c6290174STrond Norbye                 int flags,
135c6290174STrond Norbye                 struct sockaddr* address,
136c6290174STrond Norbye                 socklen_t* address_len) {
137c6290174STrond Norbye#ifdef WIN32
138c6290174STrond Norbye    return ::recvfrom(sock,
139c6290174STrond Norbye                      static_cast<char*>(buffer),
140c6290174STrond Norbye                      int(length),
141c6290174STrond Norbye                      flags,
142c6290174STrond Norbye                      address,
143c6290174STrond Norbye                      address_len);
144c6290174STrond Norbye#else
145c6290174STrond Norbye    return ::recvfrom(sock, buffer, length, flags, address, address_len);
146c6290174STrond Norbye#endif
147c6290174STrond Norbye}
148c6290174STrond Norbye
149c6290174STrond NorbyeCBSOCKET_PUBLIC_API
150c6290174STrond Norbyessize_t recvmsg(SOCKET sock, struct msghdr* message, int flags) {
151341d07b5STrond Norbye#ifdef WIN32
152341d07b5STrond Norbye    int res = 0;
153341d07b5STrond Norbye    for (size_t ii = 0; ii < size_t(message->msg_iovlen); ii++) {
154341d07b5STrond Norbye        auto nr = cb::net::recv(sock,
155341d07b5STrond Norbye                                message->msg_iov[ii].iov_base,
156341d07b5STrond Norbye                                message->msg_iov[ii].iov_len,
157341d07b5STrond Norbye                                0);
158341d07b5STrond Norbye        if (nr == -1) {
159341d07b5STrond Norbye            return (res == 0) ? -1 : res;
160c6290174STrond Norbye        }
161c6290174STrond Norbye
162341d07b5STrond Norbye        res += nr;
163c6290174STrond Norbye    }
164c6290174STrond Norbye
165341d07b5STrond Norbye    return res;
166c6290174STrond Norbye#else
167c6290174STrond Norbye    return ::recvmsg(sock, message, flags);
168c6290174STrond Norbye#endif
169c6290174STrond Norbye}
170c6290174STrond Norbye
171c29955eaSTrond NorbyeCBSOCKET_PUBLIC_API
172c29955eaSTrond Norbyeint socketpair(int domain, int type, int protocol, SOCKET socket_vector[2]) {
173341d07b5STrond Norbye    return evutil_socketpair(domain,
174341d07b5STrond Norbye                             type,
175341d07b5STrond Norbye                             protocol,
176341d07b5STrond Norbye                             reinterpret_cast<evutil_socket_t*>(socket_vector));
177c29955eaSTrond Norbye}
178c29955eaSTrond Norbye
17911d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
18011d8eb5fSTrond Norbyeint getsockopt(SOCKET sock,
18111d8eb5fSTrond Norbye               int level,
18211d8eb5fSTrond Norbye               int option_name,
18311d8eb5fSTrond Norbye               void* option_value,
18411d8eb5fSTrond Norbye               socklen_t* option_len) {
18511d8eb5fSTrond Norbye#ifdef WIN32
18611d8eb5fSTrond Norbye    return ::getsockopt(sock,
18711d8eb5fSTrond Norbye                        level,
18811d8eb5fSTrond Norbye                        option_name,
18911d8eb5fSTrond Norbye                        reinterpret_cast<char*>(option_value),
19011d8eb5fSTrond Norbye                        option_len);
19111d8eb5fSTrond Norbye#else
19211d8eb5fSTrond Norbye    return ::getsockopt(sock, level, option_name, option_value, option_len);
19311d8eb5fSTrond Norbye#endif
19411d8eb5fSTrond Norbye}
19511d8eb5fSTrond Norbye
19611d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
19711d8eb5fSTrond Norbyeint setsockopt(SOCKET sock,
19811d8eb5fSTrond Norbye               int level,
19911d8eb5fSTrond Norbye               int option_name,
20011d8eb5fSTrond Norbye               const void* option_value,
20111d8eb5fSTrond Norbye               socklen_t option_len) {
20211d8eb5fSTrond Norbye#ifdef WIN32
20311d8eb5fSTrond Norbye    return ::setsockopt(sock,
20411d8eb5fSTrond Norbye                        level,
20511d8eb5fSTrond Norbye                        option_name,
20611d8eb5fSTrond Norbye                        reinterpret_cast<const char*>(option_value),
20711d8eb5fSTrond Norbye                        option_len);
20811d8eb5fSTrond Norbye#else
20911d8eb5fSTrond Norbye    return ::setsockopt(sock, level, option_name, option_value, option_len);
21011d8eb5fSTrond Norbye#endif
21111d8eb5fSTrond Norbye}
21211d8eb5fSTrond Norbye
213c29955eaSTrond NorbyeCBSOCKET_PUBLIC_API
214c29955eaSTrond Norbyeint set_socket_noblocking(SOCKET sock) {
215c29955eaSTrond Norbye    return evutil_make_socket_nonblocking(sock);
216c29955eaSTrond Norbye}
217c29955eaSTrond Norbye
218f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
219f4e59c82STrond Norbyestd::string to_string(const struct sockaddr_storage* addr, socklen_t addr_len) {
220f4e59c82STrond Norbye    char host[50];
221f4e59c82STrond Norbye    char port[50];
222f4e59c82STrond Norbye
223f4e59c82STrond Norbye    int err = getnameinfo(reinterpret_cast<const struct sockaddr*>(addr),
224f4e59c82STrond Norbye                          addr_len,
225f4e59c82STrond Norbye                          host,
226f4e59c82STrond Norbye                          sizeof(host),
227f4e59c82STrond Norbye                          port,
228f4e59c82STrond Norbye                          sizeof(port),
229f4e59c82STrond Norbye                          NI_NUMERICHOST | NI_NUMERICSERV);
230f4e59c82STrond Norbye    if (err != 0) {
231f4e59c82STrond Norbye        throw std::runtime_error(
232f4e59c82STrond Norbye                "cb::net::to_string: getnameinfo() failed with error: " +
233f4e59c82STrond Norbye                std::to_string(err));
234f4e59c82STrond Norbye    }
235f4e59c82STrond Norbye
236f4e59c82STrond Norbye    if (addr->ss_family == AF_INET6) {
237f4e59c82STrond Norbye        return "[" + std::string(host) + "]:" + std::string(port);
238f4e59c82STrond Norbye    } else {
239f4e59c82STrond Norbye        return std::string(host) + ":" + std::string(port);
240f4e59c82STrond Norbye    }
241f4e59c82STrond Norbye}
242f4e59c82STrond Norbye
243f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
244f4e59c82STrond Norbyestd::string getsockname(SOCKET sfd) {
245f4e59c82STrond Norbye    sockaddr_storage sock{};
246f4e59c82STrond Norbye    socklen_t sock_len = sizeof(sock);
247f4e59c82STrond Norbye    if (::getsockname(sfd,
248f4e59c82STrond Norbye                      reinterpret_cast<struct sockaddr*>(&sock),
249f4e59c82STrond Norbye                      &sock_len) != 0) {
250f4e59c82STrond Norbye        throw std::system_error(cb::net::get_socket_error(),
251f4e59c82STrond Norbye                                std::system_category(),
252f4e59c82STrond Norbye                                "getsockname() failed");
253f4e59c82STrond Norbye    }
254f4e59c82STrond Norbye    return to_string(&sock, sock_len);
255f4e59c82STrond Norbye}
256f4e59c82STrond Norbye
257f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
258f4e59c82STrond Norbyestd::string getpeername(SOCKET sfd) {
259f4e59c82STrond Norbye    sockaddr_storage peer;
260f4e59c82STrond Norbye    socklen_t peer_len = sizeof(peer);
261f4e59c82STrond Norbye    if (getpeername(sfd,
262f4e59c82STrond Norbye                    reinterpret_cast<struct sockaddr*>(&peer),
263f4e59c82STrond Norbye                    &peer_len) != 0) {
264f4e59c82STrond Norbye        throw std::system_error(cb::net::get_socket_error(),
265f4e59c82STrond Norbye                                std::system_category(),
266f4e59c82STrond Norbye                                "getpeername() failed");
267f4e59c82STrond Norbye    }
268f4e59c82STrond Norbye    return to_string(&peer, peer_len);
269f4e59c82STrond Norbye}
270f4e59c82STrond Norbye
271c6290174STrond Norbye} // namespace net
272c6290174STrond Norbye} // namespace cb
273