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