//===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined(__APPLE__) #include "lldb/Core/ConnectionMachPort.h" // C Includes #include <servers/bootstrap.h> // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" using namespace lldb; using namespace lldb_private; struct MessageType { mach_msg_header_t head; ConnectionMachPort::PayloadType payload; }; ConnectionMachPort::ConnectionMachPort () : Connection(), m_task(mach_task_self()), m_port(MACH_PORT_TYPE_NONE) { } ConnectionMachPort::~ConnectionMachPort () { Disconnect (NULL); } bool ConnectionMachPort::IsConnected () const { return m_port != MACH_PORT_TYPE_NONE; } ConnectionStatus ConnectionMachPort::Connect (const char *s, Error *error_ptr) { if (IsConnected()) { if (error_ptr) error_ptr->SetErrorString ("already connected"); return eConnectionStatusError; } if (s == NULL || s[0] == '\0') { if (error_ptr) error_ptr->SetErrorString ("empty connect URL"); return eConnectionStatusError; } ConnectionStatus status = eConnectionStatusError; if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://"))) { s += strlen("bootstrap-checkin://"); if (*s) { status = BootstrapCheckIn (s, error_ptr); } else { if (error_ptr) error_ptr->SetErrorString ("bootstrap port name is empty"); } } else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://"))) { s += strlen("bootstrap-lookup://"); if (*s) { status = BootstrapLookup (s, error_ptr); } else { if (error_ptr) error_ptr->SetErrorString ("bootstrap port name is empty"); } } else { if (error_ptr) error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s); } if (status == eConnectionStatusSuccess) { if (error_ptr) error_ptr->Clear(); } else { Disconnect(NULL); } return status; } ConnectionStatus ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr) { mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE; /* Getting bootstrap server port */ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); if (kret == KERN_SUCCESS) { name_t port_name; int len = snprintf(port_name, sizeof(port_name), "%s", port); if (len < sizeof(port_name)) { kret = ::bootstrap_check_in (bootstrap_port, port_name, &m_port); } else { Disconnect(NULL); if (error_ptr) error_ptr->SetErrorString ("bootstrap is too long"); return eConnectionStatusError; } } if (kret != KERN_SUCCESS) { Disconnect(NULL); if (error_ptr) error_ptr->SetError (kret, eErrorTypeMachKernel); return eConnectionStatusError; } return eConnectionStatusSuccess; } lldb::ConnectionStatus ConnectionMachPort::BootstrapLookup (const char *port, Error *error_ptr) { name_t port_name; if (port && port[0]) { if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name)) { if (error_ptr) error_ptr->SetErrorString ("port netname is too long"); return eConnectionStatusError; } } else { if (error_ptr) error_ptr->SetErrorString ("empty port netname"); return eConnectionStatusError; } mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE; /* Getting bootstrap server port */ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); if (kret == KERN_SUCCESS) { kret = ::bootstrap_look_up (bootstrap_port, port_name, &m_port); } if (kret != KERN_SUCCESS) { if (error_ptr) error_ptr->SetError (kret, eErrorTypeMachKernel); return eConnectionStatusError; } return eConnectionStatusSuccess; } ConnectionStatus ConnectionMachPort::Disconnect (Error *error_ptr) { kern_return_t kret; // TODO: verify if we need to netname_check_out for // either or both if (m_port != MACH_PORT_TYPE_NONE) { kret = ::mach_port_deallocate (m_task, m_port); if (error_ptr) error_ptr->SetError (kret, eErrorTypeMachKernel); m_port = MACH_PORT_TYPE_NONE; } return eConnectionStatusSuccess; } size_t ConnectionMachPort::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr) { PayloadType payload; kern_return_t kret = Receive (payload); if (kret == KERN_SUCCESS) { memcpy (dst, payload.data, payload.data_length); status = eConnectionStatusSuccess; return payload.data_length; } if (error_ptr) error_ptr->SetError (kret, eErrorTypeMachKernel); status = eConnectionStatusError; return 0; } size_t ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) { PayloadType payload; payload.command = 0; payload.data_length = src_len; const size_t max_payload_size = sizeof(payload.data); if (src_len > max_payload_size) payload.data_length = max_payload_size; memcpy (payload.data, src, payload.data_length); if (Send (payload) == KERN_SUCCESS) { status = eConnectionStatusSuccess; return payload.data_length; } status = eConnectionStatusError; return 0; } ConnectionStatus ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) { return eConnectionStatusLostConnection; } kern_return_t ConnectionMachPort::Send (const PayloadType &payload) { struct MessageType message; /* (i) Form the message : */ /* (i.a) Fill the header fields : */ message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) | MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX); message.head.msgh_size = sizeof(MessageType); message.head.msgh_local_port = MACH_PORT_NULL; message.head.msgh_remote_port = m_port; /* (i.b) Explain the message type ( an integer ) */ // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32; // message.type.msgt_size = 32; // message.type.msgt_number = 1; // message.type.msgt_inline = TRUE; // message.type.msgt_longform = FALSE; // message.type.msgt_deallocate = FALSE; /* message.type.msgt_unused = 0; */ /* not needed, I think */ /* (i.c) Fill the message with the given integer : */ message.payload = payload; /* (ii) Send the message : */ kern_return_t kret = ::mach_msg (&message.head, MACH_SEND_MSG, message.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); return kret; } kern_return_t ConnectionMachPort::Receive (PayloadType &payload) { MessageType message; message.head.msgh_size = sizeof(MessageType); kern_return_t kret = ::mach_msg (&message.head, MACH_RCV_MSG, 0, sizeof(MessageType), m_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kret == KERN_SUCCESS) payload = message.payload; return kret; } #endif // #if defined(__APPLE__)