VirtualBox

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

Last change on this file since 31513 was 31510, checked in by vboxsync, 15 years ago

The debugger is back in the OSE.

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