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