ConnectionFileDescriptor.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1//===-- ConnectionFileDescriptor.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#include "lldb/Core/ConnectionFileDescriptor.h" 11 12// C Includes 13#include <arpa/inet.h> 14#include <errno.h> 15#include <fcntl.h> 16#include <netdb.h> 17#include <netinet/in.h> 18#include <netinet/tcp.h> 19#include <sys/socket.h> 20#include <sys/types.h> 21 22// C++ Includes 23// Other libraries and framework includes 24// Project includes 25#include "lldb/lldb-private-log.h" 26#include "lldb/Core/Args.h" 27#include "lldb/Core/Communication.h" 28#include "lldb/Core/Log.h" 29#include "lldb/Core/RegularExpression.h" 30#include "lldb/Core/Timer.h" 31 32using namespace lldb; 33using namespace lldb_private; 34 35ConnectionFileDescriptor::ConnectionFileDescriptor () : 36 Connection(), 37 m_fd (-1), 38 m_should_close_fd (false) 39{ 40 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 41 "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", 42 this); 43} 44 45ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : 46 Connection(), 47 m_fd (fd), 48 m_should_close_fd (owns_fd) 49{ 50 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 51 "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", 52 this, fd, owns_fd); 53} 54 55 56ConnectionFileDescriptor::~ConnectionFileDescriptor () 57{ 58 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, 59 "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", 60 this); 61 Disconnect (NULL); 62} 63 64bool 65ConnectionFileDescriptor::IsConnected () const 66{ 67 return m_fd >= 0; 68} 69 70ConnectionStatus 71ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) 72{ 73 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 74 "%p ConnectionFileDescriptor::Connect (url = '%s')", 75 this, s); 76 77 if (s && s[0]) 78 { 79 char *end = NULL; 80 if (strstr(s, "listen://")) 81 { 82 // listen://HOST:PORT 83 unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0); 84 return SocketListen (listen_port, error_ptr); 85 } 86 else if (strstr(s, "connect://")) 87 { 88 return SocketConnect (s + strlen("connect://"), error_ptr); 89 } 90 else if (strstr(s, "file://")) 91 { 92 // file:///PATH 93 const char *path = s + strlen("file://"); 94 m_fd = ::open (path, O_RDWR); 95 if (m_fd == -1) 96 { 97 if (error_ptr) 98 error_ptr->SetErrorToErrno(); 99 return eConnectionStatusError; 100 } 101 102 int flags = ::fcntl (m_fd, F_GETFL, 0); 103 if (flags >= 0) 104 { 105 if ((flags & O_NONBLOCK) == 0) 106 { 107 flags |= O_NONBLOCK; 108 ::fcntl (m_fd, F_SETFL, flags); 109 } 110 } 111 m_should_close_fd = true; 112 return eConnectionStatusSuccess; 113 } 114 if (error_ptr) 115 error_ptr->SetErrorStringWithFormat ("Unsupported connection URL: '%s'.\n", s); 116 return eConnectionStatusError; 117 } 118 if (error_ptr) 119 error_ptr->SetErrorString("NULL connection URL."); 120 return eConnectionStatusError; 121} 122 123ConnectionStatus 124ConnectionFileDescriptor::Disconnect (Error *error_ptr) 125{ 126 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 127 "%p ConnectionFileDescriptor::Disconnect ()", 128 this); 129 if (m_should_close_fd == false) 130 { 131 m_fd = -1; 132 return eConnectionStatusSuccess; 133 } 134 return Close (m_fd, error_ptr); 135} 136 137size_t 138ConnectionFileDescriptor::Read (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr) 139{ 140 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION); 141 if (log) 142 log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...", 143 this, m_fd, dst, dst_len); 144 145 Error error; 146 ssize_t bytes_read = ::read (m_fd, dst, dst_len); 147 if (bytes_read == 0) 148 { 149 error.SetErrorStringWithFormat("End-of-file.\n"); 150 status = eConnectionStatusLostConnection; 151 } 152 else if (bytes_read < 0) 153 { 154 error.SetErrorToErrno(); 155 } 156 else 157 { 158 error.Clear(); 159 } 160 161 if (log) 162 log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s", 163 this, 164 m_fd, 165 dst, 166 dst_len, 167 bytes_read, 168 error.AsCString()); 169 170 if (error_ptr) 171 *error_ptr = error; 172 173 if (error.Fail()) 174 { 175 uint32_t error_value = error.GetError(); 176 switch (error_value) 177 { 178 case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. 179 status = eConnectionStatusSuccess; 180 return 0; 181 182 case EBADF: // fildes is not a valid file or socket descriptor open for reading. 183 case EFAULT: // Buf points outside the allocated address space. 184 case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal. 185 case EINVAL: // The pointer associated with fildes was negative. 186 case EIO: // An I/O error occurred while reading from the file system. 187 // The process group is orphaned. 188 // The file is a regular file, nbyte is greater than 0, 189 // the starting position is before the end-of-file, and 190 // the starting position is greater than or equal to the 191 // offset maximum established for the open file 192 // descriptor associated with fildes. 193 case EISDIR: // An attempt is made to read a directory. 194 case ENOBUFS: // An attempt to allocate a memory buffer fails. 195 case ENOMEM: // Insufficient memory is available. 196 status = eConnectionStatusError; 197 break; // Break to close.... 198 199 case ENXIO: // An action is requested of a device that does not exist.. 200 // A requested action cannot be performed by the device. 201 case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. 202 case ENOTCONN: // A read is attempted on an unconnected socket. 203 status = eConnectionStatusLostConnection; 204 break; // Break to close.... 205 206 case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket. 207 status = eConnectionStatusTimedOut; 208 return 0; 209 } 210 211// if (log) 212// error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread); 213 Close (m_fd, NULL); 214 return 0; 215 } 216 return bytes_read; 217} 218 219size_t 220ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 221{ 222 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION); 223 if (log) 224 log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %zu)", this, src, src_len); 225 226 if (!IsConnected ()) 227 { 228 if (error_ptr) 229 error_ptr->SetErrorString("Not connected."); 230 status = eConnectionStatusNoConnection; 231 return 0; 232 } 233 234 235 Error error; 236 237 ssize_t bytes_sent = 0; 238 239 if (m_is_socket) 240 bytes_sent = ::send (m_fd, src, src_len, 0); 241 else 242 bytes_sent = ::write (m_fd, src, src_len); 243 244 if (bytes_sent < 0) 245 error.SetErrorToErrno (); 246 else 247 error.Clear (); 248 249 if (log) 250 { 251 if (m_is_socket) 252 log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", 253 this, m_fd, src, src_len, bytes_sent, error.AsCString()); 254 else 255 log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)", 256 this, m_fd, src, src_len, bytes_sent, error.AsCString()); 257 } 258 259 if (error_ptr) 260 *error_ptr = error; 261 262 if (error.Fail()) 263 { 264 switch (error.GetError()) 265 { 266 case EAGAIN: 267 case EINTR: 268 status = eConnectionStatusSuccess; 269 return 0; 270 271 case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket. 272 case ENOTCONN: // A read is attempted on an unconnected socket. 273 status = eConnectionStatusLostConnection; 274 break; // Break to close.... 275 276 default: 277 status = eConnectionStatusError; 278 break; // Break to close.... 279 } 280 281 Close (m_fd, NULL); 282 return 0; 283 } 284 285 status = eConnectionStatusSuccess; 286 return bytes_sent; 287} 288 289ConnectionStatus 290ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) 291{ 292 Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION); 293 if (log) 294 log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec); 295 struct timeval *tv_ptr; 296 struct timeval tv; 297 if (timeout_usec == UINT32_MAX) 298 { 299 // Infinite wait... 300 tv_ptr = NULL; 301 } 302 else 303 { 304 TimeValue time_value; 305 time_value.OffsetWithMicroSeconds (timeout_usec); 306 tv = time_value.GetAsTimeVal(); 307 tv_ptr = &tv; 308 } 309 310 while (IsConnected()) 311 { 312 fd_set read_fds; 313 FD_ZERO (&read_fds); 314 FD_SET (m_fd, &read_fds); 315 int nfds = m_fd + 1; 316 317 Error error; 318 319 320 if (log) 321 log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...", 322 this, nfds, m_fd, tv_ptr); 323 324 const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr); 325 if (num_set_fds < 0) 326 error.SetErrorToErrno(); 327 else 328 error.Clear(); 329 330 if (log) 331 log->Printf("%p ConnectionFileDescriptor::Write() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s", 332 this, nfds, m_fd, tv_ptr, num_set_fds, error.AsCString()); 333 334 if (error_ptr) 335 *error_ptr = error; 336 337 if (error.Fail()) 338 { 339 switch (error.GetError()) 340 { 341 case EBADF: // One of the descriptor sets specified an invalid descriptor. 342 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. 343 default: // Other unknown error 344 return eConnectionStatusError; 345 346 case EAGAIN: // The kernel was (perhaps temporarily) unable to 347 // allocate the requested number of file descriptors, 348 // or we have non-blocking IO 349 case EINTR: // A signal was delivered before the time limit 350 // expired and before any of the selected events 351 // occurred. 352 break; // Lets keep reading to until we timeout 353 } 354 } 355 else if (num_set_fds == 0) 356 { 357 return eConnectionStatusTimedOut; 358 } 359 else if (num_set_fds > 0) 360 { 361 return eConnectionStatusSuccess; 362 } 363 } 364 365 if (error_ptr) 366 error_ptr->SetErrorString("Not connected."); 367 return eConnectionStatusLostConnection; 368} 369 370ConnectionStatus 371ConnectionFileDescriptor::Close (int& fd, Error *error_ptr) 372{ 373 if (error_ptr) 374 error_ptr->Clear(); 375 bool success = true; 376 if (fd >= 0) 377 { 378 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 379 "%p ConnectionFileDescriptor::Close (fd = %i)", 380 this, 381 fd); 382 383 success = ::close (fd) == 0; 384 if (!success && error_ptr) 385 { 386 // Only set the error if we have been asked to since something else 387 // might have caused us to try and shut down the connection and may 388 // have already set the error. 389 error_ptr->SetErrorToErrno(); 390 } 391 fd = -1; 392 } 393 m_is_socket = false; 394 if (success) 395 return eConnectionStatusSuccess; 396 else 397 return eConnectionStatusError; 398} 399 400ConnectionStatus 401ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr) 402{ 403 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 404 "%p ConnectionFileDescriptor::SocketListen (port = %i)", 405 this, listen_port_num); 406 407 Close (m_fd, false); 408 m_is_socket = true; 409 int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 410 if (listen_port == -1) 411 { 412 if (error_ptr) 413 error_ptr->SetErrorToErrno(); 414 return eConnectionStatusError; 415 } 416 417 // enable local address reuse 418 SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1); 419 420 struct sockaddr_in sa; 421 ::memset (&sa, 0, sizeof sa); 422 sa.sin_len = sizeof sa; 423 sa.sin_family = AF_INET; 424 sa.sin_port = htons (listen_port_num); 425 sa.sin_addr.s_addr = htonl (INADDR_ANY); 426 427 int err = ::bind (listen_port, (struct sockaddr *) &sa, sizeof(sa)); 428 if (err == -1) 429 { 430 if (error_ptr) 431 error_ptr->SetErrorToErrno(); 432 Close (listen_port, NULL); 433 return eConnectionStatusError; 434 } 435 436 err = ::listen (listen_port, 1); 437 if (err == -1) 438 { 439 if (error_ptr) 440 error_ptr->SetErrorToErrno(); 441 Close (listen_port, NULL); 442 return eConnectionStatusError; 443 } 444 445 m_fd = ::accept (listen_port, NULL, 0); 446 if (m_fd == -1) 447 { 448 if (error_ptr) 449 error_ptr->SetErrorToErrno(); 450 Close (listen_port, NULL); 451 return eConnectionStatusError; 452 } 453 454 // We are done with the listen port 455 Close (listen_port, NULL); 456 457 m_should_close_fd = true; 458 459 // Keep our TCP packets coming without any delays. 460 SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 461 if (error_ptr) 462 error_ptr->Clear(); 463 return eConnectionStatusSuccess; 464} 465 466ConnectionStatus 467ConnectionFileDescriptor::SocketConnect (const char *host_and_port, Error *error_ptr) 468{ 469 lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, 470 "%p ConnectionFileDescriptor::SocketConnect (host/port = %s)", 471 this, host_and_port); 472 Close (m_fd, false); 473 m_is_socket = true; 474 475 RegularExpression regex ("([^:]+):([0-9]+)"); 476 if (regex.Execute (host_and_port, 2) == false) 477 { 478 if (error_ptr) 479 error_ptr->SetErrorStringWithFormat("Invalid host:port specification: '%s'.\n", host_and_port); 480 return eConnectionStatusError; 481 } 482 std::string host_str; 483 std::string port_str; 484 if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false || 485 regex.GetMatchAtIndex (host_and_port, 2, port_str) == false) 486 { 487 if (error_ptr) 488 error_ptr->SetErrorStringWithFormat("Invalid host:port specification '%s'.\n", host_and_port); 489 return eConnectionStatusError; 490 } 491 492 int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); 493 if (port == INT32_MIN) 494 { 495 if (error_ptr) 496 error_ptr->SetErrorStringWithFormat("Invalid port '%s'.\n", port_str.c_str()); 497 return eConnectionStatusError; 498 } 499 // Create the socket 500 m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 501 if (m_fd == -1) 502 { 503 if (error_ptr) 504 error_ptr->SetErrorToErrno(); 505 return eConnectionStatusError; 506 } 507 508 m_should_close_fd = true; 509 510 // Enable local address reuse 511 SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); 512 513 struct sockaddr_in sa; 514 ::bzero (&sa, sizeof (sa)); 515 sa.sin_len = sizeof sa; 516 sa.sin_family = AF_INET; 517 sa.sin_port = htons (port); 518 519 int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); 520 521 if (inet_pton_result <= 0) 522 { 523 struct hostent *host_entry = gethostbyname (host_str.c_str()); 524 if (host_entry) 525 host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); 526 inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); 527 if (inet_pton_result <= 0) 528 { 529 530 if (error_ptr) 531 { 532 if (inet_pton_result == -1) 533 error_ptr->SetErrorToErrno(); 534 else 535 error_ptr->SetErrorStringWithFormat("Invalid host string: '%s'.\n", host_str.c_str()); 536 } 537 Close (m_fd, false); 538 return eConnectionStatusError; 539 } 540 } 541 542 if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) 543 { 544 if (error_ptr) 545 error_ptr->SetErrorToErrno(); 546 Close (m_fd, false); 547 return eConnectionStatusError; 548 } 549 550 // Keep our TCP packets coming without any delays. 551 SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); 552 if (error_ptr) 553 error_ptr->Clear(); 554 return eConnectionStatusSuccess; 555} 556 557int 558ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value) 559{ 560 return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value)); 561} 562 563 564