]>
Commit | Line | Data |
---|---|---|
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 | ||
34 | namespace ceph{ | |
35 | ||
36 | int 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 | ||
65 | int 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 |
97 | int 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 | ||
129 | void 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 | ||
171 | int 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 | ||
217 | int 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 | ||
234 | int NetHandler::connect(const entity_addr_t &addr, const entity_addr_t& bind_addr) | |
235 | { | |
236 | return generic_connect(addr, bind_addr, false); | |
237 | } | |
238 | ||
239 | int 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 | } |