]> git.proxmox.com Git - ceph.git/blame - ceph/src/msg/async/net_handler.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / msg / async / net_handler.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2014 UnitedStack <haomai@unitedstack.com>
7 *
8 * Author: Haomai Wang <haomaiwang@gmail.com>
9 *
10 * This is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License version 2.1, as published by the Free Software
13 * Foundation. See file COPYING.
14 *
15 */
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <netinet/ip.h>
21#include <netinet/tcp.h>
22#include <arpa/inet.h>
23
24#include "net_handler.h"
7c673cae 25#include "common/debug.h"
91327a77
AA
26#include "common/errno.h"
27#include "include/compat.h"
28#include "include/sock_compat.h"
7c673cae
FG
29
30#define dout_subsys ceph_subsys_ms
31#undef dout_prefix
32#define dout_prefix *_dout << "NetHandler "
33
34namespace ceph{
35
36int NetHandler::create_socket(int domain, bool reuse_addr)
37{
38 int s;
39 int r = 0;
40
91327a77 41 if ((s = socket_cloexec(domain, SOCK_STREAM, 0)) == -1) {
f67539c2 42 r = ceph_sock_errno();
7c673cae
FG
43 lderr(cct) << __func__ << " couldn't create socket " << cpp_strerror(r) << dendl;
44 return -r;
45 }
46
47#if !defined(__FreeBSD__)
48 /* Make sure connection-intensive things like the benchmark
49 * will be able to close/open sockets a zillion of times */
50 if (reuse_addr) {
51 int on = 1;
f67539c2
TL
52 if (::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (SOCKOPT_VAL_TYPE)&on, sizeof(on)) == -1) {
53 r = ceph_sock_errno();
7c673cae
FG
54 lderr(cct) << __func__ << " setsockopt SO_REUSEADDR failed: "
55 << strerror(r) << dendl;
f67539c2 56 compat_closesocket(s);
7c673cae
FG
57 return -r;
58 }
59 }
60#endif
61
62 return s;
63}
64
65int NetHandler::set_nonblock(int sd)
66{
67 int flags;
68 int r = 0;
69
f67539c2
TL
70 #ifdef _WIN32
71 ULONG mode = 1;
72 r = ioctlsocket(sd, FIONBIO, &mode);
73 if (r) {
74 lderr(cct) << __func__ << " ioctlsocket(FIONBIO) failed: " << r
75 << " " << WSAGetLastError() << dendl;
76 return -r;
77 }
78 #else
7c673cae
FG
79 /* Set the socket nonblocking.
80 * Note that fcntl(2) for F_GETFL and F_SETFL can't be
81 * interrupted by a signal. */
82 if ((flags = fcntl(sd, F_GETFL)) < 0 ) {
f67539c2 83 r = ceph_sock_errno();
7c673cae
FG
84 lderr(cct) << __func__ << " fcntl(F_GETFL) failed: " << cpp_strerror(r) << dendl;
85 return -r;
86 }
87 if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0) {
f67539c2 88 r = ceph_sock_errno();
7c673cae
FG
89 lderr(cct) << __func__ << " fcntl(F_SETFL,O_NONBLOCK): " << cpp_strerror(r) << dendl;
90 return -r;
91 }
f67539c2 92 #endif
7c673cae
FG
93
94 return 0;
95}
96
7c673cae
FG
97int NetHandler::set_socket_options(int sd, bool nodelay, int size)
98{
99 int r = 0;
100 // disable Nagle algorithm?
101 if (nodelay) {
102 int flag = 1;
f67539c2 103 r = ::setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (SOCKOPT_VAL_TYPE)&flag, sizeof(flag));
7c673cae 104 if (r < 0) {
f67539c2 105 r = ceph_sock_errno();
7c673cae
FG
106 ldout(cct, 0) << "couldn't set TCP_NODELAY: " << cpp_strerror(r) << dendl;
107 }
108 }
109 if (size) {
f67539c2 110 r = ::setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (SOCKOPT_VAL_TYPE)&size, sizeof(size));
7c673cae 111 if (r < 0) {
f67539c2 112 r = ceph_sock_errno();
7c673cae
FG
113 ldout(cct, 0) << "couldn't set SO_RCVBUF to " << size << ": " << cpp_strerror(r) << dendl;
114 }
115 }
116
117 // block ESIGPIPE
3efd9988 118#ifdef CEPH_USE_SO_NOSIGPIPE
7c673cae 119 int val = 1;
f67539c2 120 r = ::setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (SOCKOPT_VAL_TYPE)&val, sizeof(val));
7c673cae 121 if (r) {
f67539c2 122 r = ceph_sock_errno();
7c673cae
FG
123 ldout(cct,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r) << dendl;
124 }
125#endif
126 return -r;
127}
128
129void NetHandler::set_priority(int sd, int prio, int domain)
130{
131#ifdef SO_PRIORITY
132 if (prio < 0) {
133 return;
134 }
92f5a8d4 135 int r = -1;
7c673cae
FG
136#ifdef IPTOS_CLASS_CS6
137 int iptos = IPTOS_CLASS_CS6;
7c673cae
FG
138 switch (domain) {
139 case AF_INET:
f67539c2 140 r = ::setsockopt(sd, IPPROTO_IP, IP_TOS, (SOCKOPT_VAL_TYPE)&iptos, sizeof(iptos));
7c673cae
FG
141 break;
142 case AF_INET6:
f67539c2 143 r = ::setsockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, (SOCKOPT_VAL_TYPE)&iptos, sizeof(iptos));
7c673cae
FG
144 break;
145 default:
146 lderr(cct) << "couldn't set ToS of unknown family (" << domain << ")"
147 << " to " << iptos << dendl;
148 return;
149 }
150 if (r < 0) {
f67539c2 151 r = ceph_sock_errno();
7c673cae
FG
152 ldout(cct,0) << "couldn't set TOS to " << iptos
153 << ": " << cpp_strerror(r) << dendl;
154 }
155
156#endif // IPTOS_CLASS_CS6
157 // setsockopt(IPTOS_CLASS_CS6) sets the priority of the socket as 0.
158 // See http://goo.gl/QWhvsD and http://goo.gl/laTbjT
159 // We need to call setsockopt(SO_PRIORITY) after it.
f67539c2 160 r = ::setsockopt(sd, SOL_SOCKET, SO_PRIORITY, (SOCKOPT_VAL_TYPE)&prio, sizeof(prio));
7c673cae 161 if (r < 0) {
f67539c2 162 r = ceph_sock_errno();
7c673cae
FG
163 ldout(cct, 0) << __func__ << " couldn't set SO_PRIORITY to " << prio
164 << ": " << cpp_strerror(r) << dendl;
165 }
166#else
167 return;
168#endif // SO_PRIORITY
169}
170
171int NetHandler::generic_connect(const entity_addr_t& addr, const entity_addr_t &bind_addr, bool nonblock)
172{
173 int ret;
174 int s = create_socket(addr.get_family());
175 if (s < 0)
176 return s;
177
178 if (nonblock) {
179 ret = set_nonblock(s);
180 if (ret < 0) {
f67539c2 181 compat_closesocket(s);
7c673cae
FG
182 return ret;
183 }
184 }
185
186 set_socket_options(s, cct->_conf->ms_tcp_nodelay, cct->_conf->ms_tcp_rcvbuf);
187
188 {
189 entity_addr_t addr = bind_addr;
190 if (cct->_conf->ms_bind_before_connect && (!addr.is_blank_ip())) {
191 addr.set_port(0);
192 ret = ::bind(s, addr.get_sockaddr(), addr.get_sockaddr_len());
193 if (ret < 0) {
f67539c2 194 ret = ceph_sock_errno();
7c673cae 195 ldout(cct, 2) << __func__ << " client bind error " << ", " << cpp_strerror(ret) << dendl;
f67539c2 196 compat_closesocket(s);
7c673cae
FG
197 return -ret;
198 }
199 }
200 }
201
202 ret = ::connect(s, addr.get_sockaddr(), addr.get_sockaddr_len());
203 if (ret < 0) {
f67539c2
TL
204 ret = ceph_sock_errno();
205 // Windows can return WSAEWOULDBLOCK (converted to EAGAIN).
206 if ((ret == EINPROGRESS || ret == EAGAIN) && nonblock)
7c673cae
FG
207 return s;
208
209 ldout(cct, 10) << __func__ << " connect: " << cpp_strerror(ret) << dendl;
f67539c2 210 compat_closesocket(s);
7c673cae
FG
211 return -ret;
212 }
213
214 return s;
215}
216
217int NetHandler::reconnect(const entity_addr_t &addr, int sd)
218{
219 int r = 0;
220 int ret = ::connect(sd, addr.get_sockaddr(), addr.get_sockaddr_len());
221
f67539c2
TL
222 if (ret < 0 && ceph_sock_errno() != EISCONN) {
223 r = ceph_sock_errno();
224 ldout(cct, 10) << __func__ << " reconnect: " << r
225 << " " << strerror(r) << dendl;
226 if (r == EINPROGRESS || r == EALREADY || r == EAGAIN)
7c673cae
FG
227 return 1;
228 return -r;
229 }
230
231 return 0;
232}
233
234int NetHandler::connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
235{
236 return generic_connect(addr, bind_addr, false);
237}
238
239int NetHandler::nonblock_connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
240{
241 return generic_connect(addr, bind_addr, true);
242}
243
244
245}