Changeset 68699 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Sep 7, 2017 3:12:54 PM (7 years ago)
- Location:
- trunk/src/VBox/Devices/Serial
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Serial/DrvChar.cpp
r68637 r68699 30 30 #include <iprt/asm.h> 31 31 #include <iprt/assert.h> 32 #include <iprt/poll.h> 32 33 #include <iprt/stream.h> 33 34 #include <iprt/semaphore.h> … … 40 41 * Defined Constants And Macros * 41 42 *********************************************************************************************************************************/ 42 /** Converts a pointer to DRVCHAR::ICharConnector to a PDRVCHAR. */43 #define PDMICHAR_2_DRVCHAR(pInterface) RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector)44 43 45 44 … … 64 63 /** Flag to notify the receive thread it should terminate. */ 65 64 volatile bool fShutdown; 66 /** Receive thread ID. */ 67 RTTHREAD ReceiveThread; 68 /** Send thread ID. */ 69 RTTHREAD SendThread; 70 /** Send event semaphore */ 71 RTSEMEVENT SendSem; 65 /** I/O thread. */ 66 PPDMTHREAD pThrdIo; 67 /** Thread to relay read data to the device above without 68 * blocking send operations. 69 * @todo: This has to go but needs changes in the interface 70 * between device and driver. 71 */ 72 PPDMTHREAD pThrdRead; 73 /** Event semaphore for the read relay thread. */ 74 RTSEMEVENT hEvtSemRead; 72 75 73 76 /** Internal send FIFO queue */ … … 75 78 bool volatile fSending; 76 79 uint8_t Alignment[2]; 80 81 /** Receive buffer. */ 82 uint8_t abBuffer[256]; 83 /** Number of bytes remaining in the receive buffer. */ 84 volatile size_t cbRemaining; 85 /** Current position into the read buffer. */ 86 uint8_t *pbBuf; 77 87 78 88 /** Read/write statistics */ … … 108 118 static DECLCALLBACK(int) drvCharWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite) 109 119 { 110 PDRVCHAR pThis = PDMICHAR_2_DRVCHAR(pInterface);120 PDRVCHAR pThis = RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector); 111 121 const char *pbBuffer = (const char *)pvBuf; 112 122 … … 119 129 120 130 pThis->u8SendByte = pbBuffer[i]; 121 RTSemEventSignal(pThis->SendSem);131 pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream); 122 132 STAM_COUNTER_INC(&pThis->StatBytesWritten); 123 133 } … … 133 143 { 134 144 RT_NOREF(pInterface, Bps, chParity, cDataBits, cStopBits); 135 /*PDRVCHAR pThis = PDMICHAR_2_DRVCHAR(pInterface); - unused*/136 145 137 146 LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits)); … … 140 149 141 150 142 /* -=-=-=-=- receivethread -=-=-=-=- */151 /* -=-=-=-=- I/O thread -=-=-=-=- */ 143 152 144 153 /** … … 149 158 * @param pvUser User argument. 150 159 */ 151 static DECLCALLBACK(int) drvCharSendLoop(RTTHREAD hThreadSelf, void *pvUser) 152 { 153 RT_NOREF(hThreadSelf); 154 PDRVCHAR pThis = (PDRVCHAR)pvUser; 155 156 int rc = VINF_SUCCESS; 157 while (!pThis->fShutdown) 160 static DECLCALLBACK(int) drvCharIoLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 161 { 162 RT_NOREF(pDrvIns); 163 PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser; 164 165 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 166 return VINF_SUCCESS; 167 168 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 158 169 { 159 RTMSINTERVAL cMillies = (rc == VERR_TIMEOUT) ? 50 : RT_INDEFINITE_WAIT; 160 rc = RTSemEventWait(pThis->SendSem, cMillies); 161 if ( RT_FAILURE(rc) 162 && rc != VERR_TIMEOUT) 163 break; 164 165 /* 166 * Write the character to the attached stream (if present). 167 */ 168 if ( pThis->fShutdown 169 || !pThis->pDrvStream) 170 break; 171 172 size_t cbProcessed = 1; 173 uint8_t ch = pThis->u8SendByte; 174 rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed); 170 uint32_t fEvts = 0; 171 172 if ( !pThis->cbRemaining 173 && pThis->pDrvStream->pfnRead) 174 fEvts |= RTPOLL_EVT_READ; 175 if (pThis->fSending) 176 fEvts |= RTPOLL_EVT_WRITE; 177 178 uint32_t fEvtsRecv = 0; 179 int rc = pThis->pDrvStream->pfnPoll(pThis->pDrvStream, fEvts, &fEvtsRecv, RT_INDEFINITE_WAIT); 175 180 if (RT_SUCCESS(rc)) 176 181 { 177 ASMAtomicXchgBool(&pThis->fSending, false); 178 Assert(cbProcessed == 1); 179 } 180 else if (rc == VERR_TIMEOUT) 181 { 182 /* Normal case, just means that the stream didn't accept a new 183 * character before the timeout elapsed. Just retry. */ 184 185 /* do not change the rc status here, otherwise the (rc == VERR_TIMEOUT) branch 186 * in the wait above will never get executed */ 187 /* rc = VINF_SUCCESS; */ 188 } 189 else 190 { 191 LogRel(("Write failed with %Rrc; skipping\n", rc)); 192 break; 193 } 194 } 195 196 return VINF_SUCCESS; 197 } 198 199 200 /* -=-=-=-=- receive thread -=-=-=-=- */ 201 202 /** 203 * Receive thread loop. 204 * 205 * @returns 0 on success. 206 * @param hThreadSelf Thread handle to this thread. 207 * @param pvUser User argument. 208 * 209 * @todo This thread isn't managed correctly wrt to the VM state. 210 * @todo This thread isn't managed correctly wrt to the VM state. 211 * @todo This thread isn't managed correctly wrt to the VM state. 212 * @todo This thread isn't managed correctly wrt to the VM state. 213 * @todo This thread isn't managed correctly wrt to the VM state. 214 * @todo This thread isn't managed correctly wrt to the VM state. 215 * @todo This thread isn't managed correctly wrt to the VM state. 216 * @todo This thread isn't managed correctly wrt to the VM state. 217 * @todo This thread isn't managed correctly wrt to the VM state. 218 * @todo This thread isn't managed correctly wrt to the VM state. 219 * @todo This thread isn't managed correctly wrt to the VM state. 220 * @todo This thread isn't managed correctly wrt to the VM state. 221 * @todo This thread isn't managed correctly wrt to the VM state. 222 * @todo This thread isn't managed correctly wrt to the VM state. 223 * @todo This thread isn't managed correctly wrt to the VM state. 224 * @todo This thread isn't managed correctly wrt to the VM state. 225 * @todo This thread isn't managed correctly wrt to the VM state. 226 * @todo This thread isn't managed correctly wrt to the VM state. 227 * @todo This thread isn't managed correctly wrt to the VM state. 228 * @todo This thread isn't managed correctly wrt to the VM state. 229 * @todo This thread isn't managed correctly wrt to the VM state. 230 * @todo This thread isn't managed correctly wrt to the VM state. 231 * @todo This thread isn't managed correctly wrt to the VM state. 232 * @todo This thread isn't managed correctly wrt to the VM state. 233 * @todo This thread isn't managed correctly wrt to the VM state. 234 * @todo This thread isn't managed correctly wrt to the VM state. 235 * @todo This thread isn't managed correctly wrt to the VM state. 236 * @todo This thread isn't managed correctly wrt to the VM state. 237 * @todo This thread isn't managed correctly wrt to the VM state. 238 * @todo This thread isn't managed correctly wrt to the VM state. 239 * @todo This thread isn't managed correctly wrt to the VM state. 240 * @todo This thread isn't managed correctly wrt to the VM state. 241 * 242 * It's possible to end up in the APIC code while the VM is being destroyed! 243 * @code 244 0:018> k 245 # Child-SP RetAddr Call Site 246 00 00000000`2061f1b0 00007ffe`42a889d9 VBoxVMM!apicReadRaw32+0x78 [e:\vbox\svn\trunk\src\vbox\vmm\vmmall\apicall.cpp @ 462] 247 01 00000000`2061f1f0 00007ffe`42916fc2 VBoxVMM!APICLocalInterrupt+0x189 [e:\vbox\svn\trunk\src\vbox\vmm\vmmall\apicall.cpp @ 2524] 248 02 00000000`2061f320 00007ffe`41b96937 VBoxVMM!pdmR3PicHlp_ClearInterruptFF+0x172 [e:\vbox\svn\trunk\src\vbox\vmm\vmmr3\pdmdevmischlp.cpp @ 67] 249 03 00000000`2061f360 00007ffe`41b961a8 VBoxDD!pic_update_irq+0x327 [e:\vbox\svn\trunk\src\vbox\devices\pc\devpic.cpp @ 318] 250 04 00000000`2061f3f0 00007ffe`42bcbaa3 VBoxDD!picSetIrq+0x2b8 [e:\vbox\svn\trunk\src\vbox\devices\pc\devpic.cpp @ 352] 251 05 00000000`2061f450 00007ffe`42905dff VBoxVMM!PDMIsaSetIrq+0xe3 [e:\vbox\svn\trunk\src\vbox\vmm\vmmall\pdmall.cpp @ 138] 252 06 00000000`2061f490 00007ffe`41c06db4 VBoxVMM!pdmR3DevHlp_ISASetIrq+0x2df [e:\vbox\svn\trunk\src\vbox\vmm\vmmr3\pdmdevhlp.cpp @ 1804] 253 07 00000000`2061f500 00007ffe`41c08d39 VBoxDD!PDMDevHlpISASetIrqNoWait+0x44 [e:\vbox\svn\trunk\include\vbox\vmm\pdmdev.h @ 4972] 254 08 00000000`2061f530 00007ffe`41c08a44 VBoxDD!serial_update_irq+0x1c9 [e:\vbox\svn\trunk\src\vbox\devices\serial\devserial.cpp @ 326] 255 09 00000000`2061f590 00007ffe`41c08814 VBoxDD!serial_receive+0x134 [e:\vbox\svn\trunk\src\vbox\devices\serial\devserial.cpp @ 718] 256 0a 00000000`2061f5d0 00007ffe`41c1d894 VBoxDD!serialNotifyRead+0x124 [e:\vbox\svn\trunk\src\vbox\devices\serial\devserial.cpp @ 744] 257 0b 00000000`2061f630 00007ffe`43a6250f VBoxDD!drvCharReceiveLoop+0x194 [e:\vbox\svn\trunk\src\vbox\devices\serial\drvchar.cpp @ 241] 258 0c 00000000`2061f800 00007ffe`43b8ddbf VBoxRT!rtThreadMain+0x1bf [e:\vbox\svn\trunk\src\vbox\runtime\common\misc\thread.cpp @ 717] 259 0d 00000000`2061f880 00000000`52971d9f VBoxRT!rtThreadNativeMain+0xcf [e:\vbox\svn\trunk\src\vbox\runtime\r3\win\thread-win.cpp @ 252] 260 0e 00000000`2061f8d0 00000000`52971e3b MSVCR100!endthreadex+0x43 261 @endcode 262 * 263 */ 264 static DECLCALLBACK(int) drvCharReceiveLoop(RTTHREAD hThreadSelf, void *pvUser) 265 { 266 RT_NOREF(hThreadSelf); 267 PDRVCHAR pThis = (PDRVCHAR)pvUser; 268 char abBuffer[256]; 269 char *pbRemaining = abBuffer; 270 size_t cbRemaining = 0; 271 int rc; 272 273 while (!pThis->fShutdown) 274 { 275 if (!cbRemaining) 276 { 277 /* Get block of data from stream driver. */ 278 if (pThis->pDrvStream) 182 if (fEvtsRecv & RTPOLL_EVT_WRITE) 279 183 { 280 pbRemaining = abBuffer; 281 cbRemaining = sizeof(abBuffer); 282 rc = pThis->pDrvStream->pfnRead(pThis->pDrvStream, abBuffer, &cbRemaining); 184 Assert(pThis->fSending); 185 186 size_t cbProcessed = 1; 187 uint8_t ch = pThis->u8SendByte; 188 rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed); 189 if (RT_SUCCESS(rc)) 190 { 191 ASMAtomicXchgBool(&pThis->fSending, false); 192 Assert(cbProcessed == 1); 193 } 194 else if (rc == VERR_TIMEOUT) 195 { 196 /* Normal case, just means that the stream didn't accept a new 197 * character before the timeout elapsed. Just retry. */ 198 199 /* do not change the rc status here, otherwise the (rc == VERR_TIMEOUT) branch 200 * in the wait above will never get executed */ 201 /* rc = VINF_SUCCESS; */ 202 } 203 else 204 { 205 LogRel(("Write failed with %Rrc; skipping\n", rc)); 206 break; 207 } 208 } 209 210 if (fEvtsRecv & RTPOLL_EVT_READ) 211 { 212 AssertPtr(pThis->pDrvStream->pfnRead); 213 Assert(!pThis->cbRemaining); 214 215 size_t cbRead = sizeof(pThis->abBuffer); 216 rc = pThis->pDrvStream->pfnRead(pThis->pDrvStream, &pThis->abBuffer[0], &cbRead); 283 217 if (RT_FAILURE(rc)) 284 218 { … … 286 220 break; 287 221 } 222 pThis->pbBuf = &pThis->abBuffer[0]; 223 ASMAtomicWriteZ(&pThis->cbRemaining, cbRead); 224 RTSemEventSignal(pThis->hEvtSemRead); /* Wakeup relay thread to continue. */ 288 225 } 289 else290 RTThreadSleep(100);291 226 } 292 else 227 else if (rc != VERR_INTERRUPTED) 228 LogRelMax(10, ("Char#%d: Polling failed with %Rrc\n", pDrvIns->iInstance, rc)); 229 } 230 231 return VINF_SUCCESS; 232 } 233 234 235 /** 236 * Unblock the send worker thread so it can respond to a state change. 237 * 238 * @returns VBox status code. 239 * @param pDrvIns The char driver instance. 240 * @param pThread The worker thread. 241 */ 242 static DECLCALLBACK(int) drvCharIoLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 243 { 244 PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser; 245 246 RT_NOREF(pDrvIns); 247 return pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream); 248 } 249 250 251 static DECLCALLBACK(int) drvCharReadRelayLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 252 { 253 RT_NOREF(pDrvIns); 254 PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser; 255 256 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 257 return VINF_SUCCESS; 258 259 int rc = VINF_SUCCESS; 260 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 261 { 262 size_t cbRem = ASMAtomicReadZ(&pThis->cbRemaining); 263 264 /* Block as long as there is nothing to relay. */ 265 if (!pThis->cbRemaining) 266 rc = RTSemEventWait(pThis->hEvtSemRead, RT_INDEFINITE_WAIT); 267 268 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 269 break; 270 271 cbRem = ASMAtomicReadZ(&pThis->cbRemaining); 272 if (cbRem) 293 273 { 294 274 /* Send data to guest. */ 295 size_t cbProcessed = cbRem aining;296 rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, p bRemaining, &cbProcessed);275 size_t cbProcessed = cbRem; 276 rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pThis->pbBuf, &cbProcessed); 297 277 if (RT_SUCCESS(rc)) 298 278 { 299 279 Assert(cbProcessed); 300 pbRemaining += cbProcessed; 301 cbRemaining -= cbProcessed; 280 pThis->pbBuf += cbProcessed; 281 282 /* Wake up the I/o thread so it can read new data to process. */ 283 cbRem = ASMAtomicSubZ(&pThis->cbRemaining, cbProcessed); 284 if (cbRem == cbProcessed) 285 pThis->pDrvStream->pfnPollInterrupt(pThis->pDrvStream); 302 286 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed); 303 287 } … … 321 305 322 306 /** 307 * Unblock the read relay worker thread so it can respond to a state change. 308 * 309 * @returns VBox status code. 310 * @param pDrvIns The char driver instance. 311 * @param pThread The worker thread. 312 */ 313 static DECLCALLBACK(int) drvCharReadRelayLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 314 { 315 PDRVCHAR pThis = (PDRVCHAR)pThread->pvUser; 316 317 RT_NOREF(pDrvIns); 318 return RTSemEventSignal(pThis->hEvtSemRead); 319 } 320 321 322 /** 323 323 * @callback_method_impl{PDMICHARCONNECTOR,pfnSetModemLines} 324 324 */ … … 358 358 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 359 359 360 /* 361 * Tell the threads to shut down. 362 */ 363 pThis->fShutdown = true; 364 if (pThis->SendSem != NIL_RTSEMEVENT) 360 if (pThis->hEvtSemRead != NIL_RTSEMEVENT) 365 361 { 366 RTSemEventSignal(pThis->SendSem); 367 pThis->SendSem = NIL_RTSEMEVENT; 368 } 369 370 /* 371 * Wait for the threads. 372 * ASSUMES that PDM destroys the driver chain from the bottom and up. 373 */ 374 if (pThis->ReceiveThread != NIL_RTTHREAD) 375 { 376 int rc = RTThreadWait(pThis->ReceiveThread, 30000, NULL); 377 if (RT_SUCCESS(rc)) 378 pThis->ReceiveThread = NIL_RTTHREAD; 379 else 380 LogRel(("Char%d: receive thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc)); 381 } 382 383 if (pThis->SendThread != NIL_RTTHREAD) 384 { 385 int rc = RTThreadWait(pThis->SendThread, 30000, NULL); 386 if (RT_SUCCESS(rc)) 387 pThis->SendThread = NIL_RTTHREAD; 388 else 389 LogRel(("Char%d: send thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc)); 390 } 391 392 if (pThis->SendSem != NIL_RTSEMEVENT) 393 { 394 RTSemEventDestroy(pThis->SendSem); 395 pThis->SendSem = NIL_RTSEMEVENT; 362 RTSemEventDestroy(pThis->hEvtSemRead); 363 pThis->hEvtSemRead = NIL_RTSEMEVENT; 396 364 } 397 365 } … … 413 381 * Init basic data members and interfaces. 414 382 */ 415 pThis-> fShutdown = false;416 pThis-> ReceiveThread= NIL_RTTHREAD;417 pThis-> SendThread= NIL_RTTHREAD;418 pThis-> SendSem= NIL_RTSEMEVENT;383 pThis->pDrvIns = pDrvIns; 384 pThis->pThrdIo = NIL_RTTHREAD; 385 pThis->pThrdRead = NIL_RTTHREAD; 386 pThis->hEvtSemRead = NIL_RTSEMEVENT; 419 387 /* IBase. */ 420 388 pDrvIns->IBase.pfnQueryInterface = drvCharQueryInterface; … … 443 411 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("Char#%d has no stream interface below"), pDrvIns->iInstance); 444 412 445 /* 446 * Don't start the receive thread if the driver doesn't support reading 447 */ 413 /* Don't start the receive relay thread if reading is not supported. */ 448 414 if (pThis->pDrvStream->pfnRead) 449 415 { 450 rc = RTThreadCreate(&pThis->ReceiveThread, drvCharReceiveLoop, (void *)pThis, 0,451 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "CharRecv");416 rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->pThrdRead, pThis, drvCharReadRelayLoop, 417 drvCharReadRelayLoopWakeup, 0, RTTHREADTYPE_IO, "CharReadRel"); 452 418 if (RT_FAILURE(rc)) 453 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create receive thread"), pDrvIns->iInstance); 419 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create read relay thread"), pDrvIns->iInstance); 420 421 rc = RTSemEventCreate(&pThis->hEvtSemRead); 422 AssertRCReturn(rc, rc); 454 423 } 455 424 456 rc = RTSemEventCreate(&pThis->SendSem); 457 AssertRCReturn(rc, rc); 458 459 rc = RTThreadCreate(&pThis->SendThread, drvCharSendLoop, (void *)pThis, 0, 460 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "CharSend"); 425 rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->pThrdIo, pThis, drvCharIoLoop, 426 drvCharIoLoopWakeup, 0, RTTHREADTYPE_IO, "CharIo"); 461 427 if (RT_FAILURE(rc)) 462 428 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create send thread"), pDrvIns->iInstance); -
trunk/src/VBox/Devices/Serial/DrvNamedPipe.cpp
r62956 r68699 1 /* $Id$ */1 /* $Id$ */ 2 2 /** @file 3 3 * Named pipe / local socket stream driver. … … 26 26 #include <iprt/stream.h> 27 27 #include <iprt/alloc.h> 28 #include <iprt/pipe.h> 29 #include <iprt/poll.h> 28 30 #include <iprt/string.h> 29 31 #include <iprt/semaphore.h> 32 #include <iprt/socket.h> 30 33 #include <iprt/uuid.h> 31 34 … … 49 52 * Defined Constants And Macros * 50 53 *********************************************************************************************************************************/ 51 /** Converts a pointer to DRVNAMEDPIPE::IMedia to a PDRVNAMEDPIPE. */ 52 #define PDMISTREAM_2_DRVNAMEDPIPE(pInterface) ( (PDRVNAMEDPIPE)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAMEDPIPE, IStream)) ) 53 54 55 #ifndef RT_OS_WINDOWS 56 # define DRVNAMEDPIPE_POLLSET_ID_SOCKET 0 57 # define DRVNAMEDPIPE_POLLSET_ID_WAKEUP 1 58 #endif 59 60 # define DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL 0 61 # define DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION 1 54 62 55 63 /********************************************************************************************************************************* … … 74 82 /** File handle of the named pipe. */ 75 83 HANDLE NamedPipe; 84 /** The wake event handle. */ 85 HANDLE hEvtWake; 76 86 /** Overlapped structure for writes. */ 77 87 OVERLAPPED OverlappedWrite; … … 80 90 /** Listen thread wakeup semaphore */ 81 91 RTSEMEVENTMULTI ListenSem; 92 /** Read buffer. */ 93 uint8_t abBufRead[32]; 94 /** Write buffer. */ 95 uint8_t abBufWrite[32]; 96 /** Read buffer currently used. */ 97 size_t cbReadBufUsed; 98 /** Size of the write buffer used. */ 99 size_t cbWriteBufUsed; 100 /** Flag whether a wake operation was caused by an external trigger. */ 101 volatile bool fWakeExternal; 102 /** Flag whether a read was started. */ 103 bool fReadPending; 82 104 #else /* !RT_OS_WINDOWS */ 105 /** Poll set used to wait for I/O events. */ 106 RTPOLLSET hPollSet; 107 /** Reading end of the wakeup pipe. */ 108 RTPIPE hPipeWakeR; 109 /** Writing end of the wakeup pipe. */ 110 RTPIPE hPipeWakeW; 111 /** Socket handle. */ 112 RTSOCKET hSock; 113 /** Flag whether the socket is in the pollset. */ 114 bool fSockInPollSet; 83 115 /** Socket handle of the local socket for server. */ 84 116 int LocalSocketServer; 85 /** Socket handle of the local socket. */86 int LocalSocket;87 117 #endif /* !RT_OS_WINDOWS */ 88 118 /** Thread for listening for new connections. */ … … 98 128 99 129 130 /** 131 * Kicks any possibly polling thread to get informed about changes. 132 * 133 * @returns VBOx status code. 134 * @param pThis The named pipe driver instance. 135 * @param bReason The reason code to handle. 136 */ 137 static int drvNamedPipePollerKick(PDRVNAMEDPIPE pThis, uint8_t bReason) 138 { 139 #ifdef RT_OS_WINDOWS 140 if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL) 141 ASMAtomicXchgBool(&pThis->fWakeExternal, true); 142 if (!SetEvent(pThis->hEvtWake)) 143 return RTErrConvertFromWin32(GetLastError()); 144 145 return VINF_SUCCESS; 146 #else 147 size_t cbWritten = 0; 148 return RTPipeWrite(pThis->hPipeWakeW, &bReason, 1, &cbWritten); 149 #endif 150 } 151 152 153 /** @interface_method_impl{PDMISTREAM,pfnPoll} */ 154 static DECLCALLBACK(int) drvNamedPipePoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies) 155 { 156 int rc = VINF_SUCCESS; 157 PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream); 158 159 LogFlowFunc(("pInterface=%#p fEvts=%#x pfEvts=%#p cMillies=%u\n", pInterface, fEvts, pfEvts, cMillies)); 160 161 #ifdef RT_OS_WINDOWS 162 /* Immediately return if there is something to read or no write pending and the respective events are set. */ 163 *pfEvts = 0; 164 if ( (fEvts & RTPOLL_EVT_READ) 165 && pThis->cbReadBufUsed > 0) 166 *pfEvts |= RTPOLL_EVT_READ; 167 if ( (fEvts & RTPOLL_EVT_WRITE) 168 && !pThis->cbWriteBufUsed) 169 *pfEvts |= RTPOLL_EVT_WRITE; 170 171 if (*pfEvts) 172 return VINF_SUCCESS; 173 174 while (RT_SUCCESS(rc)) 175 { 176 /* Set up the waiting handles. */ 177 HANDLE ahEvts[3]; 178 unsigned cEvts = 0; 179 180 ahEvts[cEvts++] = pThis->hEvtWake; 181 if (fEvts & RTPOLL_EVT_WRITE) 182 { 183 Assert(pThis->cbWriteBufUsed); 184 ahEvts[cEvts++] = pThis->OverlappedWrite.hEvent; 185 } 186 if ( (fEvts & RTPOLL_EVT_READ) 187 && pThis->NamedPipe != INVALID_HANDLE_VALUE 188 && !pThis->fReadPending) 189 { 190 Assert(!pThis->cbReadBufUsed); 191 192 DWORD cbReallyRead; 193 pThis->OverlappedRead.Offset = 0; 194 pThis->OverlappedRead.OffsetHigh = 0; 195 if (!ReadFile(pThis->NamedPipe, &pThis->abBufRead[0], sizeof(pThis->abBufRead), &cbReallyRead, &pThis->OverlappedRead)) 196 { 197 DWORD uError = GetLastError(); 198 199 if (uError == ERROR_IO_PENDING) 200 { 201 uError = 0; 202 pThis->fReadPending = true; 203 } 204 205 if ( uError == ERROR_PIPE_LISTENING 206 || uError == ERROR_PIPE_NOT_CONNECTED) 207 { 208 /* No connection yet/anymore */ 209 cbReallyRead = 0; 210 } 211 else 212 { 213 rc = RTErrConvertFromWin32(uError); 214 Log(("drvNamedPipePoll: ReadFile returned %d (%Rrc)\n", uError, rc)); 215 } 216 } 217 else 218 { 219 LogFlowFunc(("Read completed: cbReallyRead=%u\n", cbReallyRead)); 220 pThis->fReadPending = false; 221 *pfEvts |= RTPOLL_EVT_READ; 222 return VINF_SUCCESS; 223 } 224 225 if (RT_FAILURE(rc)) 226 { 227 Log(("drvNamedPipePoll: FileRead returned %Rrc fShutdown=%d\n", rc, pThis->fShutdown)); 228 if ( !pThis->fShutdown 229 && ( rc == VERR_EOF 230 || rc == VERR_BROKEN_PIPE 231 ) 232 ) 233 { 234 FlushFileBuffers(pThis->NamedPipe); 235 DisconnectNamedPipe(pThis->NamedPipe); 236 if (!pThis->fIsServer) 237 { 238 CloseHandle(pThis->NamedPipe); 239 pThis->NamedPipe = INVALID_HANDLE_VALUE; 240 } 241 /* pretend success */ 242 rc = VINF_SUCCESS; 243 } 244 cbReallyRead = 0; 245 } 246 } 247 248 if (pThis->fReadPending) 249 ahEvts[cEvts++] = pThis->OverlappedRead.hEvent; 250 251 DWORD dwMillies = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies; 252 DWORD uErr = WaitForMultipleObjects(cEvts, &ahEvts[0], FALSE /* bWaitAll */, dwMillies); 253 if (uErr == WAIT_TIMEOUT) 254 rc = VERR_TIMEOUT; 255 else if (uErr == WAIT_FAILED) 256 rc = RTErrConvertFromWin32(GetLastError()); 257 else 258 { 259 /* Something triggered. */ 260 unsigned idxEvt = uErr - WAIT_OBJECT_0; 261 Assert(idxEvt < cEvts); 262 263 LogFlowFunc(("Interrupted by pipe activity: idxEvt=%u\n", idxEvt)); 264 265 if (idxEvt == 0) 266 { 267 /* The wakeup triggered. */ 268 if (ASMAtomicXchgBool(&pThis->fWakeExternal, false)) 269 rc = VERR_INTERRUPTED; 270 else 271 { 272 /* 273 * Internal event because there was a new connection from the listener thread, 274 * restart everything. 275 */ 276 rc = VINF_SUCCESS; 277 } 278 } 279 else if (ahEvts[idxEvt] == pThis->OverlappedWrite.hEvent) 280 { 281 LogFlowFunc(("Write completed\n")); 282 /* Fetch the result of the write. */ 283 DWORD cbWritten = 0; 284 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedWrite, &cbWritten, TRUE) == FALSE) 285 { 286 uErr = GetLastError(); 287 rc = RTErrConvertFromWin32(uErr); 288 Log(("drvNamedPipePoll: Write completed with %d (%Rrc)\n", uErr, rc)); 289 290 if (RT_FAILURE(rc)) 291 { 292 /** @todo WriteFile(pipe) has been observed to return ERROR_NO_DATA 293 * (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is 294 * disconnected. */ 295 if ( rc == VERR_EOF 296 || rc == VERR_BROKEN_PIPE) 297 { 298 FlushFileBuffers(pThis->NamedPipe); 299 DisconnectNamedPipe(pThis->NamedPipe); 300 if (!pThis->fIsServer) 301 { 302 CloseHandle(pThis->NamedPipe); 303 pThis->NamedPipe = INVALID_HANDLE_VALUE; 304 } 305 /* pretend success */ 306 rc = VINF_SUCCESS; 307 } 308 cbWritten = (DWORD)pThis->cbWriteBufUsed; 309 } 310 } 311 312 pThis->cbWriteBufUsed -= cbWritten; 313 if (!pThis->cbWriteBufUsed && (fEvts & RTPOLL_EVT_WRITE)) 314 { 315 *pfEvts |= RTPOLL_EVT_WRITE; 316 break; 317 } 318 } 319 else 320 { 321 Assert(ahEvts[idxEvt] == pThis->OverlappedRead.hEvent); 322 323 DWORD cbRead = 0; 324 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedRead, &cbRead, TRUE) == FALSE) 325 { 326 uErr = GetLastError(); 327 rc = RTErrConvertFromWin32(uErr); 328 Log(("drvNamedPipePoll: Read completed with %d (%Rrc)\n", uErr, rc)); 329 330 if (RT_FAILURE(rc)) 331 { 332 /** @todo WriteFile(pipe) has been observed to return ERROR_NO_DATA 333 * (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is 334 * disconnected. */ 335 if ( rc == VERR_EOF 336 || rc == VERR_BROKEN_PIPE) 337 { 338 FlushFileBuffers(pThis->NamedPipe); 339 DisconnectNamedPipe(pThis->NamedPipe); 340 if (!pThis->fIsServer) 341 { 342 CloseHandle(pThis->NamedPipe); 343 pThis->NamedPipe = INVALID_HANDLE_VALUE; 344 } 345 /* pretend success */ 346 rc = VINF_SUCCESS; 347 } 348 cbRead = 0; 349 } 350 } 351 352 LogFlowFunc(("Read completed with cbRead=%u\n", cbRead)); 353 pThis->fReadPending = false; 354 pThis->cbReadBufUsed = cbRead; 355 if (pThis->cbReadBufUsed && (fEvts & RTPOLL_EVT_READ)) 356 { 357 *pfEvts |= RTPOLL_EVT_READ; 358 break; 359 } 360 } 361 } 362 } 363 #else 364 if (pThis->hSock != NIL_RTSOCKET) 365 { 366 if (!pThis->fSockInPollSet) 367 { 368 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hSock, 369 fEvts, DRVNAMEDPIPE_POLLSET_ID_SOCKET); 370 if (RT_SUCCESS(rc)) 371 pThis->fSockInPollSet = true; 372 } 373 else 374 { 375 /* Always include error event. */ 376 fEvts |= RTPOLL_EVT_ERROR; 377 rc = RTPollSetEventsChange(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET, fEvts); 378 AssertRC(rc); 379 } 380 } 381 382 while (RT_SUCCESS(rc)) 383 { 384 uint32_t fEvtsRecv = 0; 385 uint32_t idHnd = 0; 386 387 rc = RTPoll(pThis->hPollSet, cMillies, &fEvtsRecv, &idHnd); 388 if (RT_SUCCESS(rc)) 389 { 390 if (idHnd == DRVNAMEDPIPE_POLLSET_ID_WAKEUP) 391 { 392 /* We got woken up, drain the pipe and return. */ 393 uint8_t bReason; 394 size_t cbRead = 0; 395 rc = RTPipeRead(pThis->hPipeWakeR, &bReason, 1, &cbRead); 396 AssertRC(rc); 397 398 if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL) 399 rc = VERR_INTERRUPTED; 400 else if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION) 401 { 402 Assert(!pThis->fSockInPollSet); 403 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hSock, 404 fEvts, DRVNAMEDPIPE_POLLSET_ID_SOCKET); 405 if (RT_SUCCESS(rc)) 406 pThis->fSockInPollSet = true; 407 } 408 else 409 AssertMsgFailed(("Unknown wakeup reason in pipe %u\n", bReason)); 410 } 411 else 412 { 413 Assert(idHnd == DRVNAMEDPIPE_POLLSET_ID_SOCKET); 414 415 /* On error we close the socket here. */ 416 if (fEvtsRecv & RTPOLL_EVT_ERROR) 417 { 418 rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET); 419 AssertRC(rc); 420 421 RTSocketClose(pThis->hSock); 422 pThis->hSock = NIL_RTSOCKET; 423 pThis->fSockInPollSet = false; 424 /* Continue with polling. */ 425 } 426 else 427 { 428 *pfEvts = fEvtsRecv; 429 break; 430 } 431 } 432 } 433 } 434 #endif 435 436 LogFlowFunc(("returns %Rrc\n", rc)); 437 return rc; 438 } 439 440 441 /** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */ 442 static DECLCALLBACK(int) drvNamedPipePollInterrupt(PPDMISTREAM pInterface) 443 { 444 PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream); 445 return drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL); 446 } 447 448 100 449 /** @interface_method_impl{PDMISTREAM,pfnRead} */ 101 450 static DECLCALLBACK(int) drvNamedPipeRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead) 102 451 { 103 452 int rc = VINF_SUCCESS; 104 PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);453 PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream); 105 454 LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation)); 106 455 … … 109 458 if (pThis->NamedPipe != INVALID_HANDLE_VALUE) 110 459 { 111 DWORD cbReallyRead; 112 pThis->OverlappedRead.Offset = 0; 113 pThis->OverlappedRead.OffsetHigh = 0; 114 if (!ReadFile(pThis->NamedPipe, pvBuf, (DWORD)*pcbRead, &cbReallyRead, &pThis->OverlappedRead)) 115 { 116 DWORD uError = GetLastError(); 117 118 if (uError == ERROR_IO_PENDING) 119 { 120 uError = 0; 121 122 /* Wait for incoming bytes. */ 123 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedRead, &cbReallyRead, TRUE) == FALSE) 124 uError = GetLastError(); 125 } 126 127 if ( uError == ERROR_PIPE_LISTENING 128 || uError == ERROR_PIPE_NOT_CONNECTED) 129 { 130 /* No connection yet/anymore */ 131 cbReallyRead = 0; 132 133 /* wait a bit or else we'll be called right back. */ 134 RTThreadSleep(100); 135 } 136 else 137 { 138 rc = RTErrConvertFromWin32(uError); 139 Log(("drvNamedPipeRead: ReadFile returned %d (%Rrc)\n", uError, rc)); 140 } 141 } 142 143 if (RT_FAILURE(rc)) 144 { 145 Log(("drvNamedPipeRead: FileRead returned %Rrc fShutdown=%d\n", rc, pThis->fShutdown)); 146 if ( !pThis->fShutdown 147 && ( rc == VERR_EOF 148 || rc == VERR_BROKEN_PIPE 149 ) 150 ) 151 { 152 FlushFileBuffers(pThis->NamedPipe); 153 DisconnectNamedPipe(pThis->NamedPipe); 154 if (!pThis->fIsServer) 155 { 156 CloseHandle(pThis->NamedPipe); 157 pThis->NamedPipe = INVALID_HANDLE_VALUE; 158 } 159 /* pretend success */ 460 /* Check if there is something in the read buffer and return as much as we can. */ 461 if (pThis->cbReadBufUsed) 462 { 463 size_t cbRead = RT_MIN(*pcbRead, pThis->cbReadBufUsed); 464 465 memcpy(pvBuf, &pThis->abBufRead[0], cbRead); 466 if (cbRead < pThis->cbReadBufUsed) 467 memmove(&pThis->abBufRead[0], &pThis->abBufRead[cbRead], pThis->cbReadBufUsed - cbRead); 468 pThis->cbReadBufUsed -= cbRead; 469 *pcbRead = cbRead; 470 } 471 else 472 *pcbRead = 0; 473 } 474 #else /* !RT_OS_WINDOWS */ 475 if (pThis->hSock != NIL_RTSOCKET) 476 { 477 size_t cbRead; 478 size_t cbBuf = *pcbRead; 479 rc = RTSocketReadNB(pThis->hSock, pvBuf, cbBuf, &cbRead); 480 if (RT_SUCCESS(rc)) 481 { 482 if (!cbRead && rc != VINF_TRY_AGAIN) 483 { 484 rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET); 485 AssertRC(rc); 486 487 RTSocketClose(pThis->hSock); 488 pThis->hSock = NIL_RTSOCKET; 489 pThis->fSockInPollSet = false; 160 490 rc = VINF_SUCCESS; 161 491 } 162 cbReallyRead = 0; 163 } 164 *pcbRead = (size_t)cbReallyRead; 165 } 166 #else /* !RT_OS_WINDOWS */ 167 if (pThis->LocalSocket != -1) 168 { 169 ssize_t cbReallyRead; 170 cbReallyRead = recv(pThis->LocalSocket, pvBuf, *pcbRead, 0); 171 if (cbReallyRead == 0) 172 { 173 int tmp = pThis->LocalSocket; 174 pThis->LocalSocket = -1; 175 close(tmp); 176 } 177 else if (cbReallyRead == -1) 178 { 179 cbReallyRead = 0; 180 rc = RTErrConvertFromErrno(errno); 181 } 182 *pcbRead = cbReallyRead; 492 *pcbRead = cbRead; 493 } 183 494 } 184 495 #endif /* !RT_OS_WINDOWS */ … … 198 509 { 199 510 int rc = VINF_SUCCESS; 200 PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);511 PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream); 201 512 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation)); 202 513 … … 205 516 if (pThis->NamedPipe != INVALID_HANDLE_VALUE) 206 517 { 207 DWORD cbWritten = (DWORD)*pcbWrite; 208 pThis->OverlappedWrite.Offset = 0; 209 pThis->OverlappedWrite.OffsetHigh = 0; 210 if (!WriteFile(pThis->NamedPipe, pvBuf, cbWritten, NULL, &pThis->OverlappedWrite)) 211 { 212 DWORD uError = GetLastError(); 213 214 if ( uError == ERROR_PIPE_LISTENING 215 || uError == ERROR_PIPE_NOT_CONNECTED) 216 { 217 /* No connection yet/anymore; just discard the write (pretending everything was written). */; 218 } 219 else if (uError != ERROR_IO_PENDING) 220 { 221 rc = RTErrConvertFromWin32(uError); 222 Log(("drvNamedPipeWrite: WriteFile returned %d (%Rrc)\n", uError, rc)); 223 cbWritten = 0; 224 } 225 else 226 { 227 /* Wait for the write to complete. */ 228 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedWrite, &cbWritten, TRUE /*bWait*/) == FALSE) 229 rc = RTErrConvertFromWin32(uError = GetLastError()); 230 } 231 } 232 233 if (RT_FAILURE(rc)) 234 { 235 /** @todo WriteFile(pipe) has been observed to return ERROR_NO_DATA 236 * (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is 237 * disconnected. */ 238 if ( rc == VERR_EOF 239 || rc == VERR_BROKEN_PIPE) 240 { 241 FlushFileBuffers(pThis->NamedPipe); 242 DisconnectNamedPipe(pThis->NamedPipe); 243 if (!pThis->fIsServer) 244 { 245 CloseHandle(pThis->NamedPipe); 246 pThis->NamedPipe = INVALID_HANDLE_VALUE; 247 } 248 /* pretend success */ 249 rc = VINF_SUCCESS; 250 } 251 cbWritten = 0; 252 } 253 *pcbWrite = cbWritten; 518 /* Accept the data in case the write buffer is empty. */ 519 if (!pThis->cbWriteBufUsed) 520 { 521 size_t cbWrite = RT_MIN(*pcbWrite, sizeof(pThis->cbWriteBufUsed)); 522 523 memcpy(&pThis->abBufWrite[0], pvBuf, cbWrite); 524 pThis->cbWriteBufUsed += cbWrite; 525 526 /* Initiate the write. */ 527 pThis->OverlappedWrite.Offset = 0; 528 pThis->OverlappedWrite.OffsetHigh = 0; 529 if (!WriteFile(pThis->NamedPipe, pvBuf, (DWORD)cbWrite, NULL, &pThis->OverlappedWrite)) 530 { 531 DWORD uError = GetLastError(); 532 533 if ( uError == ERROR_PIPE_LISTENING 534 || uError == ERROR_PIPE_NOT_CONNECTED) 535 { 536 /* No connection yet/anymore; just discard the write (pretending everything was written). */ 537 pThis->cbWriteBufUsed = 0; 538 cbWrite = *pcbWrite; 539 } 540 else if (uError != ERROR_IO_PENDING) /* We wait for the write to complete in the poll callback. */ 541 { 542 rc = RTErrConvertFromWin32(uError); 543 Log(("drvNamedPipeWrite: WriteFile returned %d (%Rrc)\n", uError, rc)); 544 cbWrite = 0; 545 } 546 } 547 548 if (RT_FAILURE(rc)) 549 { 550 /** @todo WriteFile(pipe) has been observed to return ERROR_NO_DATA 551 * (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is 552 * disconnected. */ 553 if ( rc == VERR_EOF 554 || rc == VERR_BROKEN_PIPE) 555 { 556 FlushFileBuffers(pThis->NamedPipe); 557 DisconnectNamedPipe(pThis->NamedPipe); 558 if (!pThis->fIsServer) 559 { 560 CloseHandle(pThis->NamedPipe); 561 pThis->NamedPipe = INVALID_HANDLE_VALUE; 562 } 563 /* pretend success */ 564 rc = VINF_SUCCESS; 565 } 566 cbWrite = 0; 567 } 568 569 *pcbWrite = cbWrite; 570 } 571 else 572 *pcbWrite = 0; 254 573 } 255 574 #else /* !RT_OS_WINDOWS */ 256 if (pThis->LocalSocket != -1) 257 { 258 ssize_t cbWritten; 259 cbWritten = send(pThis->LocalSocket, pvBuf, *pcbWrite, 0); 260 if (cbWritten == 0) 261 { 262 int tmp = pThis->LocalSocket; 263 pThis->LocalSocket = -1; 264 close(tmp); 265 } 266 else if (cbWritten == -1) 267 { 268 cbWritten = 0; 269 rc = RTErrConvertFromErrno(errno); 270 } 271 *pcbWrite = cbWritten; 272 } 575 if (pThis->hSock != NIL_RTSOCKET) 576 { 577 size_t cbBuf = *pcbWrite; 578 rc = RTSocketWriteNB(pThis->hSock, pvBuf, cbBuf, pcbWrite); 579 } 580 else 581 *pcbWrite = 0; 273 582 #endif /* !RT_OS_WINDOWS */ 274 583 … … 331 640 if (GetOverlappedResult(pThis->NamedPipe, &overlapped, &dummy, TRUE) == FALSE) 332 641 hrc = GetLastError(); 333 642 else 643 drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION); 334 644 } 335 645 … … 362 672 break; 363 673 } 364 if (pThis-> LocalSocket != -1)674 if (pThis->hSock != NIL_RTSOCKET) 365 675 { 366 676 LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance)); … … 368 678 } 369 679 else 370 pThis->LocalSocket = s; 371 680 { 681 RTSOCKET hSockNew = NIL_RTSOCKET; 682 rc = RTSocketFromNative(&hSockNew, s); 683 if (RT_SUCCESS(rc)) 684 { 685 pThis->hSock = hSockNew; 686 /* Inform the poller about the new socket. */ 687 drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION); 688 } 689 else 690 { 691 LogRel(("NamedPipe%d: Failed to wrap socket with %Rrc\n", pThis->pDrvIns->iInstance)); 692 close(s); 693 } 694 } 372 695 #endif /* !RT_OS_WINDOWS */ 373 696 } … … 473 796 pThis->OverlappedWrite.hEvent = NULL; 474 797 } 798 if (pThis->hEvtWake != NULL) 799 { 800 CloseHandle(pThis->hEvtWake); 801 pThis->hEvtWake = NULL; 802 } 475 803 #else /* !RT_OS_WINDOWS */ 476 804 Assert(pThis->LocalSocketServer == -1); 477 if (pThis->LocalSocket != -1) 478 { 479 int rc = shutdown(pThis->LocalSocket, SHUT_RDWR); 480 AssertRC(rc == 0); NOREF(rc); 481 482 rc = close(pThis->LocalSocket); 483 Assert(rc == 0); 484 pThis->LocalSocket = -1; 485 } 805 806 if (pThis->hSock != NIL_RTSOCKET) 807 { 808 int rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET); 809 AssertRC(rc); 810 811 rc = RTSocketShutdown(pThis->hSock, true /* fRead */, true /* fWrite */); 812 AssertRC(rc); 813 814 rc = RTSocketClose(pThis->hSock); 815 AssertRC(rc); RT_NOREF(rc); 816 817 pThis->hSock = NIL_RTSOCKET; 818 } 819 820 if (pThis->hPipeWakeR != NIL_RTPIPE) 821 { 822 int rc = RTPipeClose(pThis->hPipeWakeR); 823 AssertRC(rc); 824 825 pThis->hPipeWakeR = NIL_RTPIPE; 826 } 827 828 if (pThis->hPipeWakeW != NIL_RTPIPE) 829 { 830 int rc = RTPipeClose(pThis->hPipeWakeW); 831 AssertRC(rc); 832 833 pThis->hPipeWakeW = NIL_RTPIPE; 834 } 835 836 if (pThis->hPollSet != NIL_RTPOLLSET) 837 { 838 int rc = RTPollSetDestroy(pThis->hPollSet); 839 AssertRC(rc); 840 841 pThis->hPollSet = NIL_RTPOLLSET; 842 } 843 486 844 if ( pThis->fIsServer 487 845 && pThis->pszLocation) … … 539 897 pThis->OverlappedWrite.hEvent = NULL; 540 898 pThis->OverlappedRead.hEvent = NULL; 899 pThis->hEvtWake = NULL; 541 900 #else /* !RT_OS_WINDOWS */ 542 901 pThis->LocalSocketServer = -1; 543 pThis->LocalSocket = -1; 902 pThis->hSock = NIL_RTSOCKET; 903 904 pThis->hPollSet = NIL_RTPOLLSET; 905 pThis->hPipeWakeR = NIL_RTPIPE; 906 pThis->hPipeWakeW = NIL_RTPIPE; 907 pThis->fSockInPollSet = false; 544 908 #endif /* !RT_OS_WINDOWS */ 545 909 pThis->ListenThread = NIL_RTTHREAD; … … 548 912 pDrvIns->IBase.pfnQueryInterface = drvNamedPipeQueryInterface; 549 913 /* IStream */ 914 pThis->IStream.pfnPoll = drvNamedPipePoll; 915 pThis->IStream.pfnPollInterrupt = drvNamedPipePollInterrupt; 550 916 pThis->IStream.pfnRead = drvNamedPipeRead; 551 917 pThis->IStream.pfnWrite = drvNamedPipeWrite; … … 619 985 AssertReturn(pThis->OverlappedRead.hEvent != NULL, VERR_OUT_OF_RESOURCES); 620 986 987 pThis->hEvtWake = CreateEvent(NULL, FALSE, FALSE, NULL); 988 AssertReturn(pThis->hEvtWake != NULL, VERR_OUT_OF_RESOURCES); 989 621 990 #else /* !RT_OS_WINDOWS */ 991 rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */); 992 if (RT_FAILURE(rc)) 993 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 994 N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance); 995 996 rc = RTPollSetCreate(&pThis->hPollSet); 997 if (RT_FAILURE(rc)) 998 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 999 N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance); 1000 1001 rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR, 1002 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 1003 DRVNAMEDPIPE_POLLSET_ID_WAKEUP); 1004 if (RT_FAILURE(rc)) 1005 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 1006 N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"), 1007 pDrvIns->iInstance, pThis->pszLocation); 1008 622 1009 int s = socket(PF_UNIX, SOCK_STREAM, 0); 623 1010 if (s == -1) … … 648 1035 { 649 1036 /* Connect to the local socket. */ 650 pThis->LocalSocket = s;651 1037 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) 652 1038 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, 653 1039 N_("NamedPipe#%d failed to connect to local socket %s"), 654 1040 pDrvIns->iInstance, pThis->pszLocation); 1041 1042 rc = RTSocketFromNative(&pThis->hSock, s); 1043 if (RT_FAILURE(rc)) 1044 { 1045 close(s); 1046 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 1047 N_("NamedPipe#%d failed to wrap socket %Rrc"), 1048 pDrvIns->iInstance, pThis->pszLocation); 1049 } 655 1050 } 656 1051 #endif /* !RT_OS_WINDOWS */ -
trunk/src/VBox/Devices/Serial/DrvRawFile.cpp
r62956 r68699 25 25 #include <iprt/file.h> 26 26 #include <iprt/mem.h> 27 #include <iprt/poll.h> 27 28 #include <iprt/semaphore.h> 28 29 #include <iprt/stream.h> … … 36 37 * Defined Constants And Macros * 37 38 *********************************************************************************************************************************/ 38 /** Converts a pointer to DRVRAWFILE::IMedia to a PDRVRAWFILE. */39 #define PDMISTREAM_2_DRVRAWFILE(pInterface) ( (PDRVRAWFILE)((uintptr_t)pInterface - RT_OFFSETOF(DRVRAWFILE, IStream)) )40 39 41 40 … … 56 55 /** Pointer to the file name. (Freed by MM) */ 57 56 char *pszLocation; 58 /** F lag whether VirtualBox represents the server or client side. */57 /** File handle to write the data to. */ 59 58 RTFILE hOutputFile; 59 /** Event semaphore for the poll interface. */ 60 RTSEMEVENT hSemEvtPoll; 60 61 } DRVRAWFILE, *PDRVRAWFILE; 61 62 … … 63 64 64 65 /* -=-=-=-=- PDMISTREAM -=-=-=-=- */ 66 67 /** @interface_method_impl{PDMISTREAM,pfnPoll} */ 68 static DECLCALLBACK(int) drvRawFilePoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies) 69 { 70 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream); 71 72 Assert(!(fEvts & RTPOLL_EVT_READ)); /* Reading is not supported here. */ 73 74 /* Writing is always possible. */ 75 if (fEvts & RTPOLL_EVT_WRITE) 76 { 77 *pfEvts = RTPOLL_EVT_WRITE; 78 return VINF_SUCCESS; 79 } 80 81 return RTSemEventWait(pThis->hSemEvtPoll, cMillies); 82 } 83 84 85 /** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */ 86 static DECLCALLBACK(int) drvRawFilePollInterrupt(PPDMISTREAM pInterface) 87 { 88 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream); 89 return RTSemEventSignal(pThis->hSemEvtPoll); 90 } 91 65 92 66 93 /** @interface_method_impl{PDMISTREAM,pfnWrite} */ … … 68 95 { 69 96 int rc = VINF_SUCCESS; 70 PDRVRAWFILE pThis = PDMISTREAM_2_DRVRAWFILE(pInterface);97 PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream); 71 98 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation)); 72 99 … … 144 171 RTFileClose(pThis->hOutputFile); 145 172 pThis->hOutputFile = NIL_RTFILE; 173 } 174 175 if (pThis->hSemEvtPoll != NIL_RTSEMEVENT) 176 { 177 RTSemEventDestroy(pThis->hSemEvtPoll); 178 pThis->hSemEvtPoll = NIL_RTSEMEVENT; 146 179 } 147 180 } … … 168 201 pDrvIns->IBase.pfnQueryInterface = drvRawFileQueryInterface; 169 202 /* IStream */ 203 pThis->IStream.pfnPoll = drvRawFilePoll; 204 pThis->IStream.pfnPollInterrupt = drvRawFilePollInterrupt; 205 pThis->IStream.pfnRead = NULL; 170 206 pThis->IStream.pfnWrite = drvRawFileWrite; 171 207 … … 179 215 if (RT_FAILURE(rc)) 180 216 AssertMsgFailedReturn(("Configuration error: query \"Location\" resulted in %Rrc.\n", rc), rc); 217 218 rc = RTSemEventCreate(&pThis->hSemEvtPoll); 219 AssertRCReturn(rc, rc); 181 220 182 221 /* -
trunk/src/VBox/Devices/Serial/DrvTCP.cpp
r62956 r68699 5 5 6 6 /* 7 * Copyright (C) 2006-201 6Oracle Corporation.7 * Copyright (C) 2006-2017 Oracle Corporation. 8 8 * 9 9 * This file was contributed by Alexey Eromenko (derived from DrvNamedPipe) … … 28 28 #include <iprt/stream.h> 29 29 #include <iprt/alloc.h> 30 #include <iprt/pipe.h> 31 #include <iprt/poll.h> 30 32 #include <iprt/string.h> 31 33 #include <iprt/semaphore.h> 34 #include <iprt/socket.h> 35 #include <iprt/tcp.h> 32 36 #include <iprt/uuid.h> 33 37 #include <stdlib.h> 34 38 35 39 #include "VBoxDD.h" 36 37 #ifdef RT_OS_WINDOWS38 # include <iprt/win/ws2tcpip.h>39 #else /* !RT_OS_WINDOWS */40 # include <errno.h>41 # include <unistd.h>42 # include <sys/types.h>43 # include <sys/socket.h>44 # include <netinet/in.h>45 # include <netdb.h>46 # ifndef SHUT_RDWR /* OS/2 */47 # define SHUT_RDWR 348 # endif49 #endif /* !RT_OS_WINDOWS */50 51 #ifndef SHUT_RDWR52 # ifdef SD_BOTH53 # define SHUT_RDWR SD_BOTH54 # else55 # define SHUT_RDWR 256 # endif57 #endif58 59 40 60 41 /********************************************************************************************************************************* 61 42 * Defined Constants And Macros * 62 43 *********************************************************************************************************************************/ 63 /** Converts a pointer to DRVTCP::IMedia to a PDRVTCP. */ 64 #define PDMISTREAM_2_DRVTCP(pInterface) ( (PDRVTCP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTCP, IStream)) ) 65 44 45 #define DRVTCP_POLLSET_ID_SOCKET 0 46 #define DRVTCP_POLLSET_ID_WAKEUP 1 47 48 #define DRVTCP_WAKEUP_REASON_EXTERNAL 0 49 #define DRVTCP_WAKEUP_REASON_NEW_CONNECTION 1 66 50 67 51 /********************************************************************************************************************************* … … 84 68 bool fIsServer; 85 69 86 /** Socket handle of the TCP socket for server. */87 int TCPServer;70 /** Handle of the TCP server for incoming connections. */ 71 PRTTCPSERVER hTcpServ; 88 72 /** Socket handle of the TCP socket connection. */ 89 int TCPConnection; 73 RTSOCKET hTcpSock; 74 75 /** Poll set used to wait for I/O events. */ 76 RTPOLLSET hPollSet; 77 /** Reading end of the wakeup pipe. */ 78 RTPIPE hPipeWakeR; 79 /** Writing end of the wakeup pipe. */ 80 RTPIPE hPipeWakeW; 81 /** Flag whether the socket is in the pollset. */ 82 bool fTcpSockInPollSet; 90 83 91 84 /** Thread for listening for new connections. */ … … 101 94 102 95 96 /** 97 * Kicks any possibly polling thread to get informed about changes. 98 * 99 * @returns VBOx status code. 100 * @param pThis The TCP driver instance. 101 * @param bReason The reason code to handle. 102 */ 103 static int drvTcpPollerKick(PDRVTCP pThis, uint8_t bReason) 104 { 105 size_t cbWritten = 0; 106 return RTPipeWrite(pThis->hPipeWakeW, &bReason, 1, &cbWritten); 107 } 108 109 110 /** @interface_method_impl{PDMISTREAM,pfnPoll} */ 111 static DECLCALLBACK(int) drvTcpPoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies) 112 { 113 int rc = VINF_SUCCESS; 114 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream); 115 116 if (pThis->hTcpSock != NIL_RTSOCKET) 117 { 118 if (!pThis->fTcpSockInPollSet) 119 { 120 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, 121 fEvts, DRVTCP_POLLSET_ID_SOCKET); 122 if (RT_SUCCESS(rc)) 123 pThis->fTcpSockInPollSet = true; 124 } 125 else 126 { 127 /* Always include error event. */ 128 fEvts |= RTPOLL_EVT_ERROR; 129 rc = RTPollSetEventsChange(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET, fEvts); 130 AssertRC(rc); 131 } 132 } 133 134 if (RT_SUCCESS(rc)) 135 { 136 while (RT_SUCCESS(rc)) 137 { 138 uint32_t fEvtsRecv = 0; 139 uint32_t idHnd = 0; 140 141 rc = RTPoll(pThis->hPollSet, cMillies, &fEvtsRecv, &idHnd); 142 if (RT_SUCCESS(rc)) 143 { 144 if (idHnd == DRVTCP_POLLSET_ID_WAKEUP) 145 { 146 /* We got woken up, drain the pipe and return. */ 147 uint8_t bReason; 148 size_t cbRead = 0; 149 rc = RTPipeRead(pThis->hPipeWakeR, &bReason, 1, &cbRead); 150 AssertRC(rc); 151 152 if (bReason == DRVTCP_WAKEUP_REASON_EXTERNAL) 153 rc = VERR_INTERRUPTED; 154 else if (bReason == DRVTCP_WAKEUP_REASON_NEW_CONNECTION) 155 { 156 Assert(!pThis->fTcpSockInPollSet); 157 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, 158 fEvts, DRVTCP_POLLSET_ID_SOCKET); 159 if (RT_SUCCESS(rc)) 160 pThis->fTcpSockInPollSet = true; 161 } 162 else 163 AssertMsgFailed(("Unknown wakeup reason in pipe %u\n", bReason)); 164 } 165 else 166 { 167 Assert(idHnd == DRVTCP_POLLSET_ID_SOCKET); 168 169 /* On error we close the socket here. */ 170 if (fEvtsRecv & RTPOLL_EVT_ERROR) 171 { 172 rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET); 173 AssertRC(rc); 174 175 if (pThis->fIsServer) 176 RTTcpServerDisconnectClient2(pThis->hTcpSock); 177 else 178 RTSocketClose(pThis->hTcpSock); 179 pThis->hTcpSock = NIL_RTSOCKET; 180 pThis->fTcpSockInPollSet = false; 181 /* Continue with polling. */ 182 } 183 else 184 { 185 *pfEvts = fEvtsRecv; 186 break; 187 } 188 } 189 } 190 } 191 } 192 193 return rc; 194 } 195 196 197 /** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */ 198 static DECLCALLBACK(int) drvTcpPollInterrupt(PPDMISTREAM pInterface) 199 { 200 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream); 201 return drvTcpPollerKick(pThis, DRVTCP_WAKEUP_REASON_EXTERNAL); 202 } 203 204 103 205 /** @interface_method_impl{PDMISTREAM,pfnRead} */ 104 static DECLCALLBACK(int) drvT CPRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)206 static DECLCALLBACK(int) drvTcpRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead) 105 207 { 106 208 int rc = VINF_SUCCESS; 107 PDRVTCP pThis = PDMISTREAM_2_DRVTCP(pInterface);209 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream); 108 210 LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation)); 109 211 110 212 Assert(pvBuf); 111 213 112 if (pThis-> TCPConnection != -1)113 { 114 s size_t cbReallyRead;115 unsigned cbBuf = (unsigned)*pcbRead;116 cbReallyRead = recv(pThis->TCPConnection, (char *)pvBuf, cbBuf, 0);117 if ( cbReallyRead == 0)214 if (pThis->hTcpSock != NIL_RTSOCKET) 215 { 216 size_t cbRead; 217 size_t cbBuf = *pcbRead; 218 rc = RTSocketReadNB(pThis->hTcpSock, pvBuf, cbBuf, &cbRead); 219 if (RT_SUCCESS(rc)) 118 220 { 119 int tmp = pThis->TCPConnection; 120 pThis->TCPConnection = -1; 121 #ifdef RT_OS_WINDOWS 122 closesocket(tmp); 123 #else 124 close(tmp); 125 #endif 221 if (!cbRead && rc != VINF_TRY_AGAIN) 222 { 223 rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET); 224 AssertRC(rc); 225 226 if (pThis->fIsServer) 227 RTTcpServerDisconnectClient2(pThis->hTcpSock); 228 else 229 RTSocketClose(pThis->hTcpSock); 230 pThis->hTcpSock = NIL_RTSOCKET; 231 pThis->fTcpSockInPollSet = false; 232 rc = VINF_SUCCESS; 233 } 234 *pcbRead = cbRead; 126 235 } 127 else if (cbReallyRead == -1)128 {129 cbReallyRead = 0;130 rc = RTErrConvertFromErrno(errno);131 }132 *pcbRead = cbReallyRead;133 236 } 134 237 else … … 144 247 145 248 /** @interface_method_impl{PDMISTREAM,pfnWrite} */ 146 static DECLCALLBACK(int) drvT CPWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)249 static DECLCALLBACK(int) drvTcpWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite) 147 250 { 148 251 int rc = VINF_SUCCESS; 149 PDRVTCP pThis = PDMISTREAM_2_DRVTCP(pInterface);252 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream); 150 253 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation)); 151 254 152 255 Assert(pvBuf); 153 if (pThis->TCPConnection != -1) 154 { 155 ssize_t cbWritten; 156 unsigned cbBuf = (unsigned)*pcbWrite; 157 cbWritten = send(pThis->TCPConnection, (const char *)pvBuf, cbBuf, 0); 158 if (cbWritten == 0) 159 { 160 int tmp = pThis->TCPConnection; 161 pThis->TCPConnection = -1; 162 #ifdef RT_OS_WINDOWS 163 closesocket(tmp); 164 #else 165 close(tmp); 166 #endif 167 } 168 else if (cbWritten == -1) 169 { 170 cbWritten = 0; 171 rc = RTErrConvertFromErrno(errno); 172 } 173 *pcbWrite = cbWritten; 174 } 256 if (pThis->hTcpSock != NIL_RTSOCKET) 257 { 258 size_t cbBuf = *pcbWrite; 259 rc = RTSocketWriteNB(pThis->hTcpSock, pvBuf, cbBuf, pcbWrite); 260 } 261 else 262 *pcbWrite = 0; 175 263 176 264 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc)); … … 205 293 RT_NOREF(hThreadSelf); 206 294 PDRVTCP pThis = (PDRVTCP)pvUser; 207 int rc;208 295 209 296 while (RT_LIKELY(!pThis->fShutdown)) 210 297 { 211 if (listen(pThis->TCPServer, 0) == -1) 298 RTSOCKET hTcpSockNew = NIL_RTSOCKET; 299 int rc = RTTcpServerListen2(pThis->hTcpServ, &hTcpSockNew); 300 if (RT_SUCCESS(rc)) 212 301 { 213 rc = RTErrConvertFromErrno(errno); 214 LogRel(("DrvTCP%d: listen failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc)); 215 break; 302 if (pThis->hTcpSock != NIL_RTSOCKET) 303 { 304 LogRel(("DrvTCP%d: only single connection supported\n", pThis->pDrvIns->iInstance)); 305 RTTcpServerDisconnectClient2(hTcpSockNew); 306 } 307 else 308 { 309 pThis->hTcpSock = hTcpSockNew; 310 /* Inform the poller about the new socket. */ 311 drvTcpPollerKick(pThis, DRVTCP_WAKEUP_REASON_NEW_CONNECTION); 312 } 216 313 } 217 int s = accept(pThis->TCPServer, NULL, NULL);218 if (s == -1)219 {220 rc = RTErrConvertFromErrno(errno);221 LogRel(("DrvTCP%d: accept failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));222 break;223 }224 if (pThis->TCPConnection != -1)225 {226 LogRel(("DrvTCP%d: only single connection supported\n", pThis->pDrvIns->iInstance));227 #ifdef RT_OS_WINDOWS228 closesocket(s);229 #else230 close(s);231 #endif232 }233 else234 pThis->TCPConnection = s;235 314 } 236 315 … … 252 331 pThis->fShutdown = true; 253 332 if ( pThis->fIsServer 254 && pThis->TCPServer != -1) 255 { 256 int rc = shutdown(pThis->TCPServer, SHUT_RDWR); 257 AssertRC(rc == 0); NOREF(rc); 258 259 #ifdef RT_OS_WINDOWS 260 rc = closesocket(pThis->TCPServer); 261 #else 262 rc = close(pThis->TCPServer); 263 #endif 264 AssertRC(rc == 0); 265 pThis->TCPServer = -1; 333 && pThis->hTcpServ != NULL) 334 { 335 int rc = RTTcpServerShutdown(pThis->hTcpServ); 336 AssertRC(rc); 337 pThis->hTcpServ = NULL; 266 338 } 267 339 } … … 303 375 * While the thread exits, clean up as much as we can. 304 376 */ 305 306 Assert(pThis->TCPServer == -1); 307 if (pThis->TCPConnection != -1) 308 { 309 int rc = shutdown(pThis->TCPConnection, SHUT_RDWR); 310 AssertRC(rc == 0); NOREF(rc); 311 312 #ifdef RT_OS_WINDOWS 313 rc = closesocket(pThis->TCPConnection); 314 #else 315 rc = close(pThis->TCPConnection); 316 #endif 317 Assert(rc == 0); 318 pThis->TCPConnection = -1; 319 } 320 if ( pThis->fIsServer 321 && pThis->pszLocation) 322 RTFileDelete(pThis->pszLocation); 323 377 if (pThis->hTcpSock != NIL_RTSOCKET) 378 { 379 int rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET); 380 AssertRC(rc); 381 382 rc = RTSocketShutdown(pThis->hTcpSock, true /* fRead */, true /* fWrite */); 383 AssertRC(rc); 384 385 rc = RTSocketClose(pThis->hTcpSock); 386 AssertRC(rc); RT_NOREF(rc); 387 388 pThis->hTcpSock = NIL_RTSOCKET; 389 } 390 391 if (pThis->hPipeWakeR != NIL_RTPIPE) 392 { 393 int rc = RTPipeClose(pThis->hPipeWakeR); 394 AssertRC(rc); 395 396 pThis->hPipeWakeR = NIL_RTPIPE; 397 } 398 399 if (pThis->hPipeWakeW != NIL_RTPIPE) 400 { 401 int rc = RTPipeClose(pThis->hPipeWakeW); 402 AssertRC(rc); 403 404 pThis->hPipeWakeW = NIL_RTPIPE; 405 } 406 407 if (pThis->hPollSet != NIL_RTPOLLSET) 408 { 409 int rc = RTPollSetDestroy(pThis->hPollSet); 410 AssertRC(rc); 411 412 pThis->hPollSet = NIL_RTPOLLSET; 413 } 324 414 325 415 MMR3HeapFree(pThis->pszLocation); … … 337 427 LogRel(("DrvTCP%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc)); 338 428 } 339 340 429 } 341 430 … … 351 440 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); 352 441 PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP); 353 354 #ifdef RT_OS_WINDOWS355 {356 WSADATA wsaData;357 int err;358 359 err = WSAStartup(MAKEWORD(2,2), &wsaData);360 if (err != 0)361 {362 LogRel(("DrvTCP: Failed to initialize Winsock, error %d\n", err));363 /* XXX: let socket creation fail below */364 }365 }366 #endif367 442 368 443 /* … … 373 448 pThis->fIsServer = false; 374 449 375 pThis->TCPServer = -1; 376 pThis->TCPConnection = -1; 450 pThis->hTcpServ = NULL; 451 pThis->hTcpSock = NIL_RTSOCKET; 452 453 pThis->hPollSet = NIL_RTPOLLSET; 454 pThis->hPipeWakeR = NIL_RTPIPE; 455 pThis->hPipeWakeW = NIL_RTPIPE; 456 pThis->fTcpSockInPollSet = false; 377 457 378 458 pThis->ListenThread = NIL_RTTHREAD; … … 381 461 pDrvIns->IBase.pfnQueryInterface = drvTCPQueryInterface; 382 462 /* IStream */ 383 pThis->IStream.pfnRead = drvTCPRead; 384 pThis->IStream.pfnWrite = drvTCPWrite; 463 pThis->IStream.pfnPoll = drvTcpPoll; 464 pThis->IStream.pfnPollInterrupt = drvTcpPollInterrupt; 465 pThis->IStream.pfnRead = drvTcpRead; 466 pThis->IStream.pfnWrite = drvTcpWrite; 385 467 386 468 /* … … 398 480 N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc); 399 481 482 rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */); 483 if (RT_FAILURE(rc)) 484 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 485 N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance); 486 487 rc = RTPollSetCreate(&pThis->hPollSet); 488 if (RT_FAILURE(rc)) 489 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 490 N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance); 491 492 rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR, 493 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 494 DRVTCP_POLLSET_ID_WAKEUP); 495 if (RT_FAILURE(rc)) 496 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 497 N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"), 498 pDrvIns->iInstance, pThis->pszLocation); 499 400 500 /* 401 501 * Create/Open the socket. 402 502 */ 403 int s = socket(PF_INET, SOCK_STREAM, 0);404 if (s == -1)405 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,406 N_("DrvTCP#%d failed to create socket"), pDrvIns->iInstance);407 408 struct sockaddr_in addr;409 memset(&addr, 0, sizeof(addr));410 addr.sin_family = AF_INET;411 412 503 if (pThis->fIsServer) 413 504 { 414 addr.sin_addr.s_addr = INADDR_ANY; 415 addr.sin_port = htons(/*PORT*/ atoi(pThis->pszLocation)); 416 417 /* Bind address to the telnet socket. */ 418 pThis->TCPServer = s; 419 RTFileDelete(pThis->pszLocation); 420 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) 421 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, 422 N_("DrvTCP#%d failed to bind to socket %s"), 423 pDrvIns->iInstance, pThis->pszLocation); 505 uint32_t uPort = 0; 506 rc = RTStrToUInt32Ex(pThis->pszLocation, NULL, 10, &uPort); 507 if (RT_FAILURE(rc)) 508 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 509 N_("DrvTCP#%d: The port part of the location is not a numerical value"), 510 pDrvIns->iInstance); 511 512 /** @todo: Allow binding to distinct interfaces. */ 513 rc = RTTcpServerCreateEx(NULL, uPort, &pThis->hTcpServ); 514 if (RT_FAILURE(rc)) 515 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 516 N_("DrvTCP#%d failed to create server socket"), pDrvIns->iInstance); 517 424 518 rc = RTThreadCreate(&pThis->ListenThread, drvTCPListenLoop, (void *)pThis, 0, 425 519 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DrvTCPStream"); … … 430 524 else 431 525 { 432 char *token; 433 const char *delim = ":"; 434 struct hostent *server; 435 token = strtok(pThis->pszLocation, delim); 436 if(token) { 437 server = gethostbyname(token); 438 memmove((char *)&addr.sin_addr.s_addr, 439 (char *)server->h_addr, 440 server->h_length); 441 } 442 token = strtok(NULL, delim); 443 if(token) { 444 addr.sin_port = htons(/*PORT*/ atoi(token)); 445 } 446 447 /* Connect to the telnet socket. */ 448 pThis->TCPConnection = s; 449 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) 450 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, 526 char *pszPort = strchr(pThis->pszLocation, ':'); 527 if (!pszPort) 528 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_FOUND, RT_SRC_POS, 529 N_("DrvTCP#%d: The location misses the port to connect to"), 530 pDrvIns->iInstance); 531 532 *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */ 533 uint32_t uPort = 0; 534 rc = RTStrToUInt32Ex(pszPort + 1, NULL, 10, &uPort); 535 if (RT_FAILURE(rc)) 536 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 537 N_("DrvTCP#%d: The port part of the location is not a numerical value"), 538 pDrvIns->iInstance); 539 540 rc = RTTcpClientConnect(pThis->pszLocation, uPort, &pThis->hTcpSock); 541 *pszPort = ':'; /* Restore delimiter before checking the status. */ 542 if (RT_FAILURE(rc)) 543 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 451 544 N_("DrvTCP#%d failed to connect to socket %s"), 452 545 pDrvIns->iInstance, pThis->pszLocation); 546 547 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, 548 RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR, 549 DRVTCP_POLLSET_ID_SOCKET); 550 if (RT_FAILURE(rc)) 551 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, 552 N_("DrvTCP#%d failed to add socket for %s to poll set"), 553 pDrvIns->iInstance, pThis->pszLocation); 554 555 pThis->fTcpSockInPollSet = true; 453 556 } 454 557
Note:
See TracChangeset
for help on using the changeset viewer.