aboutsummaryrefslogtreecommitdiff
path: root/src/balutil/balretry.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/balutil/balretry.cpp191
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
5struct BALRETRY_INFO
6{
7 LPWSTR sczId; // package or container id.
8 LPWSTR sczPayloadId; // optional payload id.
9 DWORD cRetries;
10 DWORD dwLastError;
11};
12
13static DWORD vdwMaxRetries = 0;
14static DWORD vdwTimeout = 0;
15static BALRETRY_INFO vrgRetryInfo[2];
16
17// prototypes
18static BOOL IsActiveRetryEntry(
19 __in BALRETRY_TYPE type,
20 __in_z LPCWSTR wzPackageId,
21 __in_z_opt LPCWSTR wzPayloadId
22 );
23
24
25DAPI_(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
37DAPI_(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
51DAPI_(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
82DAPI_(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
98DAPI_(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
176static 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}