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