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