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