- Timestamp:
- Nov 24, 2008 3:16:01 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/VBoxHDD-new.h
r13988 r14526 216 216 * provide the mandatory configuration parts this way. */ 217 217 #define VD_CAP_CONFIG RT_BIT(7) 218 /** The backend uses the network stack interface. The caller has to provide 219 * the appropriate interface. */ 220 #define VD_CAP_TCPNET RT_BIT(8) 218 221 /** @}*/ 219 222 … … 233 236 /** Interface for configuration information. Per-image. */ 234 237 VDINTERFACETYPE_CONFIG, 238 /** Interface for TCP network stack. Per-disk. */ 239 VDINTERFACETYPE_TCPNET, 235 240 /** invalid interface. */ 236 241 VDINTERFACETYPE_INVALID … … 252 257 /** Opaque user data which is passed on every call. */ 253 258 void *pvUser; 254 /** Pointer to the function call table of the interface. 259 /** Pointer to the function call table of the interface. 255 260 * As this is opaque this must be casted to the right interface 256 261 * struct defined below based on the interface type in enmInterface. */ … … 288 293 AssertMsgBreak(pVDIfs->cbSize == sizeof(VDINTERFACE), 289 294 ("cbSize=%u\n", pVDIfs->cbSize)); 290 295 291 296 if (pVDIfs->enmInterface == enmInterface) 292 297 return pVDIfs; … … 395 400 } 396 401 397 /** 402 /** 398 403 * Completion callback which is called by the interface owner 399 404 * to inform the backend that a task finished. … … 455 460 * @param pcbWritten Where to store how many bytes where actually written. 456 461 */ 457 DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 462 DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 458 463 size_t cbWrite, const void *pvBuf, size_t *pcbWritten)); 459 464 … … 469 474 * @param pcbRead Where to store how many bytes where actually read. 470 475 */ 471 DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvUser, void *pStorage, uint64_t uOffset, 476 DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvUser, void *pStorage, uint64_t uOffset, 472 477 size_t cbRead, void *pvBuf, size_t *pcbRead)); 473 478 … … 492 497 * @param ppTask Where to store the opaque task handle. 493 498 */ 494 DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (void *pvUser, void *pStorage, uint64_t uOffset, 499 DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (void *pvUser, void *pStorage, uint64_t uOffset, 495 500 void *pvBuf, size_t cbRead, void **ppTask)); 496 501 … … 506 511 * @param ppTask Where to store the opaque task handle. 507 512 */ 508 DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 513 DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 509 514 void *pvBuf, size_t cbWrite, void **ppTask)); 510 515 … … 550 555 /** 551 556 * Progress notification interface 552 * 557 * 553 558 * Per-operation. Optional. 554 559 */ … … 687 692 DECLINLINE(PVDINTERFACECONFIG) VDGetInterfaceConfig(PVDINTERFACE pInterface) 688 693 { 689 /* Check that the interface descriptor is a progressinterface. */694 /* Check that the interface descriptor is a config interface. */ 690 695 AssertMsgReturn( (pInterface->enmInterface == VDINTERFACETYPE_CONFIG) 691 696 && (pInterface->cbSize == sizeof(VDINTERFACE)), … … 705 710 * Query configuration, validates that the values are within a set of valid names. 706 711 * 707 * @return strue if all names are found in pszzAllowed.708 * @return sfalse if not.712 * @return true if all names are found in pszzAllowed. 713 * @return false if not. 709 714 * @param pCfgIf Pointer to configuration callback table. 710 715 * @param pNode The node which values should be examined. … … 721 726 /** 722 727 * Query configuration, unsigned 64-bit integer value with default. 723 * 728 * 724 729 * @return VBox status code. 725 730 * @param pCfgIf Pointer to configuration callback table. … … 738 743 /** 739 744 * Query configuration, unsigned 32-bit integer value with default. 740 * 745 * 741 746 * @return VBox status code. 742 747 * @param pCfgIf Pointer to configuration callback table. … … 764 769 /** 765 770 * Query configuration, bool value with default. 766 * 771 * 767 772 * @return VBox status code. 768 773 * @param pCfgIf Pointer to configuration callback table. … … 786 791 * Query configuration, dynamically allocated (RTMemAlloc) zero terminated 787 792 * character value. 788 * 793 * 789 794 * @return VBox status code. 790 795 * @param pCfgIf Pointer to configuration callback table. … … 821 826 * Query configuration, dynamically allocated (RTMemAlloc) zero terminated 822 827 * character value with default. 823 * 828 * 824 829 * @return VBox status code. 825 830 * @param pCfgIf Pointer to configuration callback table. … … 862 867 /** 863 868 * Query configuration, dynamically allocated (RTMemAlloc) byte string value. 864 * 869 * 865 870 * @return VBox status code. 866 871 * @param pCfgIf Pointer to configuration callback table. … … 898 903 899 904 905 /** 906 * TCP network stack interface 907 * 908 * Per-disk. Mandatory for backends which have the VD_CAP_TCPNET bit set. 909 */ 910 typedef struct VDINTERFACETCPNET 911 { 912 /** 913 * Size of the configuration interface. 914 */ 915 uint32_t cbSize; 916 917 /** 918 * Interface type. 919 */ 920 VDINTERFACETYPE enmInterface; 921 922 /** 923 * Connect as a client to a TCP port. 924 * 925 * @return iprt status code. 926 * @param pszAddress The address to connect to. 927 * @param uPort The port to connect to. 928 * @param pSock Where to store the handle to the established connect 929 ion. 930 */ 931 DECLR3CALLBACKMEMBER(int, pfnClientConnect, (const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)); 932 933 /** 934 * Close a TCP connection. 935 * 936 * @return iprt status code. 937 * @param Sock Socket descriptor. 938 ion. 939 */ 940 DECLR3CALLBACKMEMBER(int, pfnClientClose, (RTSOCKET Sock)); 941 942 /** 943 * Socket I/O multiplexing. 944 * Checks if the socket is ready for reading. 945 * 946 * @return iprt status code. 947 * @param Sock Socket descriptor. 948 * @param cMillies Number of milliseconds to wait for the socket. 949 * Use RT_INDEFINITE_WAIT to wait for ever. 950 */ 951 DECLR3CALLBACKMEMBER(int, pfnSelectOne, (RTSOCKET Sock, unsigned cMillies)); 952 953 /** 954 * Receive data from a socket. 955 * 956 * @return iprt status code. 957 * @param Sock Socket descriptor. 958 * @param pvBuffer Where to put the data we read. 959 * @param cbBuffer Read buffer size. 960 * @param pcbRead Number of bytes read. 961 * If NULL the entire buffer will be filled upon successful return. 962 * If not NULL a partial read can be done successfully. 963 */ 964 DECLR3CALLBACKMEMBER(int, pfnRead, (RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)); 965 966 /** 967 * Send data from a socket. 968 * 969 * @return iprt status code. 970 * @param Sock Socket descriptor. 971 * @param pvBuffer Buffer to write data to socket. 972 * @param cbBuffer How much to write. 973 * @param pcbRead Number of bytes read. 974 */ 975 DECLR3CALLBACKMEMBER(int, pfnWrite, (RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)); 976 977 /** 978 * Flush socket write buffers. 979 * 980 * @return iprt status code. 981 * @param Sock Socket descriptor. 982 */ 983 DECLR3CALLBACKMEMBER(int, pfnFlush, (RTSOCKET Sock)); 984 985 } VDINTERFACETCPNET, *PVDINTERFACETCPNET; 986 987 /** 988 * Get TCP network stack interface from opaque callback table. 989 * 990 * @return Pointer to the callback table. 991 * @param pInterface Pointer to the interface descriptor. 992 */ 993 DECLINLINE(PVDINTERFACETCPNET) VDGetInterfaceTcpNet(PVDINTERFACE pInterface) 994 { 995 /* Check that the interface descriptor is a TCP network stack interface. */ 996 AssertMsgReturn( (pInterface->enmInterface == VDINTERFACETYPE_TCPNET) 997 && (pInterface->cbSize == sizeof(VDINTERFACE)), 998 ("Not a TCP network stack interface"), NULL); 999 1000 PVDINTERFACETCPNET pInterfaceTcpNet = (PVDINTERFACETCPNET)pInterface->pCallbacks; 1001 1002 /* Do basic checks. */ 1003 AssertMsgReturn( (pInterfaceTcpNet->cbSize == sizeof(VDINTERFACETCPNET)) 1004 && (pInterfaceTcpNet->enmInterface == VDINTERFACETYPE_TCPNET), 1005 ("A non TCP network stack callback table attached to a TCP network stack interface descriptor\n"), NULL); 1006 1007 return pInterfaceTcpNet; 1008 } 1009 1010 900 1011 /** @name Configuration interface key handling flags. 901 1012 * @{ … … 1495 1606 * @param pvUser User data which is passed on completion 1496 1607 */ 1497 VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 1608 VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 1498 1609 PPDMDATASEG paSeg, unsigned cSeg, 1499 1610 void *pvUser); -
trunk/src/VBox/Devices/Makefile.kmk
r14448 r14526 819 819 Storage/ISCSIHDDCore.cpp 820 820 VBoxDDU_DEFS += VBOX_WITH_ISCSI 821 Storage/DrvVD.cpp_INCS = \ 822 Network/lwip/src/include \ 823 Network/lwip/src/include/ipv4 \ 824 Network/lwip/vbox/include 821 825 endif # VBOX_WITH_ISCSI 822 826 -
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r13840 r14526 33 33 #include <iprt/string.h> 34 34 #include <iprt/cache.h> 35 #include <iprt/tcp.h> 36 37 /* All lwip header files are not C++ safe. So hack around this. */ 38 __BEGIN_DECLS 39 #include <lwip/inet.h> 40 #include <lwip/tcp.h> 41 #include <lwip/sockets.h> 42 __END_DECLS 35 43 36 44 #include "Builtins.h" 45 46 /* Small hack to get at lwIP initialized status */ 47 extern bool DevINIPConfigured(void); 37 48 38 49 … … 107 118 /** Callback table for error interface. */ 108 119 VDINTERFACEERROR VDIErrorCallbacks; 120 /** Common structure for the supported TCP network stack interface. */ 121 VDINTERFACE VDITcpNet; 122 /** Callback table for TCP network stack interface. */ 123 VDINTERFACETCPNET VDITcpNetCallbacks; 109 124 /** Common structure for the supported async I/O interface. */ 110 125 VDINTERFACE VDIAsyncIO; … … 315 330 316 331 /******************************************************************************* 332 * VD TCP network stack interface implementation - INIP case * 333 *******************************************************************************/ 334 335 /** @copydoc VDINTERFACETCPNET::pfnClientConnect */ 336 static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock) 337 { 338 int rc = VINF_SUCCESS; 339 /* First check whether lwIP is set up in this VM instance. */ 340 if (!DevINIPConfigured()) 341 { 342 LogRelFunc(("no IP stack\n")); 343 return VERR_NET_HOST_UNREACHABLE; 344 } 345 /* Resolve hostname. As there is no standard resolver for lwIP yet, 346 * just accept numeric IP addresses for now. */ 347 struct in_addr ip; 348 if (!lwip_inet_aton(pszAddress, &ip)) 349 { 350 LogRelFunc(("cannot resolve IP %s\n", pszAddress)); 351 return VERR_NET_HOST_UNREACHABLE; 352 } 353 /* Create socket and connect. */ 354 RTSOCKET Sock = lwip_socket(PF_INET, SOCK_STREAM, 0); 355 if (Sock != -1) 356 { 357 struct sockaddr_in InAddr = {0}; 358 InAddr.sin_family = AF_INET; 359 InAddr.sin_port = htons(uPort); 360 InAddr.sin_addr = ip; 361 if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr))) 362 { 363 *pSock = Sock; 364 return VINF_SUCCESS; 365 } 366 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */ 367 lwip_close(Sock); 368 } 369 else 370 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */ 371 return rc; 372 } 373 374 /** @copydoc VDINTERFACETCPNET::pfnClientClose */ 375 static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock) 376 { 377 lwip_close(Sock); 378 return VINF_SUCCESS; /** @todo real solution needed */ 379 } 380 381 /** @copydoc VDINTERFACETCPNET::pfnSelectOne */ 382 static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, unsigned cMillies) 383 { 384 fd_set fdsetR; 385 FD_ZERO(&fdsetR); 386 FD_SET(Sock, &fdsetR); 387 fd_set fdsetE = fdsetR; 388 389 int rc; 390 if (cMillies == RT_INDEFINITE_WAIT) 391 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL); 392 else 393 { 394 struct timeval timeout; 395 timeout.tv_sec = cMillies / 1000; 396 timeout.tv_usec = (cMillies % 1000) * 1000; 397 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout); 398 } 399 if (rc > 0) 400 return VINF_SUCCESS; 401 if (rc == 0) 402 return VERR_TIMEOUT; 403 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */ 404 } 405 406 /** @copydoc VDINTERFACETCPNET::pfnRead */ 407 static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead) 408 { 409 /* Do params checking */ 410 if (!pvBuffer || !cbBuffer) 411 { 412 AssertMsgFailed(("Invalid params\n")); 413 return VERR_INVALID_PARAMETER; 414 } 415 416 /* 417 * Read loop. 418 * If pcbRead is NULL we have to fill the entire buffer! 419 */ 420 size_t cbRead = 0; 421 size_t cbToRead = cbBuffer; 422 for (;;) 423 { 424 /** @todo this clipping here is just in case (the send function 425 * needed it, so I added it here, too). Didn't investigate if this 426 * really has issues. Better be safe than sorry. */ 427 ssize_t cbBytesRead = lwip_recv(Sock, (char *)pvBuffer + cbRead, 428 RT_MIN(cbToRead, 32768), 0); 429 if (cbBytesRead < 0) 430 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */ 431 if (cbBytesRead == 0 && errno) 432 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */ 433 if (pcbRead) 434 { 435 /* return partial data */ 436 *pcbRead = cbBytesRead; 437 break; 438 } 439 440 /* read more? */ 441 cbRead += cbBytesRead; 442 if (cbRead == cbBuffer) 443 break; 444 445 /* next */ 446 cbToRead = cbBuffer - cbRead; 447 } 448 449 return VINF_SUCCESS; 450 } 451 452 /** @copydoc VDINTERFACETCPNET::pfnWrite */ 453 static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer) 454 { 455 do 456 { 457 /** @todo lwip send only supports up to 65535 bytes in a single 458 * send (stupid limitation buried in the code), so make sure we 459 * don't get any wraparounds. This should be moved to DevINIP 460 * stack interface once that's implemented. */ 461 ssize_t cbWritten = lwip_send(Sock, (void *)pvBuffer, 462 RT_MIN(cbBuffer, 32768), 0); 463 if (cbWritten < 0) 464 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */ 465 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n", 466 cbWritten, cbBuffer)); 467 cbBuffer -= cbWritten; 468 pvBuffer = (const char *)pvBuffer + cbWritten; 469 } while (cbBuffer); 470 471 return VINF_SUCCESS; 472 } 473 474 /** @copydoc VDINTERFACETCPNET::pfnFlush */ 475 static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock) 476 { 477 int fFlag = 1; 478 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, 479 (const char *)&fFlag, sizeof(fFlag)); 480 fFlag = 0; 481 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, 482 (const char *)&fFlag, sizeof(fFlag)); 483 return VINF_SUCCESS; 484 } 485 486 487 /******************************************************************************* 317 488 * Media interface methods * 318 489 *******************************************************************************/ … … 629 800 630 801 /* 631 * Attach the async transport driver below of the device above us implements the802 * Attach the async transport driver below if the device above us implements the 632 803 * async interface. 633 804 */ … … 677 848 * It's sort of up side down from the image dependency tree. 678 849 */ 850 bool fHostIP = false; 679 851 unsigned iLevel = 0; 680 852 PCFGMNODE pCurNode = pCfgHandle; … … 690 862 fValid = CFGMR3AreValuesValid(pCurNode, 691 863 "Format\0Path\0" 692 "ReadOnly\0HonorZeroWrites\0"); 864 "ReadOnly\0HonorZeroWrites\0" 865 "HostIPStack\0"); 866 867 rc = CFGMR3QueryBool(pCfgHandle, "HostIPStack", &fHostIP); 868 if (rc == VERR_CFGM_VALUE_NOT_FOUND) 869 fHostIP = true; 870 else if (RT_FAILURE(rc)) 871 { 872 rc = PDMDRV_SET_ERROR(pDrvIns, rc, 873 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed")); 874 break; 875 } 693 876 } 694 877 else … … 717 900 if (RT_SUCCESS(rc)) 718 901 { 902 /* First of all figure out what kind of TCP networking stack interface 903 * to use. This is done unconditionally, as backends which don't need 904 * it will just ignore it. */ 905 if (fHostIP) 906 { 907 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET); 908 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET; 909 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect; 910 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose; 911 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne; 912 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead; 913 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite; 914 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush; 915 } 916 else 917 { 918 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET); 919 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET; 920 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect; 921 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose; 922 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne; 923 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead; 924 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite; 925 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush; 926 } 927 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP", 928 VDINTERFACETYPE_TCPNET, 929 &pThis->VDITcpNetCallbacks, NULL, 930 &pThis->pVDIfsDisk); 931 AssertRC(rc); 932 719 933 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk); 720 934 /* Error message is already set correctly. */
Note:
See TracChangeset
for help on using the changeset viewer.