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
23 using namespace lldb;
24 using namespace lldb_private;
25
26 struct MessageType
27 {
28 mach_msg_header_t head;
29 ConnectionMachPort::PayloadType payload;
30 };
31
32
33
ConnectionMachPort()34 ConnectionMachPort::ConnectionMachPort () :
35 Connection(),
36 m_task(mach_task_self()),
37 m_port(MACH_PORT_TYPE_NONE)
38 {
39 }
40
~ConnectionMachPort()41 ConnectionMachPort::~ConnectionMachPort ()
42 {
43 Disconnect (NULL);
44 }
45
46 bool
IsConnected() const47 ConnectionMachPort::IsConnected () const
48 {
49 return m_port != MACH_PORT_TYPE_NONE;
50 }
51
52 ConnectionStatus
Connect(const char * s,Error * error_ptr)53 ConnectionMachPort::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
118 ConnectionStatus
BootstrapCheckIn(const char * port,Error * error_ptr)119 ConnectionMachPort::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
154 lldb::ConnectionStatus
BootstrapLookup(const char * port,Error * error_ptr)155 ConnectionMachPort::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
197 ConnectionStatus
Disconnect(Error * error_ptr)198 ConnectionMachPort::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
215 size_t
Read(void * dst,size_t dst_len,uint32_t timeout_usec,ConnectionStatus & status,Error * error_ptr)216 ConnectionMachPort::Read (void *dst,
217 size_t dst_len,
218 uint32_t timeout_usec,
219 ConnectionStatus &status,
220 Error *error_ptr)
221 {
222 PayloadType payload;
223
224 kern_return_t kret = Receive (payload);
225 if (kret == KERN_SUCCESS)
226 {
227 memcpy (dst, payload.data, payload.data_length);
228 status = eConnectionStatusSuccess;
229 return payload.data_length;
230 }
231
232 if (error_ptr)
233 error_ptr->SetError (kret, eErrorTypeMachKernel);
234 status = eConnectionStatusError;
235 return 0;
236 }
237
238 size_t
Write(const void * src,size_t src_len,ConnectionStatus & status,Error * error_ptr)239 ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
240 {
241 PayloadType payload;
242 payload.command = 0;
243 payload.data_length = src_len;
244 const size_t max_payload_size = sizeof(payload.data);
245 if (src_len > max_payload_size)
246 payload.data_length = max_payload_size;
247 memcpy (payload.data, src, payload.data_length);
248
249 if (Send (payload) == KERN_SUCCESS)
250 {
251 status = eConnectionStatusSuccess;
252 return payload.data_length;
253 }
254 status = eConnectionStatusError;
255 return 0;
256 }
257
258 ConnectionStatus
BytesAvailable(uint32_t timeout_usec,Error * error_ptr)259 ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
260 {
261 return eConnectionStatusLostConnection;
262 }
263
264 kern_return_t
Send(const PayloadType & payload)265 ConnectionMachPort::Send (const PayloadType &payload)
266 {
267 struct MessageType message;
268
269 /* (i) Form the message : */
270
271 /* (i.a) Fill the header fields : */
272 message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) |
273 MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
274 message.head.msgh_size = sizeof(MessageType);
275 message.head.msgh_local_port = MACH_PORT_NULL;
276 message.head.msgh_remote_port = m_port;
277
278 /* (i.b) Explain the message type ( an integer ) */
279 // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
280 // message.type.msgt_size = 32;
281 // message.type.msgt_number = 1;
282 // message.type.msgt_inline = TRUE;
283 // message.type.msgt_longform = FALSE;
284 // message.type.msgt_deallocate = FALSE;
285 /* message.type.msgt_unused = 0; */ /* not needed, I think */
286
287 /* (i.c) Fill the message with the given integer : */
288 message.payload = payload;
289
290 /* (ii) Send the message : */
291 kern_return_t kret = ::mach_msg (&message.head,
292 MACH_SEND_MSG,
293 message.head.msgh_size,
294 0,
295 MACH_PORT_NULL,
296 MACH_MSG_TIMEOUT_NONE,
297 MACH_PORT_NULL);
298
299 return kret;
300 }
301
302 kern_return_t
Receive(PayloadType & payload)303 ConnectionMachPort::Receive (PayloadType &payload)
304 {
305 MessageType message;
306 message.head.msgh_size = sizeof(MessageType);
307
308 kern_return_t kret = ::mach_msg (&message.head,
309 MACH_RCV_MSG,
310 0,
311 sizeof(MessageType),
312 m_port,
313 MACH_MSG_TIMEOUT_NONE,
314 MACH_PORT_NULL);
315
316 if (kret == KERN_SUCCESS)
317 payload = message.payload;
318
319 return kret;
320 }
321
322
323 #endif // #if defined(__APPLE__)
324