ConnectionFileDescriptor.cpp revision 180546b3feb8c7bcca70a56776a7c4fad99ba09c
1//===-- ConnectionFileDescriptor.cpp ----------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "lldb/Core/ConnectionFileDescriptor.h" 11 12// C Includes 13#include <errno.h> 14#include <fcntl.h> 15#include <arpa/inet.h> 16#include <netdb.h> 17#include <netinet/in.h> 18#include <netinet/tcp.h> 19#include <sys/socket.h> 20#include <sys/un.h> 21#include <sys/types.h> 22#include <string.h> 23#include <stdlib.h> 24 25// C++ Includes 26// Other libraries and framework includes 27// Project includes 28#include "lldb/lldb-private-log.h" 29#include "lldb/Interpreter/Args.h" 30#include "lldb/Core/Communication.h" 31#include "lldb/Core/Log.h" 32#include "lldb/Core/RegularExpression.h" 33#include "lldb/Core/Timer.h" 34 35using namespace lldb; 36using namespace lldb_private; 37 38ConnectionFileDescriptor::ConnectionFileDescriptor () : 39 Connection(), 40 m_fd (-1), 41 m_is_socket (false), 42 m_should_close_fd (false) 43{ 44 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 45 "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", 46 this); 47} 48 49ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : 50 Connection(), 51 m_fd (fd), 52 m_is_socket (false), 53 m_should_close_fd (owns_fd) 54{ 55 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 56 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", 57 this, fd, owns_fd); 58} 59 60 61ConnectionFileDescriptor::~ConnectionFileDescriptor () 62{ 63 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 64 "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", 65 this); 66 Disconnect (NULL); 67} 68 69bool 70ConnectionFileDescriptor::IsConnected () const 71{ 72 return m_fd >= 0; 73} 74 75ConnectionStatus 76ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) 77{ 78 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 79 "%p ConnectionFileDescriptor::Connect (url = '%s')", 80 this, s); 81 82 if (s && s[0]) 83 { 84 char *end = NULL; 85 if (strstr(s, "listen://")) 86 { 87 // listen://HOST:PORT 88 unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0); 89 return SocketListen (listen_port, error_ptr); 90 } 91 else if (strstr(s, "unix-accept://")) 92 { 93 // unix://SOCKNAME 94 return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr); 95 } 96 else if (strstr(s, "connect://")) 97 { 98 return SocketConnect (s + strlen("connect://"), error_ptr); 99 } 100 else if (strstr(s, "fd://")) 101 { 102 // Just passing a native file descriptor within this current process 103 // that is already opened (possibly from a service or other source). 104 s += strlen ("fd://"); 105 bool success = false; 106 m_fd = Args::StringToSInt32 (s, -1, 0, &success); 107 if (success) 108 { 109 // We have what looks to be a valid file descriptor, but we 110 // should make it is. We currently are doing this by trying to 111 // get the flags from the file descriptor and making sure it 112 // isn't a bad fd. We also need to enable non blocking mode for 113 // the fd if it already isn't. 114 errno = 0; 115 int flags = ::fcntl (m_fd, F_GETFL, 0); 116 if (flags == -1 || errno == EBADF) 117 { 118 if (error_ptr) 119 error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s); 120 m_fd = -1; 121 return eConnectionStatusError; 122 } 123 else 124 { 125 if ((flags & O_NONBLOCK) == 0) 126 { 127 flags |= O_NONBLOCK; 128 ::fcntl (m_fd, F_SETFL, flags); 129 } 130 m_should_close_fd = true; 131 return eConnectionStatusSuccess; 132 } 133 } 134 135 if (error_ptr) 136 error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s); 137 m_fd = -1; 138 return eConnectionStatusError; 139 } 140 else if (strstr(s, "file://")) 141 { 142 // file:///PATH 143 const char *path = s + strlen("file://"); 144 m_fd = ::open (path, O_RDWR); 145 if (m_fd == -1) 146 { 147 if (error_ptr) 148 error_ptr->SetErrorToErrno(); 149 return eConnectionStatusError; 150 } 151 152 int flags = ::fcntl (m_fd, F_GETFL, 0); 153 if (flags >= 0) 154 { 155 if ((flags & O_NONBLOCK) == 0) 156 { 157 flags |= O_NONBLOCK; 158 ::fcntl (m_fd, F_SETFL, flags); 159 } 160 } 161 m_should_close_fd = true; 162 return eConnectionStatusSuccess; 163 } 164 if (error_ptr) 165 error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s); 166 return eConnectionStatusError; 167 } 168 if (error_ptr) 169 error_ptr->SetErrorString("invalid connect arguments"); 170 return eConnectionStatusError; 171} 172 173ConnectionStatus 174ConnectionFileDescriptor::Disconnect (Error *error_ptr) 175{ 176 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 177 "%p ConnectionFileDescriptor::Disconnect ()", 178 this); 179 if (m_should_close_fd == false) 180 { 181 m_fd = -1; 182 return eConnectionStatusSuccess; 183 } 184 return Close (m_fd, error_ptr); 185} 186 187size_t 188ConnectionFileDescriptor::Read (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr) 189{ 190 LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); 191 if (log) 192 log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...", 193 this, m_fd, dst, dst_len); 194 195 Error error; 196 ssize_t bytes_read = ::read (m_fd, dst, dst_len); 197 if (bytes_read == 0) 198 { 199 error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. 200 status = eConnectionStatusEndOfFile; 201 } 202 else if (bytes_read < 0) 203 { 204 error.SetErrorToErrno(); 205 } 206 else 207 { 208 error.Clear(); 209 } 210 211 if (log) 212 log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s", 213 this, 214 m_fd, 215 dst, 216 dst_len, 217 bytes_read, 218 error.AsCString()); 219 220 if (error_ptr) 221 *error_ptr = error; 222 223 if (error.Fail()) 224 { 225 uint32_t error_value = error.GetError(); 226 switch (error_value) 227 { 228 case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. 229 status = eConnectionStatusSuccess; 230 return 0; 231 232 case EBADF: // fildes is not a valid file or socket descriptor open for reading. 233 case EFAULT: // Buf points outside the allocated address space. 234 case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. 235 case EINVAL: // The pointer associated with fildes was negative. 236 case EIO: // An I/O error occurred while reading from the file system. 237 // The process group is orphaned. 238 // The file is a regular file, nbyte is greater than 0, 239 // the starting position is before the end-of-file, and 240 // the starting position is greater than or equal to the 241 // offset maximum established for the open file 242 // descriptor associated with fildes. 243 case EISDIR: // An attempt is made to read a directory. 244 case ENOBUFS: // An attempt to allocate a memory buffer fails. 245 case ENOMEM: // Insufficient memory is available. 246 status = eConnectionStatusError; 247 break; // Break to close.... 248 249 case ENXIO: // An action is requested of a device that does not exist.. 250 // A requested action cannot be performed by the device. 251 case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. 252 case ENOTCONN: // A read is attempted on an unconnected socket. 253 status = eConnectionStatusLostConnection; 254 break; // Break to close.... 255 256 case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. 257 status = eConnectionStatusTimedOut; 258 return 0; 259 } 260 261// if (log) 262// error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread); 263 Close (m_fd, NULL); 264 return 0; 265 } 266 return bytes_read; 267} 268 269size_t 270ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 271{ 272 LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); 273 if (log) 274 log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %zu)", this, src, src_len); 275 276 if (!IsConnected ()) 277 { 278 if (error_ptr) 279 error_ptr->SetErrorString("not connected"); 280 status = eConnectionStatusNoConnection; 281 return 0; 282 } 283 284 285 Error error; 286 287 ssize_t bytes_sent = 0; 288 289 if (m_is_socket) 290 bytes_sent = ::send (m_fd, src, src_len, 0); 291 else 292 bytes_sent = ::write (m_fd, src, src_len); 293 294 if (bytes_sent < 0) 295 error.SetErrorToErrno (); 296 else 297 error.Clear (); 298 299 if (log) 300 { 301 if (m_is_socket) 302 log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", 303 this, m_fd, src, src_len, bytes_sent, error.AsCString()); 304 else 305 log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)", 306 this, m_fd, src, src_len, bytes_sent, error.AsCString()); 307 } 308 309 if (error_ptr) 310 *error_ptr = error; 311 312 if (error.Fail()) 313 { 314 switch (error.GetError()) 315 { 316 case EAGAIN: 317 case EINTR: 318 status = eConnectionStatusSuccess; 319 return 0; 320 321 case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. 322 case ENOTCONN: // A read is attempted on an unconnected socket. 323 status = eConnectionStatusLostConnection; 324 break; // Break to close.... 325 326 default: 327 status = eConnectionStatusError; 328 break; // Break to close.... 329 } 330 331 Close (m_fd, NULL); 332 return 0; 333 } 334 335 status = eConnectionStatusSuccess; 336 return bytes_sent; 337} 338 339ConnectionStatus 340ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) 341{ 342 LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); 343 if (log) 344 log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec); 345 struct timeval *tv_ptr; 346 struct timeval tv; 347 if (timeout_usec == UINT32_MAX) 348 { 349 // Infinite wait... 350 tv_ptr = NULL; 351 } 352 else 353 { 354 TimeValue time_value; 355 time_value.OffsetWithMicroSeconds (timeout_usec); 356 tv = time_value.GetAsTimeVal(); 357 tv_ptr = &tv; 358 } 359 360 while (IsConnected()) 361 { 362 fd_set read_fds; 363 FD_ZERO (&read_fds); 364 FD_SET (m_fd, &read_fds); 365 int nfds = m_fd + 1; 366 367 Error error; 368 369 370 log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION); 371 if (log) 372 log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...", 373 this, nfds, m_fd, tv_ptr); 374 375 const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr); 376 if (num_set_fds < 0) 377 error.SetErrorToErrno(); 378 else 379 error.Clear(); 380 381 log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION); 382 if (log) 383 log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s", 384 this, nfds, m_fd, tv_ptr, num_set_fds, error.AsCString()); 385 386 if (error_ptr) 387 *error_ptr = error; 388 389 if (error.Fail()) 390 { 391 switch (error.GetError()) 392 { 393 case EBADF: // One of the descriptor sets specified an invalid descriptor. 394 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. 395 default: // Other unknown error 396 return eConnectionStatusError; 397 398 case EAGAIN: // The kernel was (perhaps temporarily) unable to 399 // allocate the requested number of file descriptors, 400 // or we have non-blocking IO 401 case EINTR: // A signal was delivered before the time limit 402 // expired and before any of the selected events 403 // occurred. 404 break; // Lets keep reading to until we timeout 405 } 406 } 407 else if (num_set_fds == 0) 408 { 409 return eConnectionStatusTimedOut; 410 } 411 else if (num_set_fds > 0) 412 { 413 return eConnectionStatusSuccess; 414 } 415 } 416 417 if (error_ptr) 418 error_ptr->SetErrorString("not connected"); 419 return eConnectionStatusLostConnection; 420} 421 422ConnectionStatus 423ConnectionFileDescriptor::Close (int& fd, Error *error_ptr) 424{ 425 if (error_ptr) 426 error_ptr->Clear(); 427 bool success = true; 428 if (fd >= 0) 429 { 430 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 431 "%p ConnectionFileDescriptor::Close (fd = %i)", 432 this, 433 fd); 434 435 success = ::close (fd) == 0; 436 if (!success && error_ptr) 437 { 438 // Only set the error if we have been asked to since something else 439 // might have caused us to try and shut down the connection and may 440 // have already set the error. 441 error_ptr->SetErrorToErrno(); 442 } 443 fd = -1; 444 } 445 m_is_socket = false; 446 if (success) 447 return eConnectionStatusSuccess; 448 else 449 return eConnectionStatusError; 450} 451 452ConnectionStatus 453ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr) 454{ 455 ConnectionStatus result = eConnectionStatusError; 456 struct sockaddr_un saddr_un; 457 458 m_is_socket = true; 459 460 int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0); 461 if (listen_socket == -1) 462 { 463 if (error_ptr) 464 error_ptr->SetErrorToErrno(); 465 return eConnectionStatusError; 466 } 467 468 saddr_un.sun_family = AF_UNIX; 469 ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1); 470 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; 471#if defined(__APPLE__) || defined(__FreeBSD__) 472 saddr_un.sun_len = SUN_LEN (&saddr_un); 473#endif 474 475 if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) 476 { 477 if (::listen (listen_socket, 5) == 0) 478 { 479 m_fd = ::accept (listen_socket, NULL, 0); 480 if (m_fd > 0) 481 { 482 m_should_close_fd = true; 483 484 if (error_ptr) 485 error_ptr->Clear(); 486 result = eConnectionStatusSuccess; 487 } 488 } 489 } 490 491 if (result != eConnectionStatusSuccess) 492 { 493 if (error_ptr) 494 error_ptr->SetErrorToErrno(); 495 } 496 // We are done with the listen port 497 Close (listen_socket, NULL); 498 return result; 499} 500 501ConnectionStatus 502ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr) 503{ 504 Close (m_fd, NULL); 505 m_is_socket = true; 506 507 // Open the socket that was passed in as an option 508 struct sockaddr_un saddr_un; 509 m_fd = ::socket (AF_UNIX, SOCK_STREAM, 0); 510 if (m_fd == -1) 511 { 512 if (error_ptr) 513 error_ptr->SetErrorToErrno(); 514 return eConnectionStatusError; 515 } 516 517 saddr_un.sun_family = AF_UNIX; 518 ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1); 519 saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; 520#if defined(__APPLE__) || defined(__FreeBSD__) 521 saddr_un.sun_len = SUN_LEN (&saddr_un); 522#endif 523 524 if (::connect (m_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) 525 { 526 if (error_ptr) 527 error_ptr->SetErrorToErrno(); 528 Close (m_fd, NULL); 529 return eConnectionStatusError; 530 } 531 if (error_ptr) 532 error_ptr->Clear(); 533 return eConnectionStatusSuccess; 534} 535 536ConnectionStatus 537ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr) 538{ 539 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 540 "%p ConnectionFileDescriptor::SocketListen (port = %i)", 541 this, listen_port_num); 542 543 Close (m_fd, NULL); 544 m_is_socket = true; 545 int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 546 if (listen_port == -1) 547 { 548 if (error_ptr) 549 error_ptr->SetErrorToErrno(); 550 return eConnectionStatusError; 551 } 552 553 // enable local address reuse 554 SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1); 555 556 struct sockaddr_in sa; 557 ::memset (&sa, 0, sizeof sa); 558 sa.sin_family = AF_INET; 559 sa.sin_port = htons (listen_port_num); 560 sa.sin_addr.s_addr = htonl (INADDR_ANY); 561 562 int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa)); 563 if (err == -1) 564 { 565 if (error_ptr) 566 error_ptr->SetErrorToErrno(); 567 Close (listen_port, NULL); 568 return eConnectionStatusError; 569 } 570 571 err = ::listen (listen_port, 1); 572 if (err == -1) 573 { 574 if (error_ptr) 575 error_ptr->SetErrorToErrno(); 576 Close (listen_port, NULL); 577 return eConnectionStatusError; 578 } 579 580 m_fd = ::accept (listen_port, NULL, 0); 581 if (m_fd == -1) 582 { 583 if (error_ptr) 584 error_ptr->SetErrorToErrno(); 585 Close (listen_port, NULL); 586 return eConnectionStatusError; 587 } 588 589 // We are done with the listen port 590 Close (listen_port, NULL); 591 592 m_should_close_fd = true; 593 594 // Keep our TCP packets coming without any delays. 595 SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 596 if (error_ptr) 597 error_ptr->Clear(); 598 return eConnectionStatusSuccess; 599} 600 601ConnectionStatus 602ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr) 603{ 604 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 605 "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)", 606 this, host_and_port); 607 Close (m_fd, NULL); 608 m_is_socket = true; 609 610 RegularExpression regex ("([^:]+):([0-9]+)"); 611 if (regex.Execute (host_and_port, 2) == false) 612 { 613 if (error_ptr) 614 error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port); 615 return eConnectionStatusError; 616 } 617 std::string host_str; 618 std::string port_str; 619 if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false || 620 regex.GetMatchAtIndex (host_and_port, 2, port_str) == false) 621 { 622 if (error_ptr) 623 error_ptr->SetErrorStringWithFormat("invalid host:port specification '%s'", host_and_port); 624 return eConnectionStatusError; 625 } 626 627 int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); 628 if (port == INT32_MIN) 629 { 630 if (error_ptr) 631 error_ptr->SetErrorStringWithFormat("invalid port '%s'", port_str.c_str()); 632 return eConnectionStatusError; 633 } 634 // Create the socket 635 m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 636 if (m_fd == -1) 637 { 638 if (error_ptr) 639 error_ptr->SetErrorToErrno(); 640 return eConnectionStatusError; 641 } 642 643 m_should_close_fd = true; 644 645 // Enable local address reuse 646 SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); 647 648 struct sockaddr_in sa; 649 ::memset (&sa, 0, sizeof (sa)); 650 sa.sin_family = AF_INET; 651 sa.sin_port = htons (port); 652 653 int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); 654 655 if (inet_pton_result <= 0) 656 { 657 struct hostent *host_entry = gethostbyname (host_str.c_str()); 658 if (host_entry) 659 host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); 660 inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); 661 if (inet_pton_result <= 0) 662 { 663 664 if (error_ptr) 665 { 666 if (inet_pton_result == -1) 667 error_ptr->SetErrorToErrno(); 668 else 669 error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str()); 670 } 671 Close (m_fd, NULL); 672 return eConnectionStatusError; 673 } 674 } 675 676 if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) 677 { 678 if (error_ptr) 679 error_ptr->SetErrorToErrno(); 680 Close (m_fd, NULL); 681 return eConnectionStatusError; 682 } 683 684 // Keep our TCP packets coming without any delays. 685 SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 686 if (error_ptr) 687 error_ptr->Clear(); 688 return eConnectionStatusSuccess; 689} 690 691int 692ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value) 693{ 694#if defined(__MINGW32__) || defined(__MINGW64__) 695 const char* option_value_p = static_cast<const char*>(&option_value); 696#else // #if defined(__MINGW32__) || defined(__MINGW64__) 697 const void* option_value_p = &option_name; 698#endif // #if defined(__MINGW32__) || defined(__MINGW64__) 699 700 return ::setsockopt(fd, level, option_name, option_value_p, sizeof(option_value)); 701} 702 703 704