VirtualBox

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

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

Debugger: fixed busy/ready.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1/* $Id: DBGCTcp.cpp 12880 2008-10-01 21:45:19Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, 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/** @copydoc FNDBGCBACKSETREADY */
172static DECLCALLBACK(void) dbgcTcpBackSetReady(PDBGCBACK pBack, bool fBusy)
173{
174 /* stub */
175 NOREF(pBack);
176 NOREF(fBusy);
177}
178
179
180/**
181 * Serve a TCP Server connection.
182 *
183 * @returns VBox status.
184 * @returns VERR_TCP_SERVER_STOP to terminate the server loop forcing
185 * the RTTcpCreateServer() call to return.
186 * @param Sock The socket which the client is connected to.
187 * The call will close this socket.
188 * @param pvUser The VM handle.
189 */
190static int dbgcTcpConnection(RTSOCKET Sock, void *pvUser)
191{
192 LogFlow(("dbgcTcpConnection: connection! Sock=%d pvUser=%p\n", Sock, pvUser));
193
194 /*
195 * Start the console.
196 */
197 DBGCTCP DbgcTcp;
198 DbgcTcp.Back.pfnInput = dbgcTcpBackInput;
199 DbgcTcp.Back.pfnRead = dbgcTcpBackRead;
200 DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite;
201 DbgcTcp.Back.pfnSetReady = dbgcTcpBackSetReady;
202 DbgcTcp.fAlive = true;
203 DbgcTcp.Sock = Sock;
204 int rc = DBGCCreate((PVM)pvUser, &DbgcTcp.Back, 0);
205 LogFlow(("dbgcTcpConnection: disconnect rc=%Vrc\n", rc));
206 return rc;
207}
208
209
210/**
211 * Spawns a new thread with a TCP based debugging console service.
212 *
213 * @returns VBox status.
214 * @param pVM VM handle.
215 * @param ppvData Where to store a pointer to the instance data.
216 */
217DBGDECL(int) DBGCTcpCreate(PVM pVM, void **ppvData)
218{
219 /*
220 * Check what the configuration says.
221 */
222 PCFGMNODE pKey = CFGMR3GetChild(CFGMR3GetRoot(pVM), "DBGC");
223 bool fEnabled;
224 int rc = CFGMR3QueryBool(pKey, "Enabled", &fEnabled);
225 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
226#if defined(VBOX_WITH_DEBUGGER) && !defined(__L4ENV__) && !defined(DEBUG_dmik)
227 fEnabled = true;
228#else
229 fEnabled = false;
230#endif
231 else if (VBOX_FAILURE(rc))
232 {
233 AssertMsgFailed(("Configuration error: Querying \"Enabled\" -> %Vrc\n", rc));
234 return rc;
235 }
236 if (!fEnabled)
237 {
238 LogFlow(("DBGCTcpCreate: returns VINF_SUCCESS (Disabled)\n"));
239 return VINF_SUCCESS;
240 }
241
242 /*
243 * Get the port configuration.
244 */
245 uint32_t u32Port;
246 rc = CFGMR3QueryU32(pKey, "Port", &u32Port);
247 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
248 u32Port = 5000;
249 else if (VBOX_FAILURE(rc))
250 {
251 AssertMsgFailed(("Configuration error: Querying \"Port\" -> %Vrc\n", rc));
252 return rc;
253 }
254
255 /*
256 * Get the address configuration.
257 */
258 char szAddress[512];
259 rc = CFGMR3QueryString(pKey, "Address", szAddress, sizeof(szAddress));
260 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
261 szAddress[0] = '\0';
262 else if (VBOX_FAILURE(rc))
263 {
264 AssertMsgFailed(("Configuration error: Querying \"Address\" -> %Vrc\n", rc));
265 return rc;
266 }
267
268 /*
269 * Create the server (separate thread).
270 */
271 PRTTCPSERVER pServer;
272 rc = RTTcpServerCreate(szAddress, u32Port, RTTHREADTYPE_DEBUGGER, "DBGC", dbgcTcpConnection, pVM, &pServer);
273 if (VBOX_SUCCESS(rc))
274 {
275 LogFlow(("DBGCTcpCreate: Created server on port %d %s\n", u32Port, szAddress));
276 *ppvData = pServer;
277 }
278
279 LogFlow(("DBGCTcpCreate: returns %Vrc\n", rc));
280 return rc;
281}
282
283
284/**
285 * Terminates any running TCP base debugger consolse service.
286 *
287 * @returns VBox status.
288 * @param pVM VM handle.
289 */
290DBGDECL(int) DBGCTcpTerminate(PVM pVM, void *pvData)
291{
292 /*
293 * Destroy the server instance if any.
294 */
295 if (pvData)
296 {
297 int rc = RTTcpServerDestroy((PRTTCPSERVER)pvData);
298 AssertRC(rc);
299 }
300
301 return VINF_SUCCESS;
302}
303
Note: See TracBrowser for help on using the repository browser.

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