VirtualBox

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

Last change on this file since 76882 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: DBGCTcp.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, TCP backend.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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_UOFFSETOF(DBGCTCP, Back)) )
54
55
56/*********************************************************************************************************************************
57* Internal Functions *
58*********************************************************************************************************************************/
59static DECLCALLBACK(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_SUCCESS(rc) && pcbRead != NULL && *pcbRead == 0)
105 rc = VERR_NET_SHUTDOWN;
106 if (RT_FAILURE(rc))
107 pDbgcTcp->fAlive = false;
108 return rc;
109}
110
111/**
112 * Write (output).
113 *
114 * @returns VBox status code.
115 * @param pBack Pointer to the backend structure supplied by
116 * the backend. The backend can use this to find
117 * it's instance data.
118 * @param pvBuf What to write.
119 * @param cbBuf Number of bytes to write.
120 * @param pcbWritten Where to store the number of bytes actually written.
121 * If NULL the entire buffer must be successfully written.
122 */
123static DECLCALLBACK(int) dbgcTcpBackWrite(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
124{
125 PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack);
126 if (!pDbgcTcp->fAlive)
127 return VERR_INVALID_HANDLE;
128
129 /*
130 * convert '\n' to '\r\n' while writing.
131 */
132 int rc = 0;
133 size_t cbLeft = cbBuf;
134 while (cbLeft)
135 {
136 size_t cb = cbLeft;
137 /* write newlines */
138 if (*(const char *)pvBuf == '\n')
139 {
140 rc = RTTcpWrite(pDbgcTcp->Sock, "\r\n", 2);
141 cb = 1;
142 }
143 /* write till next newline */
144 else
145 {
146 const char *pszNL = (const char *)memchr(pvBuf, '\n', cbLeft);
147 if (pszNL)
148 cb = (uintptr_t)pszNL - (uintptr_t)pvBuf;
149 rc = RTTcpWrite(pDbgcTcp->Sock, pvBuf, cb);
150 }
151 if (RT_FAILURE(rc))
152 {
153 pDbgcTcp->fAlive = false;
154 break;
155 }
156
157 /* advance */
158 cbLeft -= cb;
159 pvBuf = (const char *)pvBuf + cb;
160 }
161
162 /*
163 * Set returned value and return.
164 */
165 if (pcbWritten)
166 *pcbWritten = cbBuf - cbLeft;
167 return rc;
168}
169
170/** @copydoc FNDBGCBACKSETREADY */
171static DECLCALLBACK(void) dbgcTcpBackSetReady(PDBGCBACK pBack, bool fReady)
172{
173 /* stub */
174 NOREF(pBack);
175 NOREF(fReady);
176}
177
178
179/**
180 * Serve a TCP Server connection.
181 *
182 * @returns VBox status code.
183 * @returns VERR_TCP_SERVER_STOP to terminate the server loop forcing
184 * the RTTcpCreateServer() call to return.
185 * @param Sock The socket which the client is connected to.
186 * The call will close this socket.
187 * @param pvUser The VM handle.
188 */
189static DECLCALLBACK(int) dbgcTcpConnection(RTSOCKET Sock, void *pvUser)
190{
191 LogFlow(("dbgcTcpConnection: connection! Sock=%d pvUser=%p\n", Sock, pvUser));
192
193 /*
194 * Start the console.
195 */
196 DBGCTCP DbgcTcp;
197 DbgcTcp.Back.pfnInput = dbgcTcpBackInput;
198 DbgcTcp.Back.pfnRead = dbgcTcpBackRead;
199 DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite;
200 DbgcTcp.Back.pfnSetReady = dbgcTcpBackSetReady;
201 DbgcTcp.fAlive = true;
202 DbgcTcp.Sock = Sock;
203 int rc = DBGCCreate((PUVM)pvUser, &DbgcTcp.Back, 0);
204 LogFlow(("dbgcTcpConnection: disconnect rc=%Rrc\n", rc));
205 return rc;
206}
207
208
209/**
210 * Spawns a new thread with a TCP based debugging console service.
211 *
212 * @returns VBox status code.
213 * @param pUVM The user mode VM handle.
214 * @param ppvData Where to store a pointer to the instance data.
215 */
216DBGDECL(int) DBGCTcpCreate(PUVM pUVM, void **ppvData)
217{
218 /*
219 * Check what the configuration says.
220 */
221 PCFGMNODE pKey = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "DBGC");
222 bool fEnabled;
223 int rc = CFGMR3QueryBoolDef(pKey, "Enabled", &fEnabled,
224#if defined(VBOX_WITH_DEBUGGER) && defined(VBOX_WITH_DEBUGGER_TCP_BY_DEFAULT) && !defined(__L4ENV__) && !defined(DEBUG_dmik)
225 true
226#else
227 false
228#endif
229 );
230 if (RT_FAILURE(rc))
231 return VM_SET_ERROR_U(pUVM, rc, "Configuration error: Failed querying \"DBGC/Enabled\"");
232
233 if (!fEnabled)
234 {
235 LogFlow(("DBGCTcpCreate: returns VINF_SUCCESS (Disabled)\n"));
236 return VINF_SUCCESS;
237 }
238
239 /*
240 * Get the port configuration.
241 */
242 uint32_t u32Port;
243 rc = CFGMR3QueryU32Def(pKey, "Port", &u32Port, 5000);
244 if (RT_FAILURE(rc))
245 return VM_SET_ERROR_U(pUVM, rc, "Configuration error: Failed querying \"DBGC/Port\"");
246
247 /*
248 * Get the address configuration.
249 */
250 char szAddress[512];
251 rc = CFGMR3QueryStringDef(pKey, "Address", szAddress, sizeof(szAddress), "");
252 if (RT_FAILURE(rc))
253 return VM_SET_ERROR_U(pUVM, rc, "Configuration error: Failed querying \"DBGC/Address\"");
254
255 /*
256 * Create the server (separate thread).
257 */
258 PRTTCPSERVER pServer;
259 rc = RTTcpServerCreate(szAddress, u32Port, RTTHREADTYPE_DEBUGGER, "DBGC", dbgcTcpConnection, pUVM, &pServer);
260 if (RT_SUCCESS(rc))
261 {
262 LogFlow(("DBGCTcpCreate: Created server on port %d %s\n", u32Port, szAddress));
263 *ppvData = pServer;
264 return rc;
265 }
266
267 LogFlow(("DBGCTcpCreate: returns %Rrc\n", rc));
268 return VM_SET_ERROR_U(pUVM, rc, "Cannot start TCP-based debugging console service");
269}
270
271
272/**
273 * Terminates any running TCP base debugger console service.
274 *
275 * @returns VBox status code.
276 * @param pUVM The user mode VM handle.
277 * @param pvData The data returned by DBGCTcpCreate.
278 */
279DBGDECL(int) DBGCTcpTerminate(PUVM pUVM, void *pvData)
280{
281 RT_NOREF1(pUVM);
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