Changeset 68699 in vbox for trunk/src/VBox/Devices/Serial/DrvNamedPipe.cpp
- Timestamp:
- Sep 7, 2017 3:12:54 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 117930
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 */
Note:
See TracChangeset
for help on using the changeset viewer.