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