ConnectionMachPort.cpp revision 06d7cc86937caca0acf2b990a02a641dc9c7579a
1//===-- ConnectionMachPort.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#if defined(__APPLE__) 10 11#include "lldb/Core/ConnectionMachPort.h" 12 13// C Includes 14#include <servers/bootstrap.h> 15 16// C++ Includes 17// Other libraries and framework includes 18// Project includes 19#include "lldb/lldb-private-log.h" 20#include "lldb/Core/Communication.h" 21#include "lldb/Core/Log.h" 22 23using namespace lldb; 24using namespace lldb_private; 25 26struct MessageType 27{ 28 mach_msg_header_t head; 29 ConnectionMachPort::PayloadType payload; 30}; 31 32 33 34ConnectionMachPort::ConnectionMachPort () : 35 Connection(), 36 m_task(mach_task_self()), 37 m_port(MACH_PORT_TYPE_NONE) 38{ 39} 40 41ConnectionMachPort::~ConnectionMachPort () 42{ 43 Disconnect (NULL); 44} 45 46bool 47ConnectionMachPort::IsConnected () const 48{ 49 return m_port != MACH_PORT_TYPE_NONE; 50} 51 52ConnectionStatus 53ConnectionMachPort::Connect (const char *s, Error *error_ptr) 54{ 55 if (IsConnected()) 56 { 57 if (error_ptr) 58 error_ptr->SetErrorString ("already connected"); 59 return eConnectionStatusError; 60 } 61 62 if (s == NULL || s[0] == '\0') 63 { 64 if (error_ptr) 65 error_ptr->SetErrorString ("empty connect URL"); 66 return eConnectionStatusError; 67 } 68 69 ConnectionStatus status = eConnectionStatusError; 70 71 if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://"))) 72 { 73 s += strlen("bootstrap-checkin://"); 74 75 if (*s) 76 { 77 status = BootstrapCheckIn (s, error_ptr); 78 } 79 else 80 { 81 if (error_ptr) 82 error_ptr->SetErrorString ("bootstrap port name is empty"); 83 } 84 } 85 else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://"))) 86 { 87 s += strlen("bootstrap-lookup://"); 88 if (*s) 89 { 90 status = BootstrapLookup (s, error_ptr); 91 } 92 else 93 { 94 if (error_ptr) 95 error_ptr->SetErrorString ("bootstrap port name is empty"); 96 } 97 } 98 else 99 { 100 if (error_ptr) 101 error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s); 102 } 103 104 105 if (status == eConnectionStatusSuccess) 106 { 107 if (error_ptr) 108 error_ptr->Clear(); 109 } 110 else 111 { 112 Disconnect(NULL); 113 } 114 115 return status; 116} 117 118ConnectionStatus 119ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr) 120{ 121 mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE; 122 123 /* Getting bootstrap server port */ 124 kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); 125 if (kret == KERN_SUCCESS) 126 { 127 name_t port_name; 128 int len = snprintf(port_name, sizeof(port_name), "%s", port); 129 if (len < sizeof(port_name)) 130 { 131 kret = ::bootstrap_check_in (bootstrap_port, 132 port_name, 133 &m_port); 134 } 135 else 136 { 137 Disconnect(NULL); 138 if (error_ptr) 139 error_ptr->SetErrorString ("bootstrap is too long"); 140 return eConnectionStatusError; 141 } 142 } 143 144 if (kret != KERN_SUCCESS) 145 { 146 Disconnect(NULL); 147 if (error_ptr) 148 error_ptr->SetError (kret, eErrorTypeMachKernel); 149 return eConnectionStatusError; 150 } 151 return eConnectionStatusSuccess; 152} 153 154lldb::ConnectionStatus 155ConnectionMachPort::BootstrapLookup (const char *port, 156 Error *error_ptr) 157{ 158 name_t port_name; 159 160 if (port && port[0]) 161 { 162 if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name)) 163 { 164 if (error_ptr) 165 error_ptr->SetErrorString ("port netname is too long"); 166 return eConnectionStatusError; 167 } 168 } 169 else 170 { 171 if (error_ptr) 172 error_ptr->SetErrorString ("empty port netname"); 173 return eConnectionStatusError; 174 } 175 176 mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE; 177 178 /* Getting bootstrap server port */ 179 kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); 180 if (kret == KERN_SUCCESS) 181 { 182 kret = ::bootstrap_look_up (bootstrap_port, 183 port_name, 184 &m_port); 185 } 186 187 if (kret != KERN_SUCCESS) 188 { 189 if (error_ptr) 190 error_ptr->SetError (kret, eErrorTypeMachKernel); 191 return eConnectionStatusError; 192 } 193 194 return eConnectionStatusSuccess; 195} 196 197ConnectionStatus 198ConnectionMachPort::Disconnect (Error *error_ptr) 199{ 200 kern_return_t kret; 201 202 // TODO: verify if we need to netname_check_out for 203 // either or both 204 if (m_port != MACH_PORT_TYPE_NONE) 205 { 206 kret = ::mach_port_deallocate (m_task, m_port); 207 if (error_ptr) 208 error_ptr->SetError (kret, eErrorTypeMachKernel); 209 m_port = MACH_PORT_TYPE_NONE; 210 } 211 212 return eConnectionStatusSuccess; 213} 214 215size_t 216ConnectionMachPort::Read (void *dst, size_t dst_len, ConnectionStatus &status, Error *error_ptr) 217{ 218 PayloadType payload; 219 220 kern_return_t kret = Receive (payload); 221 if (kret == KERN_SUCCESS) 222 { 223 memcpy (dst, payload.data, payload.data_length); 224 status = eConnectionStatusSuccess; 225 return payload.data_length; 226 } 227 228 if (error_ptr) 229 error_ptr->SetError (kret, eErrorTypeMachKernel); 230 status = eConnectionStatusError; 231 return 0; 232} 233 234size_t 235ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr) 236{ 237 PayloadType payload; 238 payload.command = 0; 239 payload.data_length = src_len; 240 const size_t max_payload_size = sizeof(payload.data); 241 if (src_len > max_payload_size) 242 payload.data_length = max_payload_size; 243 memcpy (payload.data, src, payload.data_length); 244 245 if (Send (payload) == KERN_SUCCESS) 246 { 247 status = eConnectionStatusSuccess; 248 return payload.data_length; 249 } 250 status = eConnectionStatusError; 251 return 0; 252} 253 254ConnectionStatus 255ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) 256{ 257 return eConnectionStatusLostConnection; 258} 259 260kern_return_t 261ConnectionMachPort::Send (const PayloadType &payload) 262{ 263 struct MessageType message; 264 265 /* (i) Form the message : */ 266 267 /* (i.a) Fill the header fields : */ 268 message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) | 269 MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX); 270 message.head.msgh_size = sizeof(MessageType); 271 message.head.msgh_local_port = MACH_PORT_NULL; 272 message.head.msgh_remote_port = m_port; 273 274 /* (i.b) Explain the message type ( an integer ) */ 275 // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32; 276 // message.type.msgt_size = 32; 277 // message.type.msgt_number = 1; 278 // message.type.msgt_inline = TRUE; 279 // message.type.msgt_longform = FALSE; 280 // message.type.msgt_deallocate = FALSE; 281 /* message.type.msgt_unused = 0; */ /* not needed, I think */ 282 283 /* (i.c) Fill the message with the given integer : */ 284 message.payload = payload; 285 286 /* (ii) Send the message : */ 287 kern_return_t kret = ::mach_msg (&message.head, 288 MACH_SEND_MSG, 289 message.head.msgh_size, 290 0, 291 MACH_PORT_NULL, 292 MACH_MSG_TIMEOUT_NONE, 293 MACH_PORT_NULL); 294 295 return kret; 296} 297 298kern_return_t 299ConnectionMachPort::Receive (PayloadType &payload) 300{ 301 MessageType message; 302 message.head.msgh_size = sizeof(MessageType); 303 304 kern_return_t kret = ::mach_msg (&message.head, 305 MACH_RCV_MSG, 306 0, 307 sizeof(MessageType), 308 m_port, 309 MACH_MSG_TIMEOUT_NONE, 310 MACH_PORT_NULL); 311 312 if (kret == KERN_SUCCESS) 313 payload = message.payload; 314 315 return kret; 316} 317 318 319#endif // #if defined(__APPLE__) 320