]>
git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/net_handler.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2014 UnitedStack <haomai@unitedstack.com>
8 * Author: Haomai Wang <haomaiwang@gmail.com>
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.
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>
24 #include "net_handler.h"
25 #include "common/debug.h"
26 #include "common/errno.h"
27 #include "include/compat.h"
28 #include "include/sock_compat.h"
30 #define dout_subsys ceph_subsys_ms
32 #define dout_prefix *_dout << "NetHandler "
36 int NetHandler::create_socket(int domain
, bool reuse_addr
)
41 if ((s
= socket_cloexec(domain
, SOCK_STREAM
, 0)) == -1) {
42 r
= ceph_sock_errno();
43 lderr(cct
) << __func__
<< " couldn't create socket " << cpp_strerror(r
) << dendl
;
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 */
52 if (::setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, (SOCKOPT_VAL_TYPE
)&on
, sizeof(on
)) == -1) {
53 r
= ceph_sock_errno();
54 lderr(cct
) << __func__
<< " setsockopt SO_REUSEADDR failed: "
55 << strerror(r
) << dendl
;
56 compat_closesocket(s
);
65 int NetHandler::set_nonblock(int sd
)
70 r
= ioctlsocket(sd
, FIONBIO
, &mode
);
72 lderr(cct
) << __func__
<< " ioctlsocket(FIONBIO) failed: " << r
73 << " " << WSAGetLastError() << dendl
;
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 ) {
83 r
= ceph_sock_errno();
84 lderr(cct
) << __func__
<< " fcntl(F_GETFL) failed: " << cpp_strerror(r
) << dendl
;
87 if (fcntl(sd
, F_SETFL
, flags
| O_NONBLOCK
) < 0) {
88 r
= ceph_sock_errno();
89 lderr(cct
) << __func__
<< " fcntl(F_SETFL,O_NONBLOCK): " << cpp_strerror(r
) << dendl
;
97 int NetHandler::set_socket_options(int sd
, bool nodelay
, int size
)
100 // disable Nagle algorithm?
103 r
= ::setsockopt(sd
, IPPROTO_TCP
, TCP_NODELAY
, (SOCKOPT_VAL_TYPE
)&flag
, sizeof(flag
));
105 r
= ceph_sock_errno();
106 ldout(cct
, 0) << "couldn't set TCP_NODELAY: " << cpp_strerror(r
) << dendl
;
110 r
= ::setsockopt(sd
, SOL_SOCKET
, SO_RCVBUF
, (SOCKOPT_VAL_TYPE
)&size
, sizeof(size
));
112 r
= ceph_sock_errno();
113 ldout(cct
, 0) << "couldn't set SO_RCVBUF to " << size
<< ": " << cpp_strerror(r
) << dendl
;
118 #ifdef CEPH_USE_SO_NOSIGPIPE
120 r
= ::setsockopt(sd
, SOL_SOCKET
, SO_NOSIGPIPE
, (SOCKOPT_VAL_TYPE
)&val
, sizeof(val
));
122 r
= ceph_sock_errno();
123 ldout(cct
,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r
) << dendl
;
129 void NetHandler::set_priority(int sd
, int prio
, int domain
)
136 #ifdef IPTOS_CLASS_CS6
137 int iptos
= IPTOS_CLASS_CS6
;
140 r
= ::setsockopt(sd
, IPPROTO_IP
, IP_TOS
, (SOCKOPT_VAL_TYPE
)&iptos
, sizeof(iptos
));
143 r
= ::setsockopt(sd
, IPPROTO_IPV6
, IPV6_TCLASS
, (SOCKOPT_VAL_TYPE
)&iptos
, sizeof(iptos
));
146 lderr(cct
) << "couldn't set ToS of unknown family (" << domain
<< ")"
147 << " to " << iptos
<< dendl
;
151 r
= ceph_sock_errno();
152 ldout(cct
,0) << "couldn't set TOS to " << iptos
153 << ": " << cpp_strerror(r
) << dendl
;
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.
160 r
= ::setsockopt(sd
, SOL_SOCKET
, SO_PRIORITY
, (SOCKOPT_VAL_TYPE
)&prio
, sizeof(prio
));
162 r
= ceph_sock_errno();
163 ldout(cct
, 0) << __func__
<< " couldn't set SO_PRIORITY to " << prio
164 << ": " << cpp_strerror(r
) << dendl
;
168 #endif // SO_PRIORITY
171 int NetHandler::generic_connect(const entity_addr_t
& addr
, const entity_addr_t
&bind_addr
, bool nonblock
)
174 int s
= create_socket(addr
.get_family());
179 ret
= set_nonblock(s
);
181 compat_closesocket(s
);
186 set_socket_options(s
, cct
->_conf
->ms_tcp_nodelay
, cct
->_conf
->ms_tcp_rcvbuf
);
189 entity_addr_t addr
= bind_addr
;
190 if (cct
->_conf
->ms_bind_before_connect
&& (!addr
.is_blank_ip())) {
192 ret
= ::bind(s
, addr
.get_sockaddr(), addr
.get_sockaddr_len());
194 ret
= ceph_sock_errno();
195 ldout(cct
, 2) << __func__
<< " client bind error " << ", " << cpp_strerror(ret
) << dendl
;
196 compat_closesocket(s
);
202 ret
= ::connect(s
, addr
.get_sockaddr(), addr
.get_sockaddr_len());
204 ret
= ceph_sock_errno();
205 // Windows can return WSAEWOULDBLOCK (converted to EAGAIN).
206 if ((ret
== EINPROGRESS
|| ret
== EAGAIN
) && nonblock
)
209 ldout(cct
, 10) << __func__
<< " connect: " << cpp_strerror(ret
) << dendl
;
210 compat_closesocket(s
);
217 int NetHandler::reconnect(const entity_addr_t
&addr
, int sd
)
220 int ret
= ::connect(sd
, addr
.get_sockaddr(), addr
.get_sockaddr_len());
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
)
234 int NetHandler::connect(const entity_addr_t
&addr
, const entity_addr_t
& bind_addr
)
236 return generic_connect(addr
, bind_addr
, false);
239 int NetHandler::nonblock_connect(const entity_addr_t
&addr
, const entity_addr_t
& bind_addr
)
241 return generic_connect(addr
, bind_addr
, true);