VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCTcp.cpp@ 9262

Last change on this file since 9262 was 8827, checked in by vboxsync, 17 years ago

VBOX_WITH_DEBUGGER governs the telnet debugger, not DEBUG, since the qt bit doesn't work reliably on X and OS X.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1/** @file
2 *
3 * Debugger TCP backend
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <VBox/dbg.h>
26#include <VBox/cfgm.h>
27#include <VBox/err.h>
28
29#include <iprt/thread.h>
30#include <iprt/tcp.h>
31#include <VBox/log.h>
32#include <iprt/assert.h>
33
34#include <string.h>
35
36
37/*******************************************************************************
38* Structures and Typedefs *
39*******************************************************************************/
40/**
41 * Debug console TCP backend instance data.
42 */
43typedef struct DBGCTCP
44{
45 /** The I/O backend for the console. */
46 DBGCBACK Back;
47 /** The socket of the connection. */
48 RTSOCKET Sock;
49 /** Connection status. */
50 bool fAlive;
51} DBGCTCP;
52/** Pointer to the instance data of the console TCP backend. */
53typedef DBGCTCP *PDBGCTCP;
54
55/** Converts a pointer to DBGCTCP::Back to a pointer to DBGCTCP. */
56#define DBGCTCP_BACK2DBGCTCP(pBack) ( (PDBGCTCP)((char *)pBack - RT_OFFSETOF(DBGCTCP, Back)) )
57
58
59/*******************************************************************************
60* Internal Functions *
61*******************************************************************************/
62static int dbgcTcpConnection(RTSOCKET Sock, void *pvUser);
63
64
65
66/**
67 * Checks if there is input.
68 *
69 * @returns true if there is input ready.
70 * @returns false if there not input ready.
71 * @param pBack Pointer to the backend structure supplied by
72 * the backend. The backend can use this to find
73 * it's instance data.
74 * @param cMillies Number of milliseconds to wait on input data.
75 */
76static DECLCALLBACK(bool) dbgcTcpBackInput(PDBGCBACK pBack, uint32_t cMillies)
77{
78 PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack);
79 if (!pDbgcTcp->fAlive)
80 return false;
81 int rc = RTTcpSelectOne(pDbgcTcp->Sock, cMillies);
82 if (VBOX_FAILURE(rc) && rc != VERR_TIMEOUT)
83 pDbgcTcp->fAlive = false;
84 return rc != VERR_TIMEOUT;
85}
86
87
88/**
89 * Read input.
90 *
91 * @returns VBox status code.
92 * @param pBack Pointer to the backend structure supplied by
93 * the backend. The backend can use this to find
94 * it's instance data.
95 * @param pvBuf Where to put the bytes we read.
96 * @param cbBuf Maximum nymber of bytes to read.
97 * @param pcbRead Where to store the number of bytes actually read.
98 * If NULL the entire buffer must be filled for a
99 * successful return.
100 */
101static DECLCALLBACK(int) dbgcTcpBackRead(PDBGCBACK pBack, void *pvBuf, size_t cbBuf, size_t *pcbRead)
102{
103 PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack);
104 if (!pDbgcTcp->fAlive)
105 return VERR_INVALID_HANDLE;
106 int rc = RTTcpRead(pDbgcTcp->Sock, pvBuf, cbBuf, pcbRead);
107 if (VBOX_FAILURE(rc))
108 pDbgcTcp->fAlive = false;
109 return rc;
110}
111
112/**
113 * Write (output).
114 *
115 * @returns VBox status code.
116 * @param pBack Pointer to the backend structure supplied by
117 * the backend. The backend can use this to find
118 * it's instance data.
119 * @param pvBuf What to write.
120 * @param cbBuf Number of bytes to write.
121 * @param pcbWritten Where to store the number of bytes actually written.
122 * If NULL the entire buffer must be successfully written.
123 */
124static DECLCALLBACK(int) dbgcTcpBackWrite(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
125{
126 PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack);
127 if (!pDbgcTcp->fAlive)
128 return VERR_INVALID_HANDLE;
129
130 /*
131 * convert '\n' to '\r\n' while writing.
132 */
133 int rc = 0;
134 size_t cbLeft = cbBuf;
135 while (cbLeft)
136 {
137 size_t cb = cbLeft;
138 /* write newlines */
139 if (*(const char *)pvBuf == '\n')
140 {
141 rc = RTTcpWrite(pDbgcTcp->Sock, "\n\r", 2);
142 cb = 1;
143 }
144 /* write till next newline */
145 else
146 {
147 const char *pszNL = (const char *)memchr(pvBuf, '\n', cbLeft);
148 if (pszNL)
149 cb = (uintptr_t)pszNL - (uintptr_t)pvBuf;
150 rc = RTTcpWrite(pDbgcTcp->Sock, pvBuf, cb);
151 }
152 if (VBOX_FAILURE(rc))
153 {
154 pDbgcTcp->fAlive = false;
155 break;
156 }
157
158 /* advance */
159 cbLeft -= cb;
160 pvBuf = (const char *)pvBuf + cb;
161 }
162
163 /*
164 * Set returned value and return.
165 */
166 if (pcbWritten)
167 *pcbWritten = cbBuf - cbLeft;
168 return rc;
169}
170
171
172/**
173 * Serve a TCP Server connection.
174 *
175 * @returns VBox status.
176 * @returns VERR_TCP_SERVER_STOP to terminate the server loop forcing
177 * the RTTcpCreateServer() call to return.
178 * @param Sock The socket which the client is connected to.
179 * The call will close this socket.
180 * @param pvUser The VM handle.
181 */
182static int dbgcTcpConnection(RTSOCKET Sock, void *pvUser)
183{
184 LogFlow(("dbgcTcpConnection: connection! Sock=%d pvUser=%p\n", Sock, pvUser));
185
186 /*
187 * Start the console.
188 */
189 DBGCTCP DbgcTcp;
190 DbgcTcp.Back.pfnInput = dbgcTcpBackInput;
191 DbgcTcp.Back.pfnRead = dbgcTcpBackRead;
192 DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite;
193 DbgcTcp.fAlive = true;
194 DbgcTcp.Sock = Sock;
195 int rc = DBGCCreate((PVM)pvUser, &DbgcTcp.Back, 0);
196 LogFlow(("dbgcTcpConnection: disconnect rc=%Vrc\n", rc));
197 return rc;
198}
199
200
201/**
202 * Spawns a new thread with a TCP based debugging console service.
203 *
204 * @returns VBox status.
205 * @param pVM VM handle.
206 * @param ppvData Where to store a pointer to the instance data.
207 */
208DBGDECL(int) DBGCTcpCreate(PVM pVM, void **ppvData)
209{
210 /*
211 * Check what the configuration says.
212 */
213 PCFGMNODE pKey = CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGC");
214 bool fEnabled;
215 int rc = CFGMR3QueryBool(pKey, "Enabled", &fEnabled);
216 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
217#if defined(VBOX_WITH_DEBUGGER) && !defined(__L4ENV__) && !defined(DEBUG_dmik)
218 fEnabled = true;
219#else
220 fEnabled = false;
221#endif
222 else if (VBOX_FAILURE(rc))
223 {
224 AssertMsgFailed(("Configuration error: Querying \"Enabled\" -> %Vrc\n", rc));
225 return rc;
226 }
227 if (!fEnabled)
228 {
229 LogFlow(("DBGCTcpCreate: returns VINF_SUCCESS (Disabled)\n"));
230 return VINF_SUCCESS;
231 }
232
233 /*
234 * Get the port configuration.
235 */
236 uint32_t u32Port;
237 rc = CFGMR3QueryU32(pKey, "Port", &u32Port);
238 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
239 u32Port = 5000;
240 else if (VBOX_FAILURE(rc))
241 {
242 AssertMsgFailed(("Configuration error: Querying \"Port\" -> %Vrc\n", rc));
243 return rc;
244 }
245
246 /*
247 * Get the address configuration.
248 */
249 char szAddress[512];
250 rc = CFGMR3QueryString(pKey, "Address", szAddress, sizeof(szAddress));
251 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
252 szAddress[0] = '\0';
253 else if (VBOX_FAILURE(rc))
254 {
255 AssertMsgFailed(("Configuration error: Querying \"Address\" -> %Vrc\n", rc));
256 return rc;
257 }
258
259 /*
260 * Create the server (separate thread).
261 */
262 PRTTCPSERVER pServer;
263 rc = RTTcpServerCreate(szAddress, u32Port, RTTHREADTYPE_DEBUGGER, "DBGC", dbgcTcpConnection, pVM, &pServer);
264 if (VBOX_SUCCESS(rc))
265 {
266 LogFlow(("DBGCTcpCreate: Created server on port %d %s\n", u32Port, szAddress));
267 *ppvData = pServer;
268 }
269
270 LogFlow(("DBGCTcpCreate: returns %Vrc\n", rc));
271 return rc;
272}
273
274
275/**
276 * Terminates any running TCP base debugger consolse service.
277 *
278 * @returns VBox status.
279 * @param pVM VM handle.
280 */
281DBGDECL(int) DBGCTcpTerminate(PVM pVM, void *pvData)
282{
283 /*
284 * Destroy the server instance if any.
285 */
286 if (pvData)
287 {
288 int rc = RTTcpServerDestroy((PRTTCPSERVER)pvData);
289 AssertRC(rc);
290 }
291
292 return VINF_SUCCESS;
293}
294
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette