VirtualBox

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

Last change on this file since 50837 was 44399, checked in by vboxsync, 12 years ago

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

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