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
18c6290174STrond Norbye#include <platform/socket.h>
19c6290174STrond Norbye
20c29955eaSTrond Norbye#include <event2/util.h>
21c29955eaSTrond Norbye
22c29955eaSTrond Norbye#include <cerrno>
23341d07b5STrond Norbye#include <gsl/gsl>
24c6290174STrond Norbye
25c6290174STrond Norbye#ifndef WIN32
26c6290174STrond Norbye#include <netdb.h>
2711d8eb5fSTrond Norbye#include <unistd.h>
28c6290174STrond Norbye#endif
29c6290174STrond Norbye
30c6290174STrond Norbyenamespace cb {
31c6290174STrond Norbyenamespace net {
32c6290174STrond Norbye
33c6290174STrond NorbyeCBSOCKET_PUBLIC_API
34c6290174STrond Norbyeint closesocket(SOCKET s) {
35c29955eaSTrond Norbye#ifdef WIN32
36c29955eaSTrond Norbye    return ::closesocket(s);
37c29955eaSTrond Norbye#else
38c29955eaSTrond Norbye    return ::close(s);
39c29955eaSTrond Norbye#endif
40c29955eaSTrond Norbye
41c6290174STrond Norbye}
42c6290174STrond Norbye
43c6290174STrond NorbyeCBSOCKET_PUBLIC_API
44c6290174STrond Norbyeint get_socket_error() {
45c6290174STrond Norbye#ifdef WIN32
46c6290174STrond Norbye    return WSAGetLastError();
47c6290174STrond Norbye#else
48c6290174STrond Norbye    return errno;
49c6290174STrond Norbye#endif
50c6290174STrond Norbye}
51c6290174STrond Norbye
52c6290174STrond NorbyeCBSOCKET_PUBLIC_API
53c6290174STrond Norbyeint bind(SOCKET sock, const struct sockaddr* name, socklen_t namelen) {
54c6290174STrond Norbye    return ::bind(sock, name, namelen);
55c6290174STrond Norbye}
56c6290174STrond Norbye
5711d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
5811d8eb5fSTrond Norbyeint listen(SOCKET sock, int backlog) {
5911d8eb5fSTrond Norbye    return ::listen(sock, backlog);
6011d8eb5fSTrond Norbye}
6111d8eb5fSTrond Norbye
6211d8eb5fSTrond Norbye
63c6290174STrond NorbyeCBSOCKET_PUBLIC_API
64c6290174STrond NorbyeSOCKET accept(SOCKET sock, struct sockaddr* addr, socklen_t* addrlen) {
65341d07b5STrond Norbye    return ::accept(sock, addr, addrlen);
66c6290174STrond Norbye}
67c6290174STrond Norbye
68c6290174STrond NorbyeCBSOCKET_PUBLIC_API
690f8ec9fbSTim Bradgateint connect(SOCKET sock, const struct sockaddr* name, size_t namelen) {
70341d07b5STrond Norbye#ifdef WIN32
71341d07b5STrond Norbye    return ::connect(sock, name, gsl::narrow<int>(namelen));
72341d07b5STrond Norbye#else
730f8ec9fbSTim Bradgate    return ::connect(sock, name, gsl::narrow<socklen_t>(namelen));
74341d07b5STrond Norbye#endif
75c6290174STrond Norbye}
76c6290174STrond Norbye
77c6290174STrond NorbyeCBSOCKET_PUBLIC_API
78c6290174STrond NorbyeSOCKET socket(int domain, int type, int protocol) {
79341d07b5STrond Norbye    return ::socket(domain, type, protocol);
80c6290174STrond Norbye}
81c6290174STrond Norbye
82c6290174STrond NorbyeCBSOCKET_PUBLIC_API
83c6290174STrond Norbyeint shutdown(SOCKET sock, int how) {
84c6290174STrond Norbye    return ::shutdown(sock, how);
85c6290174STrond Norbye}
86c6290174STrond Norbye
87c6290174STrond NorbyeCBSOCKET_PUBLIC_API
88c6290174STrond Norbyessize_t send(SOCKET sock, const void* buffer, size_t length, int flags) {
89c6290174STrond Norbye#ifdef WIN32
90ba000bbfSTim Bradgate    return ::send(sock, static_cast<const char*>(buffer), gsl::narrow<int>(length), flags);
91c6290174STrond Norbye#else
92341d07b5STrond Norbye    return ::send(sock, buffer, length, flags);
93c6290174STrond Norbye#endif
94c6290174STrond Norbye}
95c6290174STrond Norbye
96c6290174STrond NorbyeCBSOCKET_PUBLIC_API
97c6290174STrond Norbyessize_t sendmsg(SOCKET sock, const struct msghdr* message, int flags) {
98c6290174STrond Norbye    return ::sendmsg(sock, message, flags);
99c6290174STrond Norbye}
100c6290174STrond Norbye
101c6290174STrond NorbyeCBSOCKET_PUBLIC_API
102c6290174STrond Norbyessize_t sendto(SOCKET sock,
103c6290174STrond Norbye               const void* buffer,
104c6290174STrond Norbye               size_t length,
105c6290174STrond Norbye               int flags,
106c6290174STrond Norbye               const struct sockaddr* dest_addr,
107c6290174STrond Norbye               socklen_t dest_len) {
108c6290174STrond Norbye#ifdef WIN32
109c6290174STrond Norbye    return ::sendto(sock,
110c6290174STrond Norbye                    static_cast<const char*>(buffer),
111c6290174STrond Norbye                    int(length),
112c6290174STrond Norbye                    flags,
113c6290174STrond Norbye                    dest_addr,
114c6290174STrond Norbye                    dest_len);
115c6290174STrond Norbye#else
116c6290174STrond Norbye    return ::sendto(sock, buffer, length, flags, dest_addr, dest_len);
117c6290174STrond Norbye#endif
118c6290174STrond Norbye}
119c6290174STrond Norbye
120c6290174STrond NorbyeCBSOCKET_PUBLIC_API
121c6290174STrond Norbyessize_t recv(SOCKET sock, void* buffer, size_t length, int flags) {
122c6290174STrond Norbye#ifdef WIN32
123ba000bbfSTim Bradgate    return ::recv(sock, static_cast<char*>(buffer), gsl::narrow<int>(length), flags);
124c6290174STrond Norbye#else
125341d07b5STrond Norbye    return ::recv(sock, buffer, length, flags);
126c6290174STrond Norbye#endif
127c6290174STrond Norbye}
128c6290174STrond Norbye
129c6290174STrond NorbyeCBSOCKET_PUBLIC_API
130c6290174STrond Norbyessize_t recvfrom(SOCKET sock,
131c6290174STrond Norbye                 void* buffer,
132c6290174STrond Norbye                 size_t length,
133c6290174STrond Norbye                 int flags,
134c6290174STrond Norbye                 struct sockaddr* address,
135c6290174STrond Norbye                 socklen_t* address_len) {
136c6290174STrond Norbye#ifdef WIN32
137c6290174STrond Norbye    return ::recvfrom(sock,
138c6290174STrond Norbye                      static_cast<char*>(buffer),
139c6290174STrond Norbye                      int(length),
140c6290174STrond Norbye                      flags,
141c6290174STrond Norbye                      address,
142c6290174STrond Norbye                      address_len);
143c6290174STrond Norbye#else
144c6290174STrond Norbye    return ::recvfrom(sock, buffer, length, flags, address, address_len);
145c6290174STrond Norbye#endif
146c6290174STrond Norbye}
147c6290174STrond Norbye
148c6290174STrond NorbyeCBSOCKET_PUBLIC_API
149c6290174STrond Norbyessize_t recvmsg(SOCKET sock, struct msghdr* message, int flags) {
150341d07b5STrond Norbye#ifdef WIN32
151341d07b5STrond Norbye    int res = 0;
152341d07b5STrond Norbye    for (size_t ii = 0; ii < size_t(message->msg_iovlen); ii++) {
153341d07b5STrond Norbye        auto nr = cb::net::recv(sock,
154341d07b5STrond Norbye                                message->msg_iov[ii].iov_base,
155341d07b5STrond Norbye                                message->msg_iov[ii].iov_len,
156341d07b5STrond Norbye                                0);
157341d07b5STrond Norbye        if (nr == -1) {
158341d07b5STrond Norbye            return (res == 0) ? -1 : res;
159c6290174STrond Norbye        }
160c6290174STrond Norbye
161341d07b5STrond Norbye        res += nr;
162c6290174STrond Norbye    }
163c6290174STrond Norbye
164341d07b5STrond Norbye    return res;
165c6290174STrond Norbye#else
166c6290174STrond Norbye    return ::recvmsg(sock, message, flags);
167c6290174STrond Norbye#endif
168c6290174STrond Norbye}
169c6290174STrond Norbye
170c29955eaSTrond NorbyeCBSOCKET_PUBLIC_API
171c29955eaSTrond Norbyeint socketpair(int domain, int type, int protocol, SOCKET socket_vector[2]) {
172341d07b5STrond Norbye    return evutil_socketpair(domain,
173341d07b5STrond Norbye                             type,
174341d07b5STrond Norbye                             protocol,
175341d07b5STrond Norbye                             reinterpret_cast<evutil_socket_t*>(socket_vector));
176c29955eaSTrond Norbye}
177c29955eaSTrond Norbye
17811d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
17911d8eb5fSTrond Norbyeint getsockopt(SOCKET sock,
18011d8eb5fSTrond Norbye               int level,
18111d8eb5fSTrond Norbye               int option_name,
18211d8eb5fSTrond Norbye               void* option_value,
18311d8eb5fSTrond Norbye               socklen_t* option_len) {
18411d8eb5fSTrond Norbye#ifdef WIN32
18511d8eb5fSTrond Norbye    return ::getsockopt(sock,
18611d8eb5fSTrond Norbye                        level,
18711d8eb5fSTrond Norbye                        option_name,
18811d8eb5fSTrond Norbye                        reinterpret_cast<char*>(option_value),
18911d8eb5fSTrond Norbye                        option_len);
19011d8eb5fSTrond Norbye#else
19111d8eb5fSTrond Norbye    return ::getsockopt(sock, level, option_name, option_value, option_len);
19211d8eb5fSTrond Norbye#endif
19311d8eb5fSTrond Norbye}
19411d8eb5fSTrond Norbye
19511d8eb5fSTrond NorbyeCBSOCKET_PUBLIC_API
19611d8eb5fSTrond Norbyeint setsockopt(SOCKET sock,
19711d8eb5fSTrond Norbye               int level,
19811d8eb5fSTrond Norbye               int option_name,
19911d8eb5fSTrond Norbye               const void* option_value,
20011d8eb5fSTrond Norbye               socklen_t option_len) {
20111d8eb5fSTrond Norbye#ifdef WIN32
20211d8eb5fSTrond Norbye    return ::setsockopt(sock,
20311d8eb5fSTrond Norbye                        level,
20411d8eb5fSTrond Norbye                        option_name,
20511d8eb5fSTrond Norbye                        reinterpret_cast<const char*>(option_value),
20611d8eb5fSTrond Norbye                        option_len);
20711d8eb5fSTrond Norbye#else
20811d8eb5fSTrond Norbye    return ::setsockopt(sock, level, option_name, option_value, option_len);
20911d8eb5fSTrond Norbye#endif
21011d8eb5fSTrond Norbye}
21111d8eb5fSTrond Norbye
212c29955eaSTrond NorbyeCBSOCKET_PUBLIC_API
213c29955eaSTrond Norbyeint set_socket_noblocking(SOCKET sock) {
214c29955eaSTrond Norbye    return evutil_make_socket_nonblocking(sock);
215c29955eaSTrond Norbye}
216c29955eaSTrond Norbye
217f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
218f4e59c82STrond Norbyestd::string to_string(const struct sockaddr_storage* addr, socklen_t addr_len) {
219f4e59c82STrond Norbye    char host[50];
220f4e59c82STrond Norbye    char port[50];
221f4e59c82STrond Norbye
222f4e59c82STrond Norbye    int err = getnameinfo(reinterpret_cast<const struct sockaddr*>(addr),
223f4e59c82STrond Norbye                          addr_len,
224f4e59c82STrond Norbye                          host,
225f4e59c82STrond Norbye                          sizeof(host),
226f4e59c82STrond Norbye                          port,
227f4e59c82STrond Norbye                          sizeof(port),
228f4e59c82STrond Norbye                          NI_NUMERICHOST | NI_NUMERICSERV);
229f4e59c82STrond Norbye    if (err != 0) {
230f4e59c82STrond Norbye        throw std::runtime_error(
231f4e59c82STrond Norbye                "cb::net::to_string: getnameinfo() failed with error: " +
232f4e59c82STrond Norbye                std::to_string(err));
233f4e59c82STrond Norbye    }
234f4e59c82STrond Norbye
235f4e59c82STrond Norbye    if (addr->ss_family == AF_INET6) {
236f4e59c82STrond Norbye        return "[" + std::string(host) + "]:" + std::string(port);
237f4e59c82STrond Norbye    } else {
238f4e59c82STrond Norbye        return std::string(host) + ":" + std::string(port);
239f4e59c82STrond Norbye    }
240f4e59c82STrond Norbye}
241f4e59c82STrond Norbye
242f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
243f4e59c82STrond Norbyestd::string getsockname(SOCKET sfd) {
244f4e59c82STrond Norbye    sockaddr_storage sock{};
245f4e59c82STrond Norbye    socklen_t sock_len = sizeof(sock);
246f4e59c82STrond Norbye    if (::getsockname(sfd,
247f4e59c82STrond Norbye                      reinterpret_cast<struct sockaddr*>(&sock),
248f4e59c82STrond Norbye                      &sock_len) != 0) {
249f4e59c82STrond Norbye        throw std::system_error(cb::net::get_socket_error(),
250f4e59c82STrond Norbye                                std::system_category(),
251f4e59c82STrond Norbye                                "getsockname() failed");
252f4e59c82STrond Norbye    }
253f4e59c82STrond Norbye    return to_string(&sock, sock_len);
254f4e59c82STrond Norbye}
255f4e59c82STrond Norbye
256f4e59c82STrond NorbyeCBSOCKET_PUBLIC_API
257f4e59c82STrond Norbyestd::string getpeername(SOCKET sfd) {
258f4e59c82STrond Norbye    sockaddr_storage peer;
259f4e59c82STrond Norbye    socklen_t peer_len = sizeof(peer);
260f4e59c82STrond Norbye    if (getpeername(sfd,
261f4e59c82STrond Norbye                    reinterpret_cast<struct sockaddr*>(&peer),
262f4e59c82STrond Norbye                    &peer_len) != 0) {
263f4e59c82STrond Norbye        throw std::system_error(cb::net::get_socket_error(),
264f4e59c82STrond Norbye                                std::system_category(),
265f4e59c82STrond Norbye                                "getpeername() failed");
266f4e59c82STrond Norbye    }
267f4e59c82STrond Norbye    return to_string(&peer, peer_len);
268f4e59c82STrond Norbye}
269f4e59c82STrond Norbye
270c6290174STrond Norbye} // namespace net
271c6290174STrond Norbye} // namespace cb
272