aboutsummaryrefslogtreecommitdiff
path: root/source/Core/ConnectionMachPort.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/ConnectionMachPort.cpp')
-rw-r--r--source/Core/ConnectionMachPort.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
new file mode 100644
index 000000000000..ca818d405a20
--- /dev/null
+++ b/source/Core/ConnectionMachPort.cpp
@@ -0,0 +1,323 @@
+//===-- 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__)