diff options
Diffstat (limited to '')
-rw-r--r-- | src/balutil/balretry.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/balutil/balretry.cpp b/src/balutil/balretry.cpp new file mode 100644 index 00000000..d95d86b2 --- /dev/null +++ b/src/balutil/balretry.cpp | |||
@@ -0,0 +1,191 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | struct BALRETRY_INFO | ||
6 | { | ||
7 | LPWSTR sczId; // package or container id. | ||
8 | LPWSTR sczPayloadId; // optional payload id. | ||
9 | DWORD cRetries; | ||
10 | DWORD dwLastError; | ||
11 | }; | ||
12 | |||
13 | static DWORD vdwMaxRetries = 0; | ||
14 | static DWORD vdwTimeout = 0; | ||
15 | static BALRETRY_INFO vrgRetryInfo[2]; | ||
16 | |||
17 | // prototypes | ||
18 | static BOOL IsActiveRetryEntry( | ||
19 | __in BALRETRY_TYPE type, | ||
20 | __in_z LPCWSTR wzPackageId, | ||
21 | __in_z_opt LPCWSTR wzPayloadId | ||
22 | ); | ||
23 | |||
24 | |||
25 | DAPI_(void) BalRetryInitialize( | ||
26 | __in DWORD dwMaxRetries, | ||
27 | __in DWORD dwTimeout | ||
28 | ) | ||
29 | { | ||
30 | BalRetryUninitialize(); // clean everything out. | ||
31 | |||
32 | vdwMaxRetries = dwMaxRetries; | ||
33 | vdwTimeout = dwTimeout; | ||
34 | } | ||
35 | |||
36 | |||
37 | DAPI_(void) BalRetryUninitialize() | ||
38 | { | ||
39 | for (DWORD i = 0; i < countof(vrgRetryInfo); ++i) | ||
40 | { | ||
41 | ReleaseStr(vrgRetryInfo[i].sczId); | ||
42 | ReleaseStr(vrgRetryInfo[i].sczPayloadId); | ||
43 | memset(vrgRetryInfo + i, 0, sizeof(BALRETRY_INFO)); | ||
44 | } | ||
45 | |||
46 | vdwMaxRetries = 0; | ||
47 | vdwTimeout = 0; | ||
48 | } | ||
49 | |||
50 | |||
51 | DAPI_(void) BalRetryStartPackage( | ||
52 | __in BALRETRY_TYPE type, | ||
53 | __in_z_opt LPCWSTR wzPackageId, | ||
54 | __in_z_opt LPCWSTR wzPayloadId | ||
55 | ) | ||
56 | { | ||
57 | if (!wzPackageId || !*wzPackageId) | ||
58 | { | ||
59 | ReleaseNullStr(vrgRetryInfo[type].sczId); | ||
60 | ReleaseNullStr(vrgRetryInfo[type].sczPayloadId); | ||
61 | } | ||
62 | else if (IsActiveRetryEntry(type, wzPackageId, wzPayloadId)) | ||
63 | { | ||
64 | ++vrgRetryInfo[type].cRetries; | ||
65 | ::Sleep(vdwTimeout); | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | StrAllocString(&vrgRetryInfo[type].sczId, wzPackageId, 0); | ||
70 | if (wzPayloadId) | ||
71 | { | ||
72 | StrAllocString(&vrgRetryInfo[type].sczPayloadId, wzPayloadId, 0); | ||
73 | } | ||
74 | |||
75 | vrgRetryInfo[type].cRetries = 0; | ||
76 | } | ||
77 | |||
78 | vrgRetryInfo[type].dwLastError = ERROR_SUCCESS; | ||
79 | } | ||
80 | |||
81 | |||
82 | DAPI_(void) BalRetryErrorOccurred( | ||
83 | __in_z LPCWSTR wzPackageId, | ||
84 | __in DWORD dwError | ||
85 | ) | ||
86 | { | ||
87 | if (IsActiveRetryEntry(BALRETRY_TYPE_CACHE, wzPackageId, NULL)) | ||
88 | { | ||
89 | vrgRetryInfo[BALRETRY_TYPE_CACHE].dwLastError = dwError; | ||
90 | } | ||
91 | else if (IsActiveRetryEntry(BALRETRY_TYPE_EXECUTE, wzPackageId, NULL)) | ||
92 | { | ||
93 | vrgRetryInfo[BALRETRY_TYPE_EXECUTE].dwLastError = dwError; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | |||
98 | DAPI_(HRESULT) BalRetryEndPackage( | ||
99 | __in BALRETRY_TYPE type, | ||
100 | __in_z_opt LPCWSTR wzPackageId, | ||
101 | __in_z_opt LPCWSTR wzPayloadId, | ||
102 | __in HRESULT hrError, | ||
103 | __inout BOOL* pfRetry | ||
104 | ) | ||
105 | { | ||
106 | HRESULT hr = S_OK; | ||
107 | |||
108 | if (!wzPackageId || !*wzPackageId) | ||
109 | { | ||
110 | ReleaseNullStr(vrgRetryInfo[type].sczId); | ||
111 | ReleaseNullStr(vrgRetryInfo[type].sczPayloadId); | ||
112 | } | ||
113 | else if (FAILED(hrError) && vrgRetryInfo[type].cRetries < vdwMaxRetries && IsActiveRetryEntry(type, wzPackageId, wzPayloadId)) | ||
114 | { | ||
115 | if (BALRETRY_TYPE_CACHE == type) | ||
116 | { | ||
117 | // Retry on all errors except the following. | ||
118 | if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) != hrError && | ||
119 | BG_E_NETWORK_DISCONNECTED != hrError && | ||
120 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrError && | ||
121 | HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED) != hrError) | ||
122 | { | ||
123 | *pfRetry = TRUE; | ||
124 | } | ||
125 | } | ||
126 | else if (BALRETRY_TYPE_EXECUTE == type) | ||
127 | { | ||
128 | // If the service is out of whack, just try again. | ||
129 | if (HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hrError) | ||
130 | { | ||
131 | *pfRetry = TRUE; | ||
132 | } | ||
133 | else if (HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE) == hrError) | ||
134 | { | ||
135 | DWORD dwError = vrgRetryInfo[type].dwLastError; | ||
136 | |||
137 | // If we failed with one of these specific error codes, then retry since | ||
138 | // we've seen these have a high success of succeeding on retry. | ||
139 | if (1303 == dwError || | ||
140 | 1304 == dwError || | ||
141 | 1306 == dwError || | ||
142 | 1307 == dwError || | ||
143 | 1309 == dwError || | ||
144 | 1310 == dwError || | ||
145 | 1311 == dwError || | ||
146 | 1312 == dwError || | ||
147 | 1316 == dwError || | ||
148 | 1317 == dwError || | ||
149 | 1321 == dwError || | ||
150 | 1335 == dwError || | ||
151 | 1402 == dwError || | ||
152 | 1406 == dwError || | ||
153 | 1606 == dwError || | ||
154 | 1706 == dwError || | ||
155 | 1719 == dwError || | ||
156 | 1723 == dwError || | ||
157 | 1923 == dwError || | ||
158 | 1931 == dwError) | ||
159 | { | ||
160 | *pfRetry = TRUE; | ||
161 | } | ||
162 | } | ||
163 | else if (HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hrError) | ||
164 | { | ||
165 | *pfRetry = TRUE; | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | return hr; | ||
171 | } | ||
172 | |||
173 | |||
174 | // Internal functions. | ||
175 | |||
176 | static BOOL IsActiveRetryEntry( | ||
177 | __in BALRETRY_TYPE type, | ||
178 | __in_z LPCWSTR wzPackageId, | ||
179 | __in_z_opt LPCWSTR wzPayloadId | ||
180 | ) | ||
181 | { | ||
182 | BOOL fActive = FALSE; | ||
183 | |||
184 | fActive = vrgRetryInfo[type].sczId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, vrgRetryInfo[type].sczId, -1); | ||
185 | if (fActive && wzPayloadId) // if a payload id was provided ensure it matches. | ||
186 | { | ||
187 | fActive = vrgRetryInfo[type].sczPayloadId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPayloadId, -1, vrgRetryInfo[type].sczPayloadId, -1); | ||
188 | } | ||
189 | |||
190 | return fActive; | ||
191 | } | ||