summaryrefslogtreecommitdiff
path: root/src/api/burn/balutil/balretry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/burn/balutil/balretry.cpp')
-rw-r--r--src/api/burn/balutil/balretry.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/api/burn/balutil/balretry.cpp b/src/api/burn/balutil/balretry.cpp
new file mode 100644
index 00000000..9d8abd6d
--- /dev/null
+++ b/src/api/burn/balutil/balretry.cpp
@@ -0,0 +1,246 @@
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
5typedef enum BALRETRY_TYPE
6{
7 BALRETRY_TYPE_CACHE_CONTAINER,
8 BALRETRY_TYPE_CACHE_PAYLOAD,
9 BALRETRY_TYPE_EXECUTE,
10} BALRETRY_TYPE;
11
12struct BALRETRY_INFO
13{
14 LPWSTR sczId;
15 DWORD cRetries;
16 DWORD dwLastError;
17};
18
19static DWORD vdwMaxRetries = 0;
20static DWORD vdwTimeout = 0;
21static BALRETRY_INFO vrgRetryInfo[3];
22
23// prototypes
24static BOOL IsActiveRetryEntry(
25 __in BALRETRY_TYPE type,
26 __in_z LPCWSTR sczId
27 );
28
29static HRESULT StartActiveRetryEntry(
30 __in BALRETRY_TYPE type,
31 __in_z LPCWSTR sczId
32 );
33
34
35DAPI_(void) BalRetryInitialize(
36 __in DWORD dwMaxRetries,
37 __in DWORD dwTimeout
38 )
39{
40 BalRetryUninitialize(); // clean everything out.
41
42 vdwMaxRetries = dwMaxRetries;
43 vdwTimeout = dwTimeout;
44}
45
46
47DAPI_(void) BalRetryUninitialize()
48{
49 for (DWORD i = 0; i < countof(vrgRetryInfo); ++i)
50 {
51 ReleaseStr(vrgRetryInfo[i].sczId);
52 memset(vrgRetryInfo + i, 0, sizeof(BALRETRY_INFO));
53 }
54
55 vdwMaxRetries = 0;
56 vdwTimeout = 0;
57}
58
59
60DAPI_(void) BalRetryStartContainerOrPayload(
61 __in_z_opt LPCWSTR wzContainerOrPackageId,
62 __in_z_opt LPCWSTR wzPayloadId
63 )
64{
65 if (!wzContainerOrPackageId && !wzPayloadId)
66 {
67 ReleaseNullStr(vrgRetryInfo[BALRETRY_TYPE_CACHE_CONTAINER].sczId);
68 ReleaseNullStr(vrgRetryInfo[BALRETRY_TYPE_CACHE_PAYLOAD].sczId);
69 }
70 else if (wzPayloadId)
71 {
72 StartActiveRetryEntry(BALRETRY_TYPE_CACHE_PAYLOAD, wzPayloadId);
73 }
74 else
75 {
76 StartActiveRetryEntry(BALRETRY_TYPE_CACHE_CONTAINER, wzContainerOrPackageId);
77 }
78}
79
80
81DAPI_(void) BalRetryStartPackage(
82 __in_z LPCWSTR wzPackageId
83 )
84{
85 StartActiveRetryEntry(BALRETRY_TYPE_EXECUTE, wzPackageId);
86}
87
88
89DAPI_(void) BalRetryErrorOccurred(
90 __in_z LPCWSTR wzPackageId,
91 __in DWORD dwError
92 )
93{
94 if (IsActiveRetryEntry(BALRETRY_TYPE_EXECUTE, wzPackageId))
95 {
96 vrgRetryInfo[BALRETRY_TYPE_EXECUTE].dwLastError = dwError;
97 }
98}
99
100
101DAPI_(HRESULT) BalRetryEndContainerOrPayload(
102 __in_z_opt LPCWSTR wzContainerOrPackageId,
103 __in_z_opt LPCWSTR wzPayloadId,
104 __in HRESULT hrError,
105 __inout BOOL* pfRetry
106 )
107{
108 HRESULT hr = S_OK;
109 BALRETRY_TYPE type = BALRETRY_TYPE_CACHE_PAYLOAD;
110 LPCWSTR wzId = NULL;
111
112 if (!wzContainerOrPackageId && !wzPayloadId)
113 {
114 ReleaseNullStr(vrgRetryInfo[BALRETRY_TYPE_CACHE_CONTAINER].sczId);
115 ReleaseNullStr(vrgRetryInfo[BALRETRY_TYPE_CACHE_PAYLOAD].sczId);
116 ExitFunction();
117 }
118 else if (wzPayloadId)
119 {
120 type = BALRETRY_TYPE_CACHE_PAYLOAD;
121 wzId = wzPayloadId;
122 }
123 else
124 {
125 type = BALRETRY_TYPE_CACHE_CONTAINER;
126 wzId = wzContainerOrPackageId;
127 }
128
129 if (FAILED(hrError) && vrgRetryInfo[type].cRetries < vdwMaxRetries && IsActiveRetryEntry(type, wzId))
130 {
131 // Retry on all errors except the following.
132 if (HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) != hrError &&
133 BG_E_NETWORK_DISCONNECTED != hrError &&
134 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrError &&
135 HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED) != hrError)
136 {
137 *pfRetry = TRUE;
138 }
139 }
140
141LExit:
142 return hr;
143}
144
145
146DAPI_(HRESULT) BalRetryEndPackage(
147 __in_z LPCWSTR wzPackageId,
148 __in HRESULT hrError,
149 __inout BOOL* pfRetry
150 )
151{
152 HRESULT hr = S_OK;
153 BALRETRY_TYPE type = BALRETRY_TYPE_EXECUTE;
154
155 if (!wzPackageId || !*wzPackageId)
156 {
157 ReleaseNullStr(vrgRetryInfo[type].sczId);
158 }
159 else if (FAILED(hrError) && vrgRetryInfo[type].cRetries < vdwMaxRetries && IsActiveRetryEntry(type, wzPackageId))
160 {
161 // If the service is out of whack, just try again.
162 if (HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hrError)
163 {
164 *pfRetry = TRUE;
165 }
166 else if (HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE) == hrError)
167 {
168 DWORD dwError = vrgRetryInfo[type].dwLastError;
169
170 // If we failed with one of these specific error codes, then retry since
171 // we've seen these have a high success of succeeding on retry.
172 if (1303 == dwError ||
173 1304 == dwError ||
174 1306 == dwError ||
175 1307 == dwError ||
176 1309 == dwError ||
177 1310 == dwError ||
178 1311 == dwError ||
179 1312 == dwError ||
180 1316 == dwError ||
181 1317 == dwError ||
182 1321 == dwError ||
183 1335 == dwError ||
184 1402 == dwError ||
185 1406 == dwError ||
186 1606 == dwError ||
187 1706 == dwError ||
188 1719 == dwError ||
189 1723 == dwError ||
190 1923 == dwError ||
191 1931 == dwError)
192 {
193 *pfRetry = TRUE;
194 }
195 }
196 else if (HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hrError)
197 {
198 *pfRetry = TRUE;
199 }
200 }
201
202 return hr;
203}
204
205
206// Internal functions.
207
208static BOOL IsActiveRetryEntry(
209 __in BALRETRY_TYPE type,
210 __in_z LPCWSTR sczId
211 )
212{
213 BOOL fActive = FALSE;
214
215 fActive = vrgRetryInfo[type].sczId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, sczId, -1, vrgRetryInfo[type].sczId, -1);
216
217 return fActive;
218}
219
220static HRESULT StartActiveRetryEntry(
221 __in BALRETRY_TYPE type,
222 __in_z LPCWSTR sczId
223 )
224{
225 HRESULT hr = S_OK;
226
227 if (!sczId || !*sczId)
228 {
229 ReleaseNullStr(vrgRetryInfo[type].sczId);
230 }
231 else if (IsActiveRetryEntry(type, sczId))
232 {
233 ++vrgRetryInfo[type].cRetries;
234 ::Sleep(vdwTimeout);
235 }
236 else
237 {
238 hr = StrAllocString(&vrgRetryInfo[type].sczId, sczId, 0);
239
240 vrgRetryInfo[type].cRetries = 0;
241 }
242
243 vrgRetryInfo[type].dwLastError = ERROR_SUCCESS;
244
245 return hr;
246}