• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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