Coverage Report

Created: 2024-09-03 06:23

/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