VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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