1 //===-- ConnectionFileDescriptorPosix.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 #if defined(__APPLE__) 11 // Enable this special support for Apple builds where we can have unlimited 12 // select bounds. We tried switching to poll() and kqueue and we were panicing 13 // the kernel, so we have to stick with select for now. 14 #define _DARWIN_UNLIMITED_SELECT 15 #endif 16 17 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" 18 #include "lldb/Host/Config.h" 19 #include "lldb/Host/IOObject.h" 20 #include "lldb/Host/SocketAddress.h" 21 #include "lldb/Host/Socket.h" 22 #include "lldb/Host/StringConvert.h" 23 24 // C Includes 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include <sys/types.h> 30 31 #ifndef LLDB_DISABLE_POSIX 32 #include <termios.h> 33 #endif 34 35 // C++ Includes 36 #include <sstream> 37 38 // Other libraries and framework includes 39 #include "llvm/Support/ErrorHandling.h" 40 #if defined(__APPLE__) 41 #include "llvm/ADT/SmallVector.h" 42 #endif 43 // Project includes 44 #include "lldb/Core/Communication.h" 45 #include "lldb/Core/Log.h" 46 #include "lldb/Core/StreamString.h" 47 #include "lldb/Core/Timer.h" 48 #include "lldb/Host/Host.h" 49 #include "lldb/Host/Socket.h" 50 #include "lldb/Interpreter/Args.h" 51 52 #include "Utility/UriParser.h" 53 54 using namespace lldb; 55 using namespace lldb_private; 56 57 ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) 58 : Connection() 59 , m_pipe() 60 , m_mutex(Mutex::eMutexTypeRecursive) 61 , m_shutting_down(false) 62 , m_waiting_for_accept(false) 63 , m_child_processes_inherit(child_processes_inherit) 64 { 65 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); 66 if (log) 67 log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this)); 68 } 69 70 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) 71 : Connection() 72 , m_pipe() 73 , m_mutex(Mutex::eMutexTypeRecursive) 74 , m_shutting_down(false) 75 , m_waiting_for_accept(false) 76 , m_child_processes_inherit(false) 77 { 78 m_write_sp.reset(new File(fd, owns_fd)); 79 m_read_sp.reset(new File(fd, false)); 80 81 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); 82 if (log) 83 log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", static_cast<void *>(this), fd, 84 owns_fd); 85 OpenCommandPipe(); 86 } 87 88 ConnectionFileDescriptor::ConnectionFileDescriptor(Socket* socket) 89 : Connection() 90 , m_pipe() 91 , m_mutex(Mutex::eMutexTypeRecursive) 92 , m_shutting_down(false) 93 , m_waiting_for_accept(false) 94 , m_child_processes_inherit(false) 95 { 96 InitializeSocket(socket); 97 } 98 99 ConnectionFileDescriptor::~ConnectionFileDescriptor() 100 { 101 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); 102 if (log) 103 log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this)); 104 Disconnect(NULL); 105 CloseCommandPipe(); 106 } 107 108 void 109 ConnectionFileDescriptor::OpenCommandPipe() 110 { 111 CloseCommandPipe(); 112 113 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 114 // Make the command file descriptor here: 115 Error result = m_pipe.CreateNew(m_child_processes_inherit); 116 if (!result.Success()) 117 { 118 if (log) 119 log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this), 120 result.AsCString()); 121 } 122 else 123 { 124 if (log) 125 log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this), 126 m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor()); 127 } 128 } 129 130 void 131 ConnectionFileDescriptor::CloseCommandPipe() 132 { 133 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 134 if (log) 135 log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this)); 136 137 m_pipe.Close(); 138 } 139 140 bool 141 ConnectionFileDescriptor::IsConnected() const 142 { 143 return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid()); 144 } 145 146 ConnectionStatus 147 ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) 148 { 149 Mutex::Locker locker(m_mutex); 150 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 151 if (log) 152 log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s); 153 154 OpenCommandPipe(); 155 156 if (s && s[0]) 157 { 158 if (strstr(s, "listen://") == s) 159 { 160 // listen://HOST:PORT 161 return SocketListenAndAccept(s + strlen("listen://"), error_ptr); 162 } 163 else if (strstr(s, "accept://") == s) 164 { 165 // unix://SOCKNAME 166 return NamedSocketAccept(s + strlen("accept://"), error_ptr); 167 } 168 else if (strstr(s, "unix-accept://") == s) 169 { 170 // unix://SOCKNAME 171 return NamedSocketAccept(s + strlen("unix-accept://"), error_ptr); 172 } 173 else if (strstr(s, "adb://") == s) 174 { 175 int port = -1; 176 std::string scheme, host, path; 177 if (!UriParser::Parse(s, scheme, host, port, path)) 178 { 179 if (error_ptr) 180 error_ptr->SetErrorStringWithFormat("Failed to parse URL '%s'", s); 181 return eConnectionStatusError; 182 } 183 std::ostringstream host_and_port; 184 host_and_port << "localhost:" << port; 185 return ConnectTCP(host_and_port.str().c_str(), error_ptr); 186 } 187 else if (strstr(s, "connect://") == s) 188 { 189 return ConnectTCP(s + strlen("connect://"), error_ptr); 190 } 191 else if (strstr(s, "tcp-connect://") == s) 192 { 193 return ConnectTCP(s + strlen("tcp-connect://"), error_ptr); 194 } 195 else if (strstr(s, "udp://") == s) 196 { 197 return ConnectUDP(s + strlen("udp://"), error_ptr); 198 } 199 #ifndef LLDB_DISABLE_POSIX 200 else if (strstr(s, "fd://") == s) 201 { 202 // Just passing a native file descriptor within this current process 203 // that is already opened (possibly from a service or other source). 204 s += strlen("fd://"); 205 bool success = false; 206 int fd = StringConvert::ToSInt32(s, -1, 0, &success); 207 208 if (success) 209 { 210 // We have what looks to be a valid file descriptor, but we 211 // should make sure it is. We currently are doing this by trying to 212 // get the flags from the file descriptor and making sure it 213 // isn't a bad fd. 214 errno = 0; 215 int flags = ::fcntl(fd, F_GETFL, 0); 216 if (flags == -1 || errno == EBADF) 217 { 218 if (error_ptr) 219 error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s); 220 m_read_sp.reset(); 221 m_write_sp.reset(); 222 return eConnectionStatusError; 223 } 224 else 225 { 226 // Don't take ownership of a file descriptor that gets passed 227 // to us since someone else opened the file descriptor and 228 // handed it to us. 229 // TODO: Since are using a URL to open connection we should 230 // eventually parse options using the web standard where we 231 // have "fd://123?opt1=value;opt2=value" and we can have an 232 // option be "owns=1" or "owns=0" or something like this to 233 // allow us to specify this. For now, we assume we must 234 // assume we don't own it. 235 236 std::unique_ptr<Socket> tcp_socket; 237 tcp_socket.reset(new Socket(fd, Socket::ProtocolTcp, false)); 238 // Try and get a socket option from this file descriptor to 239 // see if this is a socket and set m_is_socket accordingly. 240 int resuse; 241 bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse); 242 if (is_socket) 243 { 244 m_read_sp = std::move(tcp_socket); 245 m_write_sp = m_read_sp; 246 } 247 else 248 { 249 m_read_sp.reset(new File(fd, false)); 250 m_write_sp.reset(new File(fd, false)); 251 } 252 m_uri.assign(s); 253 return eConnectionStatusSuccess; 254 } 255 } 256 257 if (error_ptr) 258 error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"fd://%s\"", s); 259 m_read_sp.reset(); 260 m_write_sp.reset(); 261 return eConnectionStatusError; 262 } 263 else if (strstr(s, "file://") == s) 264 { 265 // file:///PATH 266 const char *path = s + strlen("file://"); 267 int fd = -1; 268 do 269 { 270 fd = ::open(path, O_RDWR); 271 } while (fd == -1 && errno == EINTR); 272 273 if (fd == -1) 274 { 275 if (error_ptr) 276 error_ptr->SetErrorToErrno(); 277 return eConnectionStatusError; 278 } 279 280 if (::isatty(fd)) 281 { 282 // Set up serial terminal emulation 283 struct termios options; 284 ::tcgetattr(fd, &options); 285 286 // Set port speed to maximum 287 ::cfsetospeed(&options, B115200); 288 ::cfsetispeed(&options, B115200); 289 290 // Raw input, disable echo and signals 291 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 292 293 // Make sure only one character is needed to return from a read 294 options.c_cc[VMIN] = 1; 295 options.c_cc[VTIME] = 0; 296 297 ::tcsetattr(fd, TCSANOW, &options); 298 } 299 300 int flags = ::fcntl(fd, F_GETFL, 0); 301 if (flags >= 0) 302 { 303 if ((flags & O_NONBLOCK) == 0) 304 { 305 flags |= O_NONBLOCK; 306 ::fcntl(fd, F_SETFL, flags); 307 } 308 } 309 m_read_sp.reset(new File(fd, true)); 310 m_write_sp.reset(new File(fd, false)); 311 return eConnectionStatusSuccess; 312 } 313 #endif 314 if (error_ptr) 315 error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s); 316 return eConnectionStatusError; 317 } 318 if (error_ptr) 319 error_ptr->SetErrorString("invalid connect arguments"); 320 return eConnectionStatusError; 321 } 322 323 bool 324 ConnectionFileDescriptor::InterruptRead() 325 { 326 size_t bytes_written = 0; 327 Error result = m_pipe.Write("i", 1, bytes_written); 328 return result.Success(); 329 } 330 331 ConnectionStatus 332 ConnectionFileDescriptor::Disconnect(Error *error_ptr) 333 { 334 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 335 if (log) 336 log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this)); 337 338 ConnectionStatus status = eConnectionStatusSuccess; 339 340 if (!IsConnected()) 341 { 342 if (log) 343 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this)); 344 return eConnectionStatusSuccess; 345 } 346 347 if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket) 348 static_cast<Socket &>(*m_read_sp).PreDisconnect(); 349 350 // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely 351 // because somebody is doing a blocking read on our file descriptor. If that's the case, 352 // then send the "q" char to the command file channel so the read will wake up and the connection 353 // will then know to shut down. 354 355 m_shutting_down = true; 356 357 Mutex::Locker locker; 358 bool got_lock = locker.TryLock(m_mutex); 359 360 if (!got_lock) 361 { 362 if (m_pipe.CanWrite()) 363 { 364 size_t bytes_written = 0; 365 Error result = m_pipe.Write("q", 1, bytes_written); 366 if (log) 367 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.", 368 static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString()); 369 } 370 else if (log) 371 { 372 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", 373 static_cast<void *>(this)); 374 } 375 locker.Lock(m_mutex); 376 } 377 378 Error error = m_read_sp->Close(); 379 Error error2 = m_write_sp->Close(); 380 if (error.Fail() || error2.Fail()) 381 status = eConnectionStatusError; 382 if (error_ptr) 383 *error_ptr = error.Fail() ? error : error2; 384 385 // Close any pipes we were using for async interrupts 386 m_pipe.Close(); 387 388 m_uri.clear(); 389 m_shutting_down = false; 390 return status; 391 } 392 393 size_t 394 ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) 395 { 396 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 397 398 Mutex::Locker locker; 399 bool got_lock = locker.TryLock(m_mutex); 400 if (!got_lock) 401 { 402 if (log) 403 log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this)); 404 if (error_ptr) 405 error_ptr->SetErrorString("failed to get the connection lock for read."); 406 407 status = eConnectionStatusTimedOut; 408 return 0; 409 } 410 411 if (m_shutting_down) 412 { 413 status = eConnectionStatusError; 414 return 0; 415 } 416 417 status = BytesAvailable(timeout_usec, error_ptr); 418 if (status != eConnectionStatusSuccess) 419 return 0; 420 421 Error error; 422 size_t bytes_read = dst_len; 423 error = m_read_sp->Read(dst, bytes_read); 424 425 if (log) 426 { 427 log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s", 428 static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst), 429 static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString()); 430 } 431 432 if (bytes_read == 0) 433 { 434 error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. 435 status = eConnectionStatusEndOfFile; 436 } 437 438 if (error_ptr) 439 *error_ptr = error; 440 441 if (error.Fail()) 442 { 443 uint32_t error_value = error.GetError(); 444 switch (error_value) 445 { 446 case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. 447 if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) 448 status = eConnectionStatusTimedOut; 449 else 450 status = eConnectionStatusSuccess; 451 return 0; 452 453 case EFAULT: // Buf points outside the allocated address space. 454 case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. 455 case EINVAL: // The pointer associated with fildes was negative. 456 case EIO: // An I/O error occurred while reading from the file system. 457 // The process group is orphaned. 458 // The file is a regular file, nbyte is greater than 0, 459 // the starting position is before the end-of-file, and 460 // the starting position is greater than or equal to the 461 // offset maximum established for the open file 462 // descriptor associated with fildes. 463 case EISDIR: // An attempt is made to read a directory. 464 case ENOBUFS: // An attempt to allocate a memory buffer fails. 465 case ENOMEM: // Insufficient memory is available. 466 status = eConnectionStatusError; 467 break; // Break to close.... 468 469 case ENOENT: // no such file or directory 470 case EBADF: // fildes is not a valid file or socket descriptor open for reading. 471 case ENXIO: // An action is requested of a device that does not exist.. 472 // A requested action cannot be performed by the device. 473 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. 474 case ENOTCONN: // A read is attempted on an unconnected socket. 475 status = eConnectionStatusLostConnection; 476 break; // Break to close.... 477 478 case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. 479 status = eConnectionStatusTimedOut; 480 return 0; 481 482 default: 483 if (log) 484 log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this), 485 strerror(error_value)); 486 status = eConnectionStatusError; 487 break; // Break to close.... 488 } 489 490 return 0; 491 } 492 return bytes_read; 493 } 494 495 size_t 496 ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 497 { 498 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 499 if (log) 500 log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this), 501 static_cast<const void *>(src), static_cast<uint64_t>(src_len)); 502 503 if (!IsConnected()) 504 { 505 if (error_ptr) 506 error_ptr->SetErrorString("not connected"); 507 status = eConnectionStatusNoConnection; 508 return 0; 509 } 510 511 Error error; 512 513 size_t bytes_sent = src_len; 514 error = m_write_sp->Write(src, bytes_sent); 515 516 if (log) 517 { 518 log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", 519 static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src), 520 static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString()); 521 } 522 523 if (error_ptr) 524 *error_ptr = error; 525 526 if (error.Fail()) 527 { 528 switch (error.GetError()) 529 { 530 case EAGAIN: 531 case EINTR: 532 status = eConnectionStatusSuccess; 533 return 0; 534 535 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. 536 case ENOTCONN: // A read is attempted on an unconnected socket. 537 status = eConnectionStatusLostConnection; 538 break; // Break to close.... 539 540 default: 541 status = eConnectionStatusError; 542 break; // Break to close.... 543 } 544 545 return 0; 546 } 547 548 status = eConnectionStatusSuccess; 549 return bytes_sent; 550 } 551 552 std::string 553 ConnectionFileDescriptor::GetURI() 554 { 555 return m_uri; 556 } 557 558 // This ConnectionFileDescriptor::BytesAvailable() uses select(). 559 // 560 // PROS: 561 // - select is consistent across most unix platforms 562 // - The Apple specific version allows for unlimited fds in the fd_sets by 563 // setting the _DARWIN_UNLIMITED_SELECT define prior to including the 564 // required header files. 565 // CONS: 566 // - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE. 567 // This implementation will assert if it runs into that hard limit to let 568 // users know that another ConnectionFileDescriptor::BytesAvailable() should 569 // be used or a new version of ConnectionFileDescriptor::BytesAvailable() 570 // should be written for the system that is running into the limitations. 571 572 #if defined(__APPLE__) 573 #define FD_SET_DATA(fds) fds.data() 574 #else 575 #define FD_SET_DATA(fds) &fds 576 #endif 577 578 ConnectionStatus 579 ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr) 580 { 581 // Don't need to take the mutex here separately since we are only called from Read. If we 582 // ever get used more generally we will need to lock here as well. 583 584 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION)); 585 if (log) 586 log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec); 587 588 struct timeval *tv_ptr; 589 struct timeval tv; 590 if (timeout_usec == UINT32_MAX) 591 { 592 // Inifinite wait... 593 tv_ptr = nullptr; 594 } 595 else 596 { 597 TimeValue time_value; 598 time_value.OffsetWithMicroSeconds(timeout_usec); 599 tv.tv_sec = time_value.seconds(); 600 tv.tv_usec = time_value.microseconds(); 601 tv_ptr = &tv; 602 } 603 604 // Make a copy of the file descriptors to make sure we don't 605 // have another thread change these values out from under us 606 // and cause problems in the loop below where like in FS_SET() 607 const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); 608 const int pipe_fd = m_pipe.GetReadFileDescriptor(); 609 610 if (handle != IOObject::kInvalidHandleValue) 611 { 612 #if defined(_MSC_VER) 613 // select() won't accept pipes on Windows. The entire Windows codepath needs to be 614 // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least 615 // this will allow ::select() to not return an error. 616 const bool have_pipe_fd = false; 617 #else 618 const bool have_pipe_fd = pipe_fd >= 0; 619 #if !defined(__APPLE__) 620 assert(handle < FD_SETSIZE); 621 if (have_pipe_fd) 622 assert(pipe_fd < FD_SETSIZE); 623 #endif 624 #endif 625 while (handle == m_read_sp->GetWaitableHandle()) 626 { 627 const int nfds = std::max<int>(handle, pipe_fd) + 1; 628 #if defined(__APPLE__) 629 llvm::SmallVector<fd_set, 1> read_fds; 630 read_fds.resize((nfds / FD_SETSIZE) + 1); 631 for (size_t i = 0; i < read_fds.size(); ++i) 632 FD_ZERO(&read_fds[i]); 633 // FD_SET doesn't bounds check, it just happily walks off the end 634 // but we have taken care of making the extra storage with our 635 // SmallVector of fd_set objects 636 #else 637 fd_set read_fds; 638 FD_ZERO(&read_fds); 639 #endif 640 FD_SET(handle, FD_SET_DATA(read_fds)); 641 if (have_pipe_fd) 642 FD_SET(pipe_fd, FD_SET_DATA(read_fds)); 643 644 Error error; 645 646 if (log) 647 { 648 if (have_pipe_fd) 649 log->Printf( 650 "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...", 651 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr)); 652 else 653 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...", 654 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr)); 655 } 656 657 const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr); 658 if (num_set_fds < 0) 659 error.SetErrorToErrno(); 660 else 661 error.Clear(); 662 663 if (log) 664 { 665 if (have_pipe_fd) 666 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) " 667 "=> %d, error = %s", 668 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds, 669 error.AsCString()); 670 else 671 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => " 672 "%d, error = %s", 673 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString()); 674 } 675 676 if (error_ptr) 677 *error_ptr = error; 678 679 if (error.Fail()) 680 { 681 switch (error.GetError()) 682 { 683 case EBADF: // One of the descriptor sets specified an invalid descriptor. 684 return eConnectionStatusLostConnection; 685 686 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. 687 default: // Other unknown error 688 return eConnectionStatusError; 689 690 case EAGAIN: // The kernel was (perhaps temporarily) unable to 691 // allocate the requested number of file descriptors, 692 // or we have non-blocking IO 693 case EINTR: // A signal was delivered before the time limit 694 // expired and before any of the selected events 695 // occurred. 696 break; // Lets keep reading to until we timeout 697 } 698 } 699 else if (num_set_fds == 0) 700 { 701 return eConnectionStatusTimedOut; 702 } 703 else if (num_set_fds > 0) 704 { 705 if (FD_ISSET(handle, FD_SET_DATA(read_fds))) 706 return eConnectionStatusSuccess; 707 if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds))) 708 { 709 // There is an interrupt or exit command in the command pipe 710 // Read the data from that pipe: 711 char buffer[1]; 712 713 ssize_t bytes_read; 714 715 do 716 { 717 bytes_read = ::read(pipe_fd, buffer, sizeof(buffer)); 718 } while (bytes_read < 0 && errno == EINTR); 719 720 switch (buffer[0]) 721 { 722 case 'q': 723 if (log) 724 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() " 725 "got data: %c from the command channel.", 726 static_cast<void *>(this), buffer[0]); 727 return eConnectionStatusEndOfFile; 728 case 'i': 729 // Interrupt the current read 730 return eConnectionStatusInterrupted; 731 } 732 } 733 } 734 } 735 } 736 737 if (error_ptr) 738 error_ptr->SetErrorString("not connected"); 739 return eConnectionStatusLostConnection; 740 } 741 742 ConnectionStatus 743 ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr) 744 { 745 Socket *socket = nullptr; 746 Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket); 747 if (error_ptr) 748 *error_ptr = error; 749 m_write_sp.reset(socket); 750 m_read_sp = m_write_sp; 751 if (error.Fail()) 752 { 753 return eConnectionStatusError; 754 } 755 m_uri.assign(socket_name); 756 return eConnectionStatusSuccess; 757 } 758 759 ConnectionStatus 760 ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr) 761 { 762 Socket *socket = nullptr; 763 Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket); 764 if (error_ptr) 765 *error_ptr = error; 766 m_write_sp.reset(socket); 767 m_read_sp = m_write_sp; 768 if (error.Fail()) 769 { 770 return eConnectionStatusError; 771 } 772 m_uri.assign(socket_name); 773 return eConnectionStatusSuccess; 774 } 775 776 ConnectionStatus 777 ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr) 778 { 779 m_port_predicate.SetValue(0, eBroadcastNever); 780 781 Socket *socket = nullptr; 782 m_waiting_for_accept = true; 783 Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate); 784 if (error_ptr) 785 *error_ptr = error; 786 if (error.Fail()) 787 return eConnectionStatusError; 788 789 std::unique_ptr<Socket> listening_socket_up; 790 791 listening_socket_up.reset(socket); 792 socket = nullptr; 793 error = listening_socket_up->BlockingAccept(s, m_child_processes_inherit, socket); 794 listening_socket_up.reset(); 795 if (error_ptr) 796 *error_ptr = error; 797 if (error.Fail()) 798 return eConnectionStatusError; 799 800 InitializeSocket(socket); 801 return eConnectionStatusSuccess; 802 } 803 804 ConnectionStatus 805 ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr) 806 { 807 Socket *socket = nullptr; 808 Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket); 809 if (error_ptr) 810 *error_ptr = error; 811 m_write_sp.reset(socket); 812 m_read_sp = m_write_sp; 813 if (error.Fail()) 814 { 815 return eConnectionStatusError; 816 } 817 m_uri.assign(s); 818 return eConnectionStatusSuccess; 819 } 820 821 ConnectionStatus 822 ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr) 823 { 824 Socket *send_socket = nullptr; 825 Socket *recv_socket = nullptr; 826 Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket); 827 if (error_ptr) 828 *error_ptr = error; 829 m_write_sp.reset(send_socket); 830 m_read_sp.reset(recv_socket); 831 if (error.Fail()) 832 { 833 return eConnectionStatusError; 834 } 835 m_uri.assign(s); 836 return eConnectionStatusSuccess; 837 } 838 839 uint16_t 840 ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec) 841 { 842 uint16_t bound_port = 0; 843 if (timeout_sec == UINT32_MAX) 844 m_port_predicate.WaitForValueNotEqualTo(0, bound_port); 845 else 846 { 847 TimeValue timeout = TimeValue::Now(); 848 timeout.OffsetWithSeconds(timeout_sec); 849 m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout); 850 } 851 return bound_port; 852 } 853 854 bool 855 ConnectionFileDescriptor::GetChildProcessesInherit() const 856 { 857 return m_child_processes_inherit; 858 } 859 860 void 861 ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit) 862 { 863 m_child_processes_inherit = child_processes_inherit; 864 } 865 866 void 867 ConnectionFileDescriptor::InitializeSocket(Socket* socket) 868 { 869 m_write_sp.reset(socket); 870 m_read_sp = m_write_sp; 871 StreamString strm; 872 strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber()); 873 m_uri.swap(strm.GetString()); 874 } 875