1 //===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #include "lldb/Core/ConnectionMachPort.h"
14 #include <mach/mach.h>
15 #include <servers/bootstrap.h>
18 // Other libraries and framework includes
20 #include "lldb/lldb-private-log.h"
21 #include "lldb/Core/Communication.h"
22 #include "lldb/Core/Log.h"
25 using namespace lldb_private;
29 mach_msg_header_t head;
30 ConnectionMachPort::PayloadType payload;
35 ConnectionMachPort::ConnectionMachPort () :
37 m_task(mach_task_self()),
38 m_port(MACH_PORT_TYPE_NONE)
42 ConnectionMachPort::~ConnectionMachPort ()
48 ConnectionMachPort::IsConnected () const
50 return m_port != MACH_PORT_TYPE_NONE;
54 ConnectionMachPort::Connect (const char *s, Error *error_ptr)
59 error_ptr->SetErrorString ("already connected");
60 return eConnectionStatusError;
63 if (s == NULL || s[0] == '\0')
66 error_ptr->SetErrorString ("empty connect URL");
67 return eConnectionStatusError;
70 ConnectionStatus status = eConnectionStatusError;
72 if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
74 s += strlen("bootstrap-checkin://");
78 status = BootstrapCheckIn (s, error_ptr);
83 error_ptr->SetErrorString ("bootstrap port name is empty");
86 else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
88 s += strlen("bootstrap-lookup://");
91 status = BootstrapLookup (s, error_ptr);
96 error_ptr->SetErrorString ("bootstrap port name is empty");
102 error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
106 if (status == eConnectionStatusSuccess)
120 ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
122 mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
124 /* Getting bootstrap server port */
125 kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
126 if (kret == KERN_SUCCESS)
129 int len = snprintf(port_name, sizeof(port_name), "%s", port);
130 if (len < sizeof(port_name))
132 kret = ::bootstrap_check_in (bootstrap_port,
140 error_ptr->SetErrorString ("bootstrap is too long");
141 return eConnectionStatusError;
145 if (kret != KERN_SUCCESS)
149 error_ptr->SetError (kret, eErrorTypeMachKernel);
150 return eConnectionStatusError;
152 return eConnectionStatusSuccess;
155 lldb::ConnectionStatus
156 ConnectionMachPort::BootstrapLookup (const char *port,
163 if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
166 error_ptr->SetErrorString ("port netname is too long");
167 return eConnectionStatusError;
173 error_ptr->SetErrorString ("empty port netname");
174 return eConnectionStatusError;
177 mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
179 /* Getting bootstrap server port */
180 kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
181 if (kret == KERN_SUCCESS)
183 kret = ::bootstrap_look_up (bootstrap_port,
188 if (kret != KERN_SUCCESS)
191 error_ptr->SetError (kret, eErrorTypeMachKernel);
192 return eConnectionStatusError;
195 return eConnectionStatusSuccess;
199 ConnectionMachPort::Disconnect (Error *error_ptr)
203 // TODO: verify if we need to netname_check_out for
205 if (m_port != MACH_PORT_TYPE_NONE)
207 kret = ::mach_port_deallocate (m_task, m_port);
209 error_ptr->SetError (kret, eErrorTypeMachKernel);
210 m_port = MACH_PORT_TYPE_NONE;
213 return eConnectionStatusSuccess;
217 ConnectionMachPort::Read (void *dst,
219 uint32_t timeout_usec,
220 ConnectionStatus &status,
225 kern_return_t kret = Receive (payload);
226 if (kret == KERN_SUCCESS)
228 memcpy (dst, payload.data, payload.data_length);
229 status = eConnectionStatusSuccess;
230 return payload.data_length;
234 error_ptr->SetError (kret, eErrorTypeMachKernel);
235 status = eConnectionStatusError;
240 ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
244 payload.data_length = src_len;
245 const size_t max_payload_size = sizeof(payload.data);
246 if (src_len > max_payload_size)
247 payload.data_length = max_payload_size;
248 memcpy (payload.data, src, payload.data_length);
250 if (Send (payload) == KERN_SUCCESS)
252 status = eConnectionStatusSuccess;
253 return payload.data_length;
255 status = eConnectionStatusError;
260 ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
262 return eConnectionStatusLostConnection;
266 ConnectionMachPort::Send (const PayloadType &payload)
268 struct MessageType message;
270 /* (i) Form the message : */
272 /* (i.a) Fill the header fields : */
273 message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) |
274 MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
275 message.head.msgh_size = sizeof(MessageType);
276 message.head.msgh_local_port = MACH_PORT_NULL;
277 message.head.msgh_remote_port = m_port;
279 /* (i.b) Explain the message type ( an integer ) */
280 // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
281 // message.type.msgt_size = 32;
282 // message.type.msgt_number = 1;
283 // message.type.msgt_inline = TRUE;
284 // message.type.msgt_longform = FALSE;
285 // message.type.msgt_deallocate = FALSE;
286 /* message.type.msgt_unused = 0; */ /* not needed, I think */
288 /* (i.c) Fill the message with the given integer : */
289 message.payload = payload;
291 /* (ii) Send the message : */
292 kern_return_t kret = ::mach_msg (&message.head,
294 message.head.msgh_size,
297 MACH_MSG_TIMEOUT_NONE,
304 ConnectionMachPort::Receive (PayloadType &payload)
307 message.head.msgh_size = sizeof(MessageType);
309 kern_return_t kret = ::mach_msg (&message.head,
314 MACH_MSG_TIMEOUT_NONE,
317 if (kret == KERN_SUCCESS)
318 payload = message.payload;
324 #endif // #if defined(__APPLE__)