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