| | 787 | |
|---|
| | 788 | /** |
|---|
| | 789 | * Wait for notification of changes to a guest property. If this is called in |
|---|
| | 790 | * a loop, the timestamp of the last notification seen can be passed as a |
|---|
| | 791 | * parameter to be sure that no notifications are missed. |
|---|
| | 792 | * |
|---|
| | 793 | * @returns VBox status code. |
|---|
| | 794 | * @retval VINF_SUCCESS on success, @a ppszName, @a ppszValue, |
|---|
| | 795 | * @a pu64Timestamp and @a ppszFlags containing valid data. |
|---|
| | 796 | * @retval VINF_NOT_FOUND if no previous notification could be found with the |
|---|
| | 797 | * timestamp supplied. This will normally mean that a large number |
|---|
| | 798 | * of notifications occurred in between. |
|---|
| | 799 | * @retval VERR_BUFFER_OVERFLOW if the scratch buffer @a pvBuf is not large |
|---|
| | 800 | * enough. In this case the size needed will be placed in |
|---|
| | 801 | * @a pcbBufActual if it is not NULL. |
|---|
| | 802 | * @retval VERR_TIMEOUT if a timeout occurred before a notification was seen. |
|---|
| | 803 | * |
|---|
| | 804 | * @param u32ClientId The client id returned by VbglR3GuestPropConnect(). |
|---|
| | 805 | * @param pszPatterns The patterns that the property names must matchfor |
|---|
| | 806 | * the change to be reported. |
|---|
| | 807 | * @param pvBuf A scratch buffer to store the data retrieved into. |
|---|
| | 808 | * The returned data is only valid for it's lifetime. |
|---|
| | 809 | * @a ppszValue will point to the start of this buffer. |
|---|
| | 810 | * @param cbBuf The size of @a pvBuf |
|---|
| | 811 | * @param u64Timestamp The timestamp of the last event seen. Pass zero |
|---|
| | 812 | * to wait for the next event. |
|---|
| | 813 | * @param u32Timeout Timeout in milliseconds. Use RT_INDEFINITE_WAIT |
|---|
| | 814 | * to wait indefinitely. |
|---|
| | 815 | * @param ppszName Where to store the pointer to the name retrieved. |
|---|
| | 816 | * Optional. |
|---|
| | 817 | * @param ppszValue Where to store the pointer to the value retrieved. |
|---|
| | 818 | * Optional. |
|---|
| | 819 | * @param pu64Timestamp Where to store the timestamp. Optional. |
|---|
| | 820 | * @param ppszFlags Where to store the pointer to the flags. Optional. |
|---|
| | 821 | * @param pcbBufActual If @a pcBuf is not large enough, the size needed. |
|---|
| | 822 | * Optional. |
|---|
| | 823 | */ |
|---|
| | 824 | VBGLR3DECL(int) VbglR3GuestPropWait(uint32_t u32ClientId, |
|---|
| | 825 | const char *pszPatterns, |
|---|
| | 826 | void *pvBuf, uint32_t cbBuf, |
|---|
| | 827 | uint64_t u64Timestamp, uint32_t u32Timeout, |
|---|
| | 828 | char ** ppszName, char **ppszValue, |
|---|
| | 829 | uint64_t *pu64Timestamp, char **ppszFlags, |
|---|
| | 830 | uint32_t *pcbBufActual) |
|---|
| | 831 | { |
|---|
| | 832 | /* |
|---|
| | 833 | * Create the GET_NOTIFICATION message and call the host. |
|---|
| | 834 | */ |
|---|
| | 835 | GetNotification Msg; |
|---|
| | 836 | |
|---|
| | 837 | Msg.hdr.u32Timeout = u32Timeout; |
|---|
| | 838 | Msg.hdr.info.result = (uint32_t)VERR_WRONG_ORDER; /** @todo drop the cast when the result type has been fixed! */ |
|---|
| | 839 | Msg.hdr.info.u32ClientID = u32ClientId; |
|---|
| | 840 | Msg.hdr.info.u32Function = GET_NOTIFICATION; |
|---|
| | 841 | Msg.hdr.info.cParms = 4; |
|---|
| | 842 | Msg.patterns.SetPtr(const_cast<char *>(pszPatterns), |
|---|
| | 843 | strlen(pszPatterns) + 1); |
|---|
| | 844 | Msg.buffer.SetPtr(pvBuf, cbBuf); |
|---|
| | 845 | Msg.timestamp.SetUInt64(u64Timestamp); |
|---|
| | 846 | Msg.size.SetUInt32(0); |
|---|
| | 847 | |
|---|
| | 848 | int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL_TIMEOUT(sizeof(Msg)), &Msg, sizeof(Msg)); |
|---|
| | 849 | if (RT_SUCCESS(rc)) |
|---|
| | 850 | rc = Msg.hdr.info.result; |
|---|
| | 851 | |
|---|
| | 852 | /* |
|---|
| | 853 | * The cbBufActual parameter is also returned on overflow so the caller can |
|---|
| | 854 | * adjust their buffer. |
|---|
| | 855 | */ |
|---|
| | 856 | if ( rc == VERR_BUFFER_OVERFLOW |
|---|
| | 857 | || pcbBufActual != NULL) |
|---|
| | 858 | { |
|---|
| | 859 | int rc2 = Msg.size.GetUInt32(pcbBufActual); |
|---|
| | 860 | AssertRCReturn(rc2, RT_FAILURE(rc) ? rc : rc2); |
|---|
| | 861 | } |
|---|
| | 862 | if (RT_FAILURE(rc)) |
|---|
| | 863 | return rc; |
|---|
| | 864 | |
|---|
| | 865 | /* |
|---|
| | 866 | * Buffer layout: Name\0Value\0Flags\0. |
|---|
| | 867 | * |
|---|
| | 868 | * If the caller cares about any of these strings, make sure things are |
|---|
| | 869 | * propertly terminated (paranoia). |
|---|
| | 870 | */ |
|---|
| | 871 | if ( RT_SUCCESS(rc) |
|---|
| | 872 | && (ppszName != NULL || ppszValue != NULL || ppszFlags != NULL)) |
|---|
| | 873 | { |
|---|
| | 874 | /* Validate / skip 'Name'. */ |
|---|
| | 875 | char *pszValue = (char *)memchr(pvBuf, '\0', cbBuf) + 1; |
|---|
| | 876 | AssertPtrReturn(pszValue, VERR_TOO_MUCH_DATA); |
|---|
| | 877 | if (ppszName) |
|---|
| | 878 | *ppszName = (char *)pvBuf; |
|---|
| | 879 | |
|---|
| | 880 | /* Validate / skip 'Value'. */ |
|---|
| | 881 | char *pszFlags = (char *)memchr(pszValue, '\0', |
|---|
| | 882 | cbBuf - (pszValue - (char *)pvBuf)) + 1; |
|---|
| | 883 | AssertPtrReturn(pszFlags, VERR_TOO_MUCH_DATA); |
|---|
| | 884 | if (ppszValue) |
|---|
| | 885 | *ppszValue = pszValue; |
|---|
| | 886 | |
|---|
| | 887 | if (ppszFlags) |
|---|
| | 888 | { |
|---|
| | 889 | /* Validate 'Flags'. */ |
|---|
| | 890 | void *pvEos = memchr(pszFlags, '\0', cbBuf - (pszFlags - (char *)pvBuf)); |
|---|
| | 891 | AssertPtrReturn(pvEos, VERR_TOO_MUCH_DATA); |
|---|
| | 892 | *ppszFlags = pszFlags; |
|---|
| | 893 | } |
|---|
| | 894 | } |
|---|
| | 895 | |
|---|
| | 896 | /* And the timestamp, if requested. */ |
|---|
| | 897 | if (pu64Timestamp != NULL) |
|---|
| | 898 | { |
|---|
| | 899 | rc = Msg.timestamp.GetUInt64(pu64Timestamp); |
|---|
| | 900 | AssertRCReturn(rc, rc); |
|---|
| | 901 | } |
|---|
| | 902 | |
|---|
| | 903 | return VINF_SUCCESS; |
|---|
| | 904 | } |
|---|
| | 905 | |
|---|