ConnectionFileDescriptorPosix.cpp revision 288943
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 50using namespace lldb; 51using namespace lldb_private; 52 53ConnectionFileDescriptor::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 66ConnectionFileDescriptor::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 84ConnectionFileDescriptor::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 95ConnectionFileDescriptor::~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 104void 105ConnectionFileDescriptor::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 126void 127ConnectionFileDescriptor::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 136bool 137ConnectionFileDescriptor::IsConnected() const 138{ 139 return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid()); 140} 141 142ConnectionStatus 143ConnectionFileDescriptor::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 313bool 314ConnectionFileDescriptor::InterruptRead() 315{ 316 size_t bytes_written = 0; 317 Error result = m_pipe.Write("i", 1, bytes_written); 318 return result.Success(); 319} 320 321ConnectionStatus 322ConnectionFileDescriptor::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 // Close any pipes we were using for async interrupts 376 m_pipe.Close(); 377 378 m_uri.clear(); 379 m_shutting_down = false; 380 return status; 381} 382 383size_t 384ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) 385{ 386 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 387 388 Mutex::Locker locker; 389 bool got_lock = locker.TryLock(m_mutex); 390 if (!got_lock) 391 { 392 if (log) 393 log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this)); 394 if (error_ptr) 395 error_ptr->SetErrorString("failed to get the connection lock for read."); 396 397 status = eConnectionStatusTimedOut; 398 return 0; 399 } 400 401 if (m_shutting_down) 402 { 403 status = eConnectionStatusError; 404 return 0; 405 } 406 407 status = BytesAvailable(timeout_usec, error_ptr); 408 if (status != eConnectionStatusSuccess) 409 return 0; 410 411 Error error; 412 size_t bytes_read = dst_len; 413 error = m_read_sp->Read(dst, bytes_read); 414 415 if (log) 416 { 417 log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s", 418 static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst), 419 static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString()); 420 } 421 422 if (bytes_read == 0) 423 { 424 error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. 425 status = eConnectionStatusEndOfFile; 426 } 427 428 if (error_ptr) 429 *error_ptr = error; 430 431 if (error.Fail()) 432 { 433 uint32_t error_value = error.GetError(); 434 switch (error_value) 435 { 436 case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. 437 if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket) 438 status = eConnectionStatusTimedOut; 439 else 440 status = eConnectionStatusSuccess; 441 return 0; 442 443 case EFAULT: // Buf points outside the allocated address space. 444 case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. 445 case EINVAL: // The pointer associated with fildes was negative. 446 case EIO: // An I/O error occurred while reading from the file system. 447 // The process group is orphaned. 448 // The file is a regular file, nbyte is greater than 0, 449 // the starting position is before the end-of-file, and 450 // the starting position is greater than or equal to the 451 // offset maximum established for the open file 452 // descriptor associated with fildes. 453 case EISDIR: // An attempt is made to read a directory. 454 case ENOBUFS: // An attempt to allocate a memory buffer fails. 455 case ENOMEM: // Insufficient memory is available. 456 status = eConnectionStatusError; 457 break; // Break to close.... 458 459 case ENOENT: // no such file or directory 460 case EBADF: // fildes is not a valid file or socket descriptor open for reading. 461 case ENXIO: // An action is requested of a device that does not exist.. 462 // A requested action cannot be performed by the device. 463 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. 464 case ENOTCONN: // A read is attempted on an unconnected socket. 465 status = eConnectionStatusLostConnection; 466 break; // Break to close.... 467 468 case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. 469 status = eConnectionStatusTimedOut; 470 return 0; 471 472 default: 473 if (log) 474 log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this), 475 strerror(error_value)); 476 status = eConnectionStatusError; 477 break; // Break to close.... 478 } 479 480 return 0; 481 } 482 return bytes_read; 483} 484 485size_t 486ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 487{ 488 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 489 if (log) 490 log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this), 491 static_cast<const void *>(src), static_cast<uint64_t>(src_len)); 492 493 if (!IsConnected()) 494 { 495 if (error_ptr) 496 error_ptr->SetErrorString("not connected"); 497 status = eConnectionStatusNoConnection; 498 return 0; 499 } 500 501 Error error; 502 503 size_t bytes_sent = src_len; 504 error = m_write_sp->Write(src, bytes_sent); 505 506 if (log) 507 { 508 log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)", 509 static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src), 510 static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString()); 511 } 512 513 if (error_ptr) 514 *error_ptr = error; 515 516 if (error.Fail()) 517 { 518 switch (error.GetError()) 519 { 520 case EAGAIN: 521 case EINTR: 522 status = eConnectionStatusSuccess; 523 return 0; 524 525 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket. 526 case ENOTCONN: // A read is attempted on an unconnected socket. 527 status = eConnectionStatusLostConnection; 528 break; // Break to close.... 529 530 default: 531 status = eConnectionStatusError; 532 break; // Break to close.... 533 } 534 535 return 0; 536 } 537 538 status = eConnectionStatusSuccess; 539 return bytes_sent; 540} 541 542std::string 543ConnectionFileDescriptor::GetURI() 544{ 545 return m_uri; 546} 547 548// This ConnectionFileDescriptor::BytesAvailable() uses select(). 549// 550// PROS: 551// - select is consistent across most unix platforms 552// - The Apple specific version allows for unlimited fds in the fd_sets by 553// setting the _DARWIN_UNLIMITED_SELECT define prior to including the 554// required header files. 555// CONS: 556// - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE. 557// This implementation will assert if it runs into that hard limit to let 558// users know that another ConnectionFileDescriptor::BytesAvailable() should 559// be used or a new version of ConnectionFileDescriptor::BytesAvailable() 560// should be written for the system that is running into the limitations. 561 562#if defined(__APPLE__) 563#define FD_SET_DATA(fds) fds.data() 564#else 565#define FD_SET_DATA(fds) &fds 566#endif 567 568ConnectionStatus 569ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr) 570{ 571 // Don't need to take the mutex here separately since we are only called from Read. If we 572 // ever get used more generally we will need to lock here as well. 573 574 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION)); 575 if (log) 576 log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec); 577 578 struct timeval *tv_ptr; 579 struct timeval tv; 580 if (timeout_usec == UINT32_MAX) 581 { 582 // Inifinite wait... 583 tv_ptr = nullptr; 584 } 585 else 586 { 587 TimeValue time_value; 588 time_value.OffsetWithMicroSeconds(timeout_usec); 589 tv.tv_sec = time_value.seconds(); 590 tv.tv_usec = time_value.microseconds(); 591 tv_ptr = &tv; 592 } 593 594 // Make a copy of the file descriptors to make sure we don't 595 // have another thread change these values out from under us 596 // and cause problems in the loop below where like in FS_SET() 597 const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle(); 598 const int pipe_fd = m_pipe.GetReadFileDescriptor(); 599 600 if (handle != IOObject::kInvalidHandleValue) 601 { 602#if defined(_MSC_VER) 603 // select() won't accept pipes on Windows. The entire Windows codepath needs to be 604 // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least 605 // this will allow ::select() to not return an error. 606 const bool have_pipe_fd = false; 607#else 608 const bool have_pipe_fd = pipe_fd >= 0; 609#if !defined(__APPLE__) 610 assert(handle < FD_SETSIZE); 611 if (have_pipe_fd) 612 assert(pipe_fd < FD_SETSIZE); 613#endif 614#endif 615 while (handle == m_read_sp->GetWaitableHandle()) 616 { 617 const int nfds = std::max<int>(handle, pipe_fd) + 1; 618#if defined(__APPLE__) 619 llvm::SmallVector<fd_set, 1> read_fds; 620 read_fds.resize((nfds / FD_SETSIZE) + 1); 621 for (size_t i = 0; i < read_fds.size(); ++i) 622 FD_ZERO(&read_fds[i]); 623// FD_SET doesn't bounds check, it just happily walks off the end 624// but we have taken care of making the extra storage with our 625// SmallVector of fd_set objects 626#else 627 fd_set read_fds; 628 FD_ZERO(&read_fds); 629#endif 630 FD_SET(handle, FD_SET_DATA(read_fds)); 631 if (have_pipe_fd) 632 FD_SET(pipe_fd, FD_SET_DATA(read_fds)); 633 634 Error error; 635 636 if (log) 637 { 638 if (have_pipe_fd) 639 log->Printf( 640 "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...", 641 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr)); 642 else 643 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...", 644 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr)); 645 } 646 647 const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr); 648 if (num_set_fds < 0) 649 error.SetErrorToErrno(); 650 else 651 error.Clear(); 652 653 if (log) 654 { 655 if (have_pipe_fd) 656 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) " 657 "=> %d, error = %s", 658 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds, 659 error.AsCString()); 660 else 661 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => " 662 "%d, error = %s", 663 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString()); 664 } 665 666 if (error_ptr) 667 *error_ptr = error; 668 669 if (error.Fail()) 670 { 671 switch (error.GetError()) 672 { 673 case EBADF: // One of the descriptor sets specified an invalid descriptor. 674 return eConnectionStatusLostConnection; 675 676 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. 677 default: // Other unknown error 678 return eConnectionStatusError; 679 680 case EAGAIN: // The kernel was (perhaps temporarily) unable to 681 // allocate the requested number of file descriptors, 682 // or we have non-blocking IO 683 case EINTR: // A signal was delivered before the time limit 684 // expired and before any of the selected events 685 // occurred. 686 break; // Lets keep reading to until we timeout 687 } 688 } 689 else if (num_set_fds == 0) 690 { 691 return eConnectionStatusTimedOut; 692 } 693 else if (num_set_fds > 0) 694 { 695 if (FD_ISSET(handle, FD_SET_DATA(read_fds))) 696 return eConnectionStatusSuccess; 697 if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds))) 698 { 699 // There is an interrupt or exit command in the command pipe 700 // Read the data from that pipe: 701 char buffer[1]; 702 703 ssize_t bytes_read; 704 705 do 706 { 707 bytes_read = ::read(pipe_fd, buffer, sizeof(buffer)); 708 } while (bytes_read < 0 && errno == EINTR); 709 710 switch (buffer[0]) 711 { 712 case 'q': 713 if (log) 714 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() " 715 "got data: %c from the command channel.", 716 static_cast<void *>(this), buffer[0]); 717 return eConnectionStatusEndOfFile; 718 case 'i': 719 // Interrupt the current read 720 return eConnectionStatusInterrupted; 721 } 722 } 723 } 724 } 725 } 726 727 if (error_ptr) 728 error_ptr->SetErrorString("not connected"); 729 return eConnectionStatusLostConnection; 730} 731 732ConnectionStatus 733ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr) 734{ 735 Socket *socket = nullptr; 736 Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket); 737 if (error_ptr) 738 *error_ptr = error; 739 m_write_sp.reset(socket); 740 m_read_sp = m_write_sp; 741 if (error.Fail()) 742 { 743 return eConnectionStatusError; 744 } 745 m_uri.assign(socket_name); 746 return eConnectionStatusSuccess; 747} 748 749ConnectionStatus 750ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr) 751{ 752 Socket *socket = nullptr; 753 Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket); 754 if (error_ptr) 755 *error_ptr = error; 756 m_write_sp.reset(socket); 757 m_read_sp = m_write_sp; 758 if (error.Fail()) 759 { 760 return eConnectionStatusError; 761 } 762 m_uri.assign(socket_name); 763 return eConnectionStatusSuccess; 764} 765 766ConnectionStatus 767ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr) 768{ 769 m_port_predicate.SetValue(0, eBroadcastNever); 770 771 Socket *socket = nullptr; 772 m_waiting_for_accept = true; 773 Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate); 774 if (error_ptr) 775 *error_ptr = error; 776 if (error.Fail()) 777 return eConnectionStatusError; 778 779 std::unique_ptr<Socket> listening_socket_up; 780 781 listening_socket_up.reset(socket); 782 socket = nullptr; 783 error = listening_socket_up->BlockingAccept(s, m_child_processes_inherit, socket); 784 listening_socket_up.reset(); 785 if (error_ptr) 786 *error_ptr = error; 787 if (error.Fail()) 788 return eConnectionStatusError; 789 790 InitializeSocket(socket); 791 return eConnectionStatusSuccess; 792} 793 794ConnectionStatus 795ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr) 796{ 797 Socket *socket = nullptr; 798 Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket); 799 if (error_ptr) 800 *error_ptr = error; 801 m_write_sp.reset(socket); 802 m_read_sp = m_write_sp; 803 if (error.Fail()) 804 { 805 return eConnectionStatusError; 806 } 807 m_uri.assign(s); 808 return eConnectionStatusSuccess; 809} 810 811ConnectionStatus 812ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr) 813{ 814 Socket *send_socket = nullptr; 815 Socket *recv_socket = nullptr; 816 Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket); 817 if (error_ptr) 818 *error_ptr = error; 819 m_write_sp.reset(send_socket); 820 m_read_sp.reset(recv_socket); 821 if (error.Fail()) 822 { 823 return eConnectionStatusError; 824 } 825 m_uri.assign(s); 826 return eConnectionStatusSuccess; 827} 828 829uint16_t 830ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec) 831{ 832 uint16_t bound_port = 0; 833 if (timeout_sec == UINT32_MAX) 834 m_port_predicate.WaitForValueNotEqualTo(0, bound_port); 835 else 836 { 837 TimeValue timeout = TimeValue::Now(); 838 timeout.OffsetWithSeconds(timeout_sec); 839 m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout); 840 } 841 return bound_port; 842} 843 844bool 845ConnectionFileDescriptor::GetChildProcessesInherit() const 846{ 847 return m_child_processes_inherit; 848} 849 850void 851ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit) 852{ 853 m_child_processes_inherit = child_processes_inherit; 854} 855 856void 857ConnectionFileDescriptor::InitializeSocket(Socket* socket) 858{ 859 m_write_sp.reset(socket); 860 m_read_sp = m_write_sp; 861 StreamString strm; 862 strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber()); 863 m_uri.swap(strm.GetString()); 864} 865