/src/brpc/src/butil/endpoint.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | // Date: Mon. Nov 7 14:47:36 CST 2011 |
19 | | |
20 | | #include "butil/compat.h" |
21 | | #include <arpa/inet.h> // inet_pton, inet_ntop |
22 | | #include <netdb.h> // gethostbyname_r |
23 | | #include <unistd.h> // gethostname |
24 | | #include <errno.h> // errno |
25 | | #include <string.h> // strcpy |
26 | | #include <stdio.h> // snprintf |
27 | | #include <stdlib.h> // strtol |
28 | | #include <sys/un.h> // sockaddr_un |
29 | | #include <sys/socket.h> // SO_REUSEADDR SO_REUSEPORT |
30 | | #include <memory> |
31 | | #include <gflags/gflags.h> |
32 | | #include <sys/poll.h> |
33 | | #if defined(OS_MACOSX) |
34 | | #include <sys/event.h> // kevent(), kqueue() |
35 | | #endif |
36 | | #include "butil/build_config.h" // OS_MACOSX |
37 | | #include "butil/fd_guard.h" // fd_guard |
38 | | #include "butil/endpoint.h" // ip_t |
39 | | #include "butil/logging.h" |
40 | | #include "butil/memory/singleton_on_pthread_once.h" |
41 | | #include "butil/strings/string_piece.h" |
42 | | #include "butil/fd_utility.h" |
43 | | #include "butil/memory/scope_guard.h" |
44 | | |
45 | | //supported since Linux 3.9. |
46 | | DEFINE_bool(reuse_port, false, "Enable SO_REUSEPORT for all listened sockets"); |
47 | | |
48 | | DEFINE_bool(reuse_addr, true, "Enable SO_REUSEADDR for all listened sockets"); |
49 | | |
50 | | DEFINE_bool(reuse_uds_path, false, "remove unix domain socket file before listen to it"); |
51 | | |
52 | | __BEGIN_DECLS |
53 | | int BAIDU_WEAK bthread_connect( |
54 | 0 | int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { |
55 | 0 | return connect(sockfd, serv_addr, addrlen); |
56 | 0 | } |
57 | | |
58 | | int BAIDU_WEAK bthread_timed_connect( |
59 | | int sockfd, const struct sockaddr* serv_addr, |
60 | | socklen_t addrlen, const timespec* abstime); |
61 | | |
62 | | __END_DECLS |
63 | | |
64 | | #include "butil/details/extended_endpoint.hpp" |
65 | | |
66 | | namespace butil { |
67 | | |
68 | | using details::ExtendedEndPoint; |
69 | | |
70 | 0 | static void set_endpoint(EndPoint* ep, ip_t ip, int port) { |
71 | 0 | ep->ip = ip; |
72 | 0 | ep->port = port; |
73 | 0 | if (ExtendedEndPoint::is_extended(*ep)) { |
74 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(*ep); |
75 | 0 | if (eep) { |
76 | 0 | eep->inc_ref(); |
77 | 0 | } else { |
78 | 0 | ep->ip = IP_ANY; |
79 | 0 | ep->port = 0; |
80 | 0 | } |
81 | 0 | } |
82 | 0 | } |
83 | | |
84 | 0 | void EndPoint::reset(void) { |
85 | 0 | if (ExtendedEndPoint::is_extended(*this)) { |
86 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(*this); |
87 | 0 | if (eep) { |
88 | 0 | eep->dec_ref(); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | ip = IP_ANY; |
92 | 0 | port = 0; |
93 | 0 | } |
94 | | |
95 | 0 | EndPoint::EndPoint(ip_t ip2, int port2) : ip(ip2), port(port2) { |
96 | | // Should never construct an extended endpoint by this way |
97 | 0 | if (ExtendedEndPoint::is_extended(*this)) { |
98 | 0 | CHECK(0) << "EndPoint construct with value that points to an extended EndPoint"; |
99 | 0 | ip = IP_ANY; |
100 | 0 | port = 0; |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | 0 | EndPoint::EndPoint(const EndPoint& rhs) { |
105 | 0 | set_endpoint(this, rhs.ip, rhs.port); |
106 | 0 | } |
107 | | |
108 | 0 | EndPoint::~EndPoint() { |
109 | 0 | reset(); |
110 | 0 | } |
111 | | |
112 | 0 | void EndPoint::operator=(const EndPoint& rhs) { |
113 | 0 | reset(); |
114 | 0 | set_endpoint(this, rhs.ip, rhs.port); |
115 | 0 | } |
116 | | |
117 | 12 | int str2ip(const char* ip_str, ip_t* ip) { |
118 | | // ip_str can be NULL when called by EndPoint(0, ...) |
119 | 12 | if (ip_str != NULL) { |
120 | 12 | for (; isspace(*ip_str); ++ip_str); |
121 | 12 | int rc = inet_pton(AF_INET, ip_str, ip); |
122 | 12 | if (rc > 0) { |
123 | 12 | return 0; |
124 | 12 | } |
125 | 12 | } |
126 | 0 | return -1; |
127 | 12 | } |
128 | | |
129 | 0 | IPStr ip2str(ip_t ip) { |
130 | 0 | IPStr str; |
131 | 0 | if (inet_ntop(AF_INET, &ip, str._buf, INET_ADDRSTRLEN) == NULL) { |
132 | 0 | return ip2str(IP_NONE); |
133 | 0 | } |
134 | 0 | return str; |
135 | 0 | } |
136 | | |
137 | 0 | int ip2hostname(ip_t ip, char* host, size_t host_len) { |
138 | 0 | if (host == NULL || host_len == 0) { |
139 | 0 | errno = EINVAL; |
140 | 0 | return -1; |
141 | 0 | } |
142 | 0 | sockaddr_in sa; |
143 | 0 | bzero((char*)&sa, sizeof(sa)); |
144 | 0 | sa.sin_family = AF_INET; |
145 | 0 | sa.sin_port = 0; // useless since we don't need server_name |
146 | 0 | sa.sin_addr = ip; |
147 | 0 | if (getnameinfo((const sockaddr*)&sa, sizeof(sa), |
148 | 0 | host, host_len, NULL, 0, NI_NAMEREQD) != 0) { |
149 | 0 | return -1; |
150 | 0 | } |
151 | | // remove baidu-specific domain name (that every name has) |
152 | 0 | butil::StringPiece str(host); |
153 | 0 | if (str.ends_with(".baidu.com")) { |
154 | 0 | host[str.size() - 10] = '\0'; |
155 | 0 | } |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | 0 | int ip2hostname(ip_t ip, std::string* host) { |
160 | 0 | char buf[128]; |
161 | 0 | if (ip2hostname(ip, buf, sizeof(buf)) == 0) { |
162 | 0 | host->assign(buf); |
163 | 0 | return 0; |
164 | 0 | } |
165 | 0 | return -1; |
166 | 0 | } |
167 | | |
168 | 0 | EndPointStr endpoint2str(const EndPoint& point) { |
169 | 0 | EndPointStr str; |
170 | 0 | if (ExtendedEndPoint::is_extended(point)) { |
171 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(point); |
172 | 0 | if (eep) { |
173 | 0 | eep->to(&str); |
174 | 0 | } else { |
175 | 0 | str._buf[0] = '\0'; |
176 | 0 | } |
177 | 0 | return str; |
178 | 0 | } |
179 | 0 | if (inet_ntop(AF_INET, &point.ip, str._buf, INET_ADDRSTRLEN) == NULL) { |
180 | 0 | return endpoint2str(EndPoint(IP_NONE, 0)); |
181 | 0 | } |
182 | 0 | char* buf = str._buf + strlen(str._buf); |
183 | 0 | *buf++ = ':'; |
184 | 0 | snprintf(buf, 16, "%d", point.port); |
185 | 0 | return str; |
186 | 0 | } |
187 | | |
188 | 0 | int hostname2ip(const char* hostname, ip_t* ip) { |
189 | 0 | char buf[256]; |
190 | 0 | if (NULL == hostname) { |
191 | 0 | if (gethostname(buf, sizeof(buf)) < 0) { |
192 | 0 | return -1; |
193 | 0 | } |
194 | 0 | hostname = buf; |
195 | 0 | } else { |
196 | | // skip heading space |
197 | 0 | for (; isspace(*hostname); ++hostname); |
198 | 0 | } |
199 | | |
200 | | #if defined(OS_MACOSX) |
201 | | // gethostbyname on MAC is thread-safe (with current usage) since the |
202 | | // returned hostent is TLS. Check following link for the ref: |
203 | | // https://lists.apple.com/archives/darwin-dev/2006/May/msg00008.html |
204 | | struct hostent* result = gethostbyname(hostname); |
205 | | if (result == NULL) { |
206 | | return -1; |
207 | | } |
208 | | #else |
209 | 0 | int aux_buf_len = 1024; |
210 | 0 | std::unique_ptr<char[]> aux_buf(new char[aux_buf_len]); |
211 | 0 | int ret = 0; |
212 | 0 | int error = 0; |
213 | 0 | struct hostent ent; |
214 | 0 | struct hostent* result = NULL; |
215 | 0 | do { |
216 | 0 | result = NULL; |
217 | 0 | error = 0; |
218 | 0 | ret = gethostbyname_r(hostname, |
219 | 0 | &ent, |
220 | 0 | aux_buf.get(), |
221 | 0 | aux_buf_len, |
222 | 0 | &result, |
223 | 0 | &error); |
224 | 0 | if (ret != ERANGE) { // aux_buf is not long enough |
225 | 0 | break; |
226 | 0 | } |
227 | 0 | aux_buf_len *= 2; |
228 | 0 | aux_buf.reset(new char[aux_buf_len]); |
229 | 0 | } while (1); |
230 | 0 | if (ret != 0 || result == NULL) { |
231 | 0 | return -1; |
232 | 0 | } |
233 | 0 | #endif // defined(OS_MACOSX) |
234 | | // Only fetch the first address here |
235 | 0 | bcopy((char*)result->h_addr, (char*)ip, result->h_length); |
236 | 0 | return 0; |
237 | 0 | } |
238 | | |
239 | | struct MyAddressInfo { |
240 | | char my_hostname[256]; |
241 | | ip_t my_ip; |
242 | | IPStr my_ip_str; |
243 | | |
244 | 0 | MyAddressInfo() { |
245 | 0 | my_ip = IP_ANY; |
246 | 0 | if (gethostname(my_hostname, sizeof(my_hostname)) < 0) { |
247 | 0 | my_hostname[0] = '\0'; |
248 | 0 | } else if (hostname2ip(my_hostname, &my_ip) != 0) { |
249 | 0 | my_ip = IP_ANY; |
250 | 0 | } |
251 | 0 | my_ip_str = ip2str(my_ip); |
252 | 0 | } |
253 | | }; |
254 | | |
255 | 0 | ip_t my_ip() { |
256 | 0 | return get_leaky_singleton<MyAddressInfo>()->my_ip; |
257 | 0 | } |
258 | | |
259 | 0 | const char* my_ip_cstr() { |
260 | 0 | return get_leaky_singleton<MyAddressInfo>()->my_ip_str.c_str(); |
261 | 0 | } |
262 | | |
263 | 0 | const char* my_hostname() { |
264 | 0 | return get_leaky_singleton<MyAddressInfo>()->my_hostname; |
265 | 0 | } |
266 | | |
267 | 0 | int str2endpoint(const char* str, EndPoint* point) { |
268 | 0 | if (ExtendedEndPoint::create(str, point)) { |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | | // Should be enough to hold ip address |
273 | 0 | char buf[64]; |
274 | 0 | size_t i = 0; |
275 | 0 | for (; i < sizeof(buf) && str[i] != '\0' && str[i] != ':'; ++i) { |
276 | 0 | buf[i] = str[i]; |
277 | 0 | } |
278 | 0 | if (i >= sizeof(buf) || str[i] != ':') { |
279 | 0 | return -1; |
280 | 0 | } |
281 | 0 | buf[i] = '\0'; |
282 | 0 | if (str2ip(buf, &point->ip) != 0) { |
283 | 0 | return -1; |
284 | 0 | } |
285 | 0 | ++i; |
286 | 0 | char* end = NULL; |
287 | 0 | point->port = strtol(str + i, &end, 10); |
288 | 0 | if (end == str + i) { |
289 | 0 | return -1; |
290 | 0 | } else if (*end) { |
291 | 0 | for (++end; isspace(*end); ++end); |
292 | 0 | if (*end) { |
293 | 0 | return -1; |
294 | 0 | } |
295 | 0 | } |
296 | 0 | if (point->port < 0 || point->port > 65535) { |
297 | 0 | return -1; |
298 | 0 | } |
299 | 0 | return 0; |
300 | 0 | } |
301 | | |
302 | 0 | int str2endpoint(const char* ip_str, int port, EndPoint* point) { |
303 | 0 | if (ExtendedEndPoint::create(ip_str, port, point)) { |
304 | 0 | return 0; |
305 | 0 | } |
306 | | |
307 | 0 | if (str2ip(ip_str, &point->ip) != 0) { |
308 | 0 | return -1; |
309 | 0 | } |
310 | 0 | if (port < 0 || port > 65535) { |
311 | 0 | return -1; |
312 | 0 | } |
313 | 0 | point->port = port; |
314 | 0 | return 0; |
315 | 0 | } |
316 | | |
317 | 0 | int hostname2endpoint(const char* str, EndPoint* point) { |
318 | | // Should be enough to hold ip address |
319 | | // The definitive descriptions of the rules for forming domain names appear in RFC 1035, RFC 1123, RFC 2181, |
320 | | // and RFC 5892. The full domain name may not exceed the length of 253 characters in its textual representation |
321 | | // (Domain Names - Domain Concepts and Facilities. IETF. doi:10.17487/RFC1034. RFC 1034.). |
322 | | // For cacheline optimize, use buf size as 256; |
323 | 0 | char buf[256]; |
324 | 0 | size_t i = 0; |
325 | 0 | for (; i < MAX_DOMAIN_LENGTH && str[i] != '\0' && str[i] != ':'; ++i) { |
326 | 0 | buf[i] = str[i]; |
327 | 0 | } |
328 | |
|
329 | 0 | if (i >= MAX_DOMAIN_LENGTH || str[i] != ':') { |
330 | 0 | return -1; |
331 | 0 | } |
332 | | |
333 | 0 | buf[i] = '\0'; |
334 | 0 | if (hostname2ip(buf, &point->ip) != 0) { |
335 | 0 | return -1; |
336 | 0 | } |
337 | 0 | if (str[i] == ':') { |
338 | 0 | ++i; |
339 | 0 | } |
340 | 0 | char* end = NULL; |
341 | 0 | point->port = strtol(str + i, &end, 10); |
342 | 0 | if (end == str + i) { |
343 | 0 | return -1; |
344 | 0 | } else if (*end) { |
345 | 0 | for (; isspace(*end); ++end); |
346 | 0 | if (*end) { |
347 | 0 | return -1; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | if (point->port < 0 || point->port > 65535) { |
351 | 0 | return -1; |
352 | 0 | } |
353 | 0 | return 0; |
354 | 0 | } |
355 | | |
356 | 0 | int hostname2endpoint(const char* name_str, int port, EndPoint* point) { |
357 | 0 | if (hostname2ip(name_str, &point->ip) != 0) { |
358 | 0 | return -1; |
359 | 0 | } |
360 | 0 | if (port < 0 || port > 65535) { |
361 | 0 | return -1; |
362 | 0 | } |
363 | 0 | point->port = port; |
364 | 0 | return 0; |
365 | 0 | } |
366 | | |
367 | 0 | int endpoint2hostname(const EndPoint& point, char* host, size_t host_len) { |
368 | 0 | if (ExtendedEndPoint::is_extended(point)) { |
369 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(point); |
370 | 0 | if (eep) { |
371 | 0 | return eep->to_hostname(host, host_len); |
372 | 0 | } |
373 | 0 | return -1; |
374 | 0 | } |
375 | | |
376 | 0 | if (ip2hostname(point.ip, host, host_len) == 0) { |
377 | 0 | size_t len = strlen(host); |
378 | 0 | if (len + 1 < host_len) { |
379 | 0 | snprintf(host + len, host_len - len, ":%d", point.port); |
380 | 0 | } |
381 | 0 | return 0; |
382 | 0 | } |
383 | 0 | return -1; |
384 | 0 | } |
385 | | |
386 | 0 | int endpoint2hostname(const EndPoint& point, std::string* host) { |
387 | 0 | char buf[256]; |
388 | 0 | if (endpoint2hostname(point, buf, sizeof(buf)) == 0) { |
389 | 0 | host->assign(buf); |
390 | 0 | return 0; |
391 | 0 | } |
392 | 0 | return -1; |
393 | 0 | } |
394 | | |
395 | | #if defined(OS_LINUX) |
396 | 0 | static short epoll_to_poll_events(uint32_t epoll_events) { |
397 | | // Most POLL* and EPOLL* are same values. |
398 | 0 | short poll_events = (epoll_events & |
399 | 0 | (EPOLLIN | EPOLLPRI | EPOLLOUT | |
400 | 0 | EPOLLRDNORM | EPOLLRDBAND | |
401 | 0 | EPOLLWRNORM | EPOLLWRBAND | |
402 | 0 | EPOLLMSG | EPOLLERR | EPOLLHUP)); |
403 | 0 | CHECK_EQ((uint32_t)poll_events, epoll_events); |
404 | 0 | return poll_events; |
405 | 0 | } |
406 | | #elif defined(OS_MACOSX) |
407 | | short kqueue_to_poll_events(int kqueue_events) { |
408 | | //TODO: add more values? |
409 | | short poll_events = 0; |
410 | | if (kqueue_events == EVFILT_READ) { |
411 | | poll_events |= POLLIN; |
412 | | } |
413 | | if (kqueue_events == EVFILT_WRITE) { |
414 | | poll_events |= POLLOUT; |
415 | | } |
416 | | return poll_events; |
417 | | } |
418 | | #endif |
419 | | |
420 | | int pthread_fd_wait(int fd, unsigned events, |
421 | 0 | const timespec* abstime) { |
422 | 0 | #if defined(OS_LINUX) |
423 | 0 | const short poll_events = epoll_to_poll_events(events); |
424 | | #elif defined(OS_MACOSX) |
425 | | const short poll_events = kqueue_to_poll_events(events); |
426 | | #endif |
427 | 0 | if (poll_events == 0) { |
428 | 0 | errno = EINVAL; |
429 | 0 | return -1; |
430 | 0 | } |
431 | 0 | pollfd ufds = { fd, poll_events, 0 }; |
432 | 0 | int64_t abstime_us = -1; |
433 | 0 | if (NULL != abstime) { |
434 | 0 | abstime_us = butil::timespec_to_microseconds(*abstime); |
435 | 0 | } |
436 | 0 | while (true) { |
437 | 0 | int diff_ms = -1; |
438 | 0 | if (NULL != abstime) { |
439 | 0 | int64_t now_us = butil::gettimeofday_us(); |
440 | 0 | if (abstime_us <= now_us) { |
441 | 0 | errno = ETIMEDOUT; |
442 | 0 | return -1; |
443 | 0 | } |
444 | 0 | diff_ms = (abstime_us - now_us + 999L) / 1000L; |
445 | 0 | } |
446 | 0 | int rc = poll(&ufds, 1, diff_ms); |
447 | 0 | if (rc > 0) { |
448 | 0 | break; |
449 | 0 | } else if (rc == 0) { |
450 | 0 | errno = ETIMEDOUT; |
451 | 0 | return -1; |
452 | 0 | } else { |
453 | 0 | if (errno == EINTR) { |
454 | 0 | continue; |
455 | 0 | } |
456 | 0 | return -1; |
457 | 0 | } |
458 | 0 | } |
459 | 0 | if (ufds.revents & POLLNVAL) { |
460 | 0 | errno = EBADF; |
461 | 0 | return -1; |
462 | 0 | } |
463 | 0 | return 0; |
464 | 0 | } |
465 | | |
466 | | int pthread_timed_connect(int sockfd, const struct sockaddr* serv_addr, |
467 | 0 | socklen_t addrlen, const timespec* abstime) { |
468 | 0 | bool is_blocking = butil::is_blocking(sockfd); |
469 | 0 | if (is_blocking) { |
470 | 0 | butil::make_non_blocking(sockfd); |
471 | 0 | } |
472 | | // Scoped non-blocking. |
473 | 0 | BRPC_SCOPE_EXIT { |
474 | 0 | if (is_blocking) { |
475 | 0 | butil::make_blocking(sockfd); |
476 | 0 | } |
477 | 0 | }; |
478 | |
|
479 | 0 | const int rc = ::connect(sockfd, serv_addr, addrlen); |
480 | 0 | if (rc == 0 || errno != EINPROGRESS) { |
481 | 0 | return rc; |
482 | 0 | } |
483 | 0 | #if defined(OS_LINUX) |
484 | 0 | if (pthread_fd_wait(sockfd, EPOLLOUT, abstime) < 0) { |
485 | | #elif defined(OS_MACOSX) |
486 | | if (pthread_fd_wait(sockfd, EVFILT_WRITE, abstime) < 0) { |
487 | | #endif |
488 | 0 | return -1; |
489 | 0 | } |
490 | | |
491 | 0 | if (is_connected(sockfd) != 0) { |
492 | 0 | return -1; |
493 | 0 | } |
494 | 0 | return 0; |
495 | 0 | } |
496 | | |
497 | 0 | int tcp_connect(EndPoint server, int* self_port) { |
498 | 0 | return tcp_connect(server, self_port, -1); |
499 | 0 | } |
500 | | |
501 | 0 | int tcp_connect(const EndPoint& server, int* self_port, int connect_timeout_ms) { |
502 | 0 | struct sockaddr_storage serv_addr{}; |
503 | 0 | socklen_t serv_addr_size = 0; |
504 | 0 | if (endpoint2sockaddr(server, &serv_addr, &serv_addr_size) != 0) { |
505 | 0 | return -1; |
506 | 0 | } |
507 | 0 | fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0)); |
508 | 0 | if (sockfd < 0) { |
509 | 0 | return -1; |
510 | 0 | } |
511 | 0 | timespec abstime{}; |
512 | 0 | timespec* abstime_ptr = NULL; |
513 | 0 | if (connect_timeout_ms > 0) { |
514 | 0 | abstime = butil::milliseconds_from_now(connect_timeout_ms); |
515 | 0 | abstime_ptr = &abstime; |
516 | 0 | } |
517 | 0 | int rc; |
518 | 0 | if (bthread_timed_connect != NULL) { |
519 | 0 | rc = bthread_timed_connect(sockfd, (struct sockaddr*)&serv_addr, |
520 | 0 | serv_addr_size, abstime_ptr); |
521 | 0 | } else { |
522 | 0 | rc = pthread_timed_connect(sockfd, (struct sockaddr*) &serv_addr, |
523 | 0 | serv_addr_size, abstime_ptr); |
524 | 0 | } |
525 | 0 | if (rc < 0) { |
526 | 0 | return -1; |
527 | 0 | } |
528 | 0 | if (self_port != NULL) { |
529 | 0 | EndPoint pt; |
530 | 0 | if (get_local_side(sockfd, &pt) == 0) { |
531 | 0 | *self_port = pt.port; |
532 | 0 | } else { |
533 | 0 | CHECK(false) << "Fail to get the local port of sockfd=" << sockfd; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | return sockfd.release(); |
537 | 0 | } |
538 | | |
539 | 0 | int tcp_listen(EndPoint point) { |
540 | 0 | struct sockaddr_storage serv_addr; |
541 | 0 | socklen_t serv_addr_size = 0; |
542 | 0 | if (endpoint2sockaddr(point, &serv_addr, &serv_addr_size) != 0) { |
543 | 0 | return -1; |
544 | 0 | } |
545 | 0 | fd_guard sockfd(socket(serv_addr.ss_family, SOCK_STREAM, 0)); |
546 | 0 | if (sockfd < 0) { |
547 | 0 | return -1; |
548 | 0 | } |
549 | | |
550 | 0 | if (FLAGS_reuse_addr) { |
551 | 0 | #if defined(SO_REUSEADDR) |
552 | 0 | const int on = 1; |
553 | 0 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, |
554 | 0 | &on, sizeof(on)) != 0) { |
555 | 0 | return -1; |
556 | 0 | } |
557 | | #else |
558 | | LOG(ERROR) << "Missing def of SO_REUSEADDR while -reuse_addr is on"; |
559 | | return -1; |
560 | | #endif |
561 | 0 | } |
562 | | |
563 | 0 | if (FLAGS_reuse_port) { |
564 | 0 | #if defined(SO_REUSEPORT) |
565 | 0 | const int on = 1; |
566 | 0 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, |
567 | 0 | &on, sizeof(on)) != 0) { |
568 | 0 | LOG(WARNING) << "Fail to setsockopt SO_REUSEPORT of sockfd=" << sockfd; |
569 | 0 | } |
570 | | #else |
571 | | LOG(ERROR) << "Missing def of SO_REUSEPORT while -reuse_port is on"; |
572 | | return -1; |
573 | | #endif |
574 | 0 | } |
575 | |
|
576 | 0 | if (FLAGS_reuse_uds_path && serv_addr.ss_family == AF_UNIX) { |
577 | 0 | ::unlink(((sockaddr_un*) &serv_addr)->sun_path); |
578 | 0 | } |
579 | |
|
580 | 0 | if (bind(sockfd, (struct sockaddr*)& serv_addr, serv_addr_size) != 0) { |
581 | 0 | return -1; |
582 | 0 | } |
583 | 0 | if (listen(sockfd, 65535) != 0) { |
584 | | // ^^^ kernel would silently truncate backlog to the value |
585 | | // defined in /proc/sys/net/core/somaxconn if it is less |
586 | | // than 65535 |
587 | 0 | return -1; |
588 | 0 | } |
589 | 0 | return sockfd.release(); |
590 | 0 | } |
591 | | |
592 | 0 | int get_local_side(int fd, EndPoint *out) { |
593 | 0 | struct sockaddr_storage addr; |
594 | 0 | socklen_t socklen = sizeof(addr); |
595 | 0 | const int rc = getsockname(fd, (struct sockaddr*)&addr, &socklen); |
596 | 0 | if (rc != 0) { |
597 | 0 | return rc; |
598 | 0 | } |
599 | 0 | if (out) { |
600 | 0 | return sockaddr2endpoint(&addr, socklen, out); |
601 | 0 | } |
602 | 0 | return 0; |
603 | 0 | } |
604 | | |
605 | 0 | int get_remote_side(int fd, EndPoint *out) { |
606 | 0 | struct sockaddr_storage addr; |
607 | 0 | bzero(&addr, sizeof(addr)); |
608 | 0 | socklen_t socklen = sizeof(addr); |
609 | 0 | const int rc = getpeername(fd, (struct sockaddr*)&addr, &socklen); |
610 | 0 | if (rc != 0) { |
611 | 0 | return rc; |
612 | 0 | } |
613 | 0 | if (out) { |
614 | 0 | return sockaddr2endpoint(&addr, socklen, out); |
615 | 0 | } |
616 | 0 | return 0; |
617 | 0 | } |
618 | | |
619 | 0 | int endpoint2sockaddr(const EndPoint& point, struct sockaddr_storage* ss, socklen_t* size) { |
620 | 0 | bzero(ss, sizeof(*ss)); |
621 | 0 | if (ExtendedEndPoint::is_extended(point)) { |
622 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(point); |
623 | 0 | if (!eep) { |
624 | 0 | return -1; |
625 | 0 | } |
626 | 0 | int ret = eep->to(ss); |
627 | 0 | if (ret < 0) { |
628 | 0 | return -1; |
629 | 0 | } |
630 | 0 | if (size) { |
631 | 0 | *size = static_cast<socklen_t>(ret); |
632 | 0 | } |
633 | 0 | return 0; |
634 | 0 | } |
635 | 0 | struct sockaddr_in* in4 = (struct sockaddr_in*) ss; |
636 | 0 | in4->sin_family = AF_INET; |
637 | 0 | in4->sin_addr = point.ip; |
638 | 0 | in4->sin_port = htons(point.port); |
639 | 0 | if (size) { |
640 | 0 | *size = sizeof(*in4); |
641 | 0 | } |
642 | 0 | return 0; |
643 | 0 | } |
644 | | |
645 | 0 | int sockaddr2endpoint(struct sockaddr_storage* ss, socklen_t size, EndPoint* point) { |
646 | 0 | if (ss->ss_family == AF_INET) { |
647 | 0 | *point = EndPoint(*(sockaddr_in*)ss); |
648 | 0 | return 0; |
649 | 0 | } |
650 | 0 | if (ExtendedEndPoint::create(ss, size, point)) { |
651 | 0 | return 0; |
652 | 0 | } |
653 | 0 | return -1; |
654 | 0 | } |
655 | | |
656 | 0 | sa_family_t get_endpoint_type(const EndPoint& point) { |
657 | 0 | if (ExtendedEndPoint::is_extended(point)) { |
658 | 0 | ExtendedEndPoint* eep = ExtendedEndPoint::address(point); |
659 | 0 | if (eep) { |
660 | 0 | return eep->family(); |
661 | 0 | } |
662 | 0 | return AF_UNSPEC; |
663 | 0 | } |
664 | 0 | return AF_INET; |
665 | 0 | } |
666 | | |
667 | 0 | bool is_endpoint_extended(const EndPoint& point) { |
668 | 0 | return ExtendedEndPoint::is_extended(point); |
669 | 0 | } |
670 | | |
671 | | } // namespace butil |