]> git.proxmox.com Git - ceph.git/blame - ceph/src/msg/async/net_handler.cc
update sources to 12.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"
25#include "common/errno.h"
26#include "common/debug.h"
27
28#define dout_subsys ceph_subsys_ms
29#undef dout_prefix
30#define dout_prefix *_dout << "NetHandler "
31
32namespace ceph{
33
34int NetHandler::create_socket(int domain, bool reuse_addr)
35{
36 int s;
37 int r = 0;
38
39 if ((s = ::socket(domain, SOCK_STREAM, 0)) == -1) {
40 r = errno;
41 lderr(cct) << __func__ << " couldn't create socket " << cpp_strerror(r) << dendl;
42 return -r;
43 }
44
45#if !defined(__FreeBSD__)
46 /* Make sure connection-intensive things like the benchmark
47 * will be able to close/open sockets a zillion of times */
48 if (reuse_addr) {
49 int on = 1;
50 if (::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
51 r = errno;
52 lderr(cct) << __func__ << " setsockopt SO_REUSEADDR failed: "
53 << strerror(r) << dendl;
54 close(s);
55 return -r;
56 }
57 }
58#endif
59
60 return s;
61}
62
63int NetHandler::set_nonblock(int sd)
64{
65 int flags;
66 int r = 0;
67
68 /* Set the socket nonblocking.
69 * Note that fcntl(2) for F_GETFL and F_SETFL can't be
70 * interrupted by a signal. */
71 if ((flags = fcntl(sd, F_GETFL)) < 0 ) {
72 r = errno;
73 lderr(cct) << __func__ << " fcntl(F_GETFL) failed: " << cpp_strerror(r) << dendl;
74 return -r;
75 }
76 if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0) {
77 r = errno;
78 lderr(cct) << __func__ << " fcntl(F_SETFL,O_NONBLOCK): " << cpp_strerror(r) << dendl;
79 return -r;
80 }
81
82 return 0;
83}
84
85void NetHandler::set_close_on_exec(int sd)
86{
87 int flags = fcntl(sd, F_GETFD, 0);
88 if (flags < 0) {
89 int r = errno;
90 lderr(cct) << __func__ << " fcntl(F_GETFD): "
91 << cpp_strerror(r) << dendl;
92 return;
93 }
94 if (fcntl(sd, F_SETFD, flags | FD_CLOEXEC)) {
95 int r = errno;
96 lderr(cct) << __func__ << " fcntl(F_SETFD): "
97 << cpp_strerror(r) << dendl;
98 }
99}
100
101int NetHandler::set_socket_options(int sd, bool nodelay, int size)
102{
103 int r = 0;
104 // disable Nagle algorithm?
105 if (nodelay) {
106 int flag = 1;
107 r = ::setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag));
108 if (r < 0) {
109 r = errno;
110 ldout(cct, 0) << "couldn't set TCP_NODELAY: " << cpp_strerror(r) << dendl;
111 }
112 }
113 if (size) {
114 r = ::setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void*)&size, sizeof(size));
115 if (r < 0) {
116 r = errno;
117 ldout(cct, 0) << "couldn't set SO_RCVBUF to " << size << ": " << cpp_strerror(r) << dendl;
118 }
119 }
120
121 // block ESIGPIPE
3efd9988 122#ifdef CEPH_USE_SO_NOSIGPIPE
7c673cae
FG
123 int val = 1;
124 r = ::setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
125 if (r) {
126 r = errno;
127 ldout(cct,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r) << dendl;
128 }
129#endif
130 return -r;
131}
132
133void NetHandler::set_priority(int sd, int prio, int domain)
134{
135#ifdef SO_PRIORITY
136 if (prio < 0) {
137 return;
138 }
139#ifdef IPTOS_CLASS_CS6
140 int iptos = IPTOS_CLASS_CS6;
141 int r = -1;
142 switch (domain) {
143 case AF_INET:
144 r = ::setsockopt(sd, IPPROTO_IP, IP_TOS, &iptos, sizeof(iptos));
145 break;
146 case AF_INET6:
147 r = ::setsockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, &iptos, sizeof(iptos));
148 break;
149 default:
150 lderr(cct) << "couldn't set ToS of unknown family (" << domain << ")"
151 << " to " << iptos << dendl;
152 return;
153 }
154 if (r < 0) {
155 r = errno;
156 ldout(cct,0) << "couldn't set TOS to " << iptos
157 << ": " << cpp_strerror(r) << dendl;
158 }
159
160#endif // IPTOS_CLASS_CS6
161 // setsockopt(IPTOS_CLASS_CS6) sets the priority of the socket as 0.
162 // See http://goo.gl/QWhvsD and http://goo.gl/laTbjT
163 // We need to call setsockopt(SO_PRIORITY) after it.
164 r = ::setsockopt(sd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio));
165 if (r < 0) {
166 r = errno;
167 ldout(cct, 0) << __func__ << " couldn't set SO_PRIORITY to " << prio
168 << ": " << cpp_strerror(r) << dendl;
169 }
170#else
171 return;
172#endif // SO_PRIORITY
173}
174
175int NetHandler::generic_connect(const entity_addr_t& addr, const entity_addr_t &bind_addr, bool nonblock)
176{
177 int ret;
178 int s = create_socket(addr.get_family());
179 if (s < 0)
180 return s;
181
182 if (nonblock) {
183 ret = set_nonblock(s);
184 if (ret < 0) {
185 close(s);
186 return ret;
187 }
188 }
189
190 set_socket_options(s, cct->_conf->ms_tcp_nodelay, cct->_conf->ms_tcp_rcvbuf);
191
192 {
193 entity_addr_t addr = bind_addr;
194 if (cct->_conf->ms_bind_before_connect && (!addr.is_blank_ip())) {
195 addr.set_port(0);
196 ret = ::bind(s, addr.get_sockaddr(), addr.get_sockaddr_len());
197 if (ret < 0) {
198 ret = errno;
199 ldout(cct, 2) << __func__ << " client bind error " << ", " << cpp_strerror(ret) << dendl;
200 close(s);
201 return -ret;
202 }
203 }
204 }
205
206 ret = ::connect(s, addr.get_sockaddr(), addr.get_sockaddr_len());
207 if (ret < 0) {
208 ret = errno;
209 if (errno == EINPROGRESS && nonblock)
210 return s;
211
212 ldout(cct, 10) << __func__ << " connect: " << cpp_strerror(ret) << dendl;
213 close(s);
214 return -ret;
215 }
216
217 return s;
218}
219
220int NetHandler::reconnect(const entity_addr_t &addr, int sd)
221{
222 int r = 0;
223 int ret = ::connect(sd, addr.get_sockaddr(), addr.get_sockaddr_len());
224
225 if (ret < 0 && errno != EISCONN) {
226 r = errno;
227 ldout(cct, 10) << __func__ << " reconnect: " << strerror(r) << dendl;
228 if (r == EINPROGRESS || r == EALREADY)
229 return 1;
230 return -r;
231 }
232
233 return 0;
234}
235
236int NetHandler::connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
237{
238 return generic_connect(addr, bind_addr, false);
239}
240
241int NetHandler::nonblock_connect(const entity_addr_t &addr, const entity_addr_t& bind_addr)
242{
243 return generic_connect(addr, bind_addr, true);
244}
245
246
247}