Sync DrDump crash handler with TortoiseSVN codebase
[TortoiseGit.git] / ext / CrashServer / CrashHandler / SendRpt / DoctorDump.cpp
blobfddc6a360dfdca637266c45254e5fc720f4d3fa3
1 // Copyright 2014 Idol Software, Inc.
2 //
3 // This file is part of Doctor Dump SDK.
4 //
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stdafx.h"
19 #include "DoctorDump.h"
20 #include "..\..\CommonLibs\Log\log.h"
21 #include "..\..\CommonLibs\Zlib\ZipUnzip.h"
23 using namespace std;
24 using namespace doctor_dump;
26 class ProgressNotifier
28 public:
29 ProgressNotifier(DumpUploaderWebService& webService, size_t total, IUploadProgress& uploadProgress)
30 : m_webService(webService), m_sent(0), m_total(total), m_uploadProgress(uploadProgress)
32 m_webService.SetProgressCallback(ProgressCallback, this);
35 ~ProgressNotifier()
37 m_webService.SetProgressCallback(nullptr, nullptr);
40 private:
41 size_t m_sent;
42 size_t m_total;
43 IUploadProgress& m_uploadProgress;
44 DumpUploaderWebService& m_webService;
46 static void ProgressCallback(BOOL send, SIZE_T bytesCount, LPVOID context)
48 static_cast<ProgressNotifier*>(context)->ProgressCallback(send, bytesCount);
51 void ProgressCallback(BOOL send, SIZE_T bytesCount)
53 if (!send)
54 return;
55 m_sent += bytesCount;
56 if (m_sent > m_total)
57 m_sent = m_total;
59 m_uploadProgress.OnProgress(m_total, m_sent);
63 std::vector<unsigned char> DumpUploaderWebServiceEx::ReadFile(const std::wstring& path)
65 std::vector<unsigned char> data;
67 CAtlFile file;
68 for (int i = 0; ; ++i)
70 file.Attach(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
71 if (file != INVALID_HANDLE_VALUE)
72 break;
74 DWORD err = GetLastError();
75 // File indexing services like to open just closed files (our doctor_dump_mini.zip file), so lets make few tries.
76 if (err == ERROR_SHARING_VIOLATION && i < 10)
78 Sleep(1000);
79 continue;
81 CStringA text;
82 text.Format("failed (err %d) to open file %ls", err, path.c_str());
83 throw std::runtime_error(text);
87 ULONGLONG fileSize;
88 if (FAILED(file.GetSize(fileSize)))
89 throw std::runtime_error(std::string("failed to get file size ") + (const char*)CW2A(path.c_str()));
91 if (fileSize != 0)
93 data.resize((size_t)fileSize);
94 if (FAILED(file.Read(&data[0], static_cast<DWORD>(fileSize))))
95 throw std::runtime_error(std::string("failed to read file ") + (const char*)CW2A(path.c_str()));
98 return data;
101 std::unique_ptr<Response> Response::CreateResponse(const ns1__Response& response, Log& log)
103 std::unique_ptr<Response> result;
104 if (SOAP_TYPE_ns1__HaveSolutionResponse == response.soap_type())
106 log.Debug(_T("\thas solution"));
107 const ns1__HaveSolutionResponse& resp = static_cast<const ns1__HaveSolutionResponse&>(response);
108 std::unique_ptr<HaveSolutionResponse> res(new HaveSolutionResponse);
109 res->askConfirmation = resp.askConfirmation;
110 res->type = resp.type;
111 log.Debug(_T("\t\ttype\t%d"), res->type);
112 if (resp.url)
114 res->url = resp.url->c_str();
115 log.Debug(_T("\t\tURL\t%ls"), res->url.c_str());
117 if (resp.exe)
119 res->exe.assign(resp.exe->__ptr, resp.exe->__ptr + resp.exe->__size);
120 log.Debug(_T("\t\thas EXE, size\t%d"), res->exe.size());
122 result = std::move(res);
124 else if (SOAP_TYPE_ns1__NeedSymbolsThenMiniDumpResponse == response.soap_type() || SOAP_TYPE_ns1__NeedMiniDumpResponse == response.soap_type())
126 result.reset(new NeedMiniDumpResponse);
128 else if (SOAP_TYPE_ns1__NeedFullDumpResponse == response.soap_type())
130 const ns1__NeedFullDumpResponse& resp = static_cast<const ns1__NeedFullDumpResponse&>(response);
131 std::unique_ptr<NeedFullDumpResponse> res(new NeedFullDumpResponse);
133 res->restrictedDumpType = resp.restrictedDumpType;
134 res->attachUserInfo = resp.attachUserInfo;
136 result = std::move(res);
138 else if (SOAP_TYPE_ns1__NeedMoreInfoResponse == response.soap_type())
140 const ns1__NeedMoreInfoResponse& resp = static_cast<const ns1__NeedMoreInfoResponse&>(response);
141 std::unique_ptr<NeedMoreInfoResponse> res(new NeedMoreInfoResponse);
142 if (resp.infoModule && resp.infoModule->__size > 0)
143 res->infoModule.assign(resp.infoModule->__ptr, resp.infoModule->__ptr + resp.infoModule->__size);
144 else
145 res->infoModule.clear();
146 if (resp.infoModuleCfg)
147 res->infoModuleCfg = resp.infoModuleCfg->c_str();
148 else
149 res->infoModuleCfg = L"";
150 result = std::move(res);
152 else if (SOAP_TYPE_ns1__StopResponse == response.soap_type())
154 result.reset(new StopResponse);
156 else if (SOAP_TYPE_ns1__ErrorResponse == response.soap_type())
158 const ns1__ErrorResponse& resp = static_cast<const ns1__ErrorResponse&>(response);
159 std::unique_ptr<ErrorResponse> res(new ErrorResponse);
160 res->error = *resp.error;
161 log.Debug(_T("\terror\t\"%ls\""), res->error.c_str());
162 result = std::move(res);
164 else
166 throw std::runtime_error("unknown response type");
169 if (response.clientID)
171 result->clientID = *response.clientID;
172 log.Debug(_T("\tCliendID = \"%ls\""), result->clientID.c_str());
174 result->problemID = response.problemID ? *response.problemID : 0;
175 result->dumpGroupID = response.dumpGroupID ? *response.dumpGroupID : 0;
176 result->dumpID = response.dumpID ? *response.dumpID : 0;
177 log.Debug(_T("\tproblemID = %d, dumpGroupID = %d, dumpID = %d"), result->problemID, result->dumpGroupID, result->dumpID);
178 if (response.urlToProblem)
180 result->urlToProblem = *response.urlToProblem;
181 log.Debug(_T("\tURL to problem = \"%ls\""), result->urlToProblem.c_str());
183 else
185 result->urlToProblem = L"";
187 if (response.context && response.context->__size > 0)
188 result->context.assign(response.context->__ptr, response.context->__ptr + response.context->__size);
189 else
190 result->context.clear();
192 return result;
195 _xop__Include* DumpUploaderWebServiceEx::CreateXopInclude(DeferredDelete& context, const std::vector<BYTE>& data)
197 SOAP_SHARED_STRUCT(_xop__Include, ptr);
198 context.emplace_back(ptr);
200 _xop__Include* soapXop = ptr->get();
201 if (!data.empty())
203 soapXop->__ptr = const_cast<BYTE*>(data.data());
204 soapXop->__size = static_cast<int>(data.size());
206 else
208 soapXop->__ptr = NULL;
209 soapXop->__size = 0;
211 soapXop->id = NULL;
212 soapXop->options = NULL;
213 soapXop->type = "binary";
215 return soapXop;
218 _xop__Include* DumpUploaderWebServiceEx::CreateXopIncludeFromFile(DeferredDelete& context, const std::wstring& path)
220 std::shared_ptr<std::vector<unsigned char>> data(std::make_shared<std::vector<unsigned char>>(ReadFile(path)));
222 _xop__Include* soapXop = CreateXopInclude(context, *data.get());
223 ((soap_helpers::SoapStuct<_xop__Include>*) context.back().get())->m_data = data;
225 return soapXop;
228 DumpUploaderWebServiceEx::DumpUploaderWebServiceEx(Log& log_)
229 : m_webService(5*60 /* Parsing a dump may require a lot of time (for example if symbols are uploaded from microsoft) */)
230 , m_log(log_)
234 ns1__ClientLib* DumpUploaderWebServiceEx::CreateClientLib(DeferredDelete& context)
236 SOAP_SHARED_STRUCT(ns1__ClientLib, ptr);
237 context.emplace_back(ptr);
239 ns1__ClientLib* soapClient = ptr->get();
240 soapClient->type = ns4__ClientLib_ClientType__CrashHandler_1_0;
241 soapClient->v1 = 0;
242 soapClient->v2 = 0;
243 soapClient->v3 = 0;
244 soapClient->v4 = 0;
245 soapClient->arch =
246 #ifdef _M_AMD64
247 ns4__ClientLib_Architecture__x64
248 #else
249 ns4__ClientLib_Architecture__x86
250 #endif
253 TCHAR path[MAX_PATH];
254 if (!GetModuleFileName(NULL, path, _countof(path)))
255 return soapClient;
257 std::vector<BYTE> verInfo(GetFileVersionInfoSize(path, NULL));
258 VS_FIXEDFILEINFO* lpFileinfo = NULL;
259 UINT uLen;
260 if (verInfo.empty()
261 || !GetFileVersionInfo(path, 0, static_cast<DWORD>(verInfo.size()), &verInfo[0])
262 || !VerQueryValue(&verInfo[0], _T("\\"), (LPVOID*)&lpFileinfo, &uLen))
263 return soapClient;
264 soapClient->v1 = HIWORD(lpFileinfo->dwProductVersionMS);
265 soapClient->v2 = LOWORD(lpFileinfo->dwProductVersionMS);
266 soapClient->v3 = HIWORD(lpFileinfo->dwProductVersionLS);
267 soapClient->v4 = LOWORD(lpFileinfo->dwProductVersionLS);
268 m_log.Info(_T("Client lib %d.%d.%d.%d"), soapClient->v1, soapClient->v2, soapClient->v3, soapClient->v4);
270 return soapClient;
273 ns1__Application* DumpUploaderWebServiceEx::CreateApp(DeferredDelete& context, const Application& app)
275 SOAP_SHARED_STRUCT(ns1__Application, ptr);
276 context.emplace_back(ptr);
278 std::shared_ptr<std::wstring> pMainModule(std::make_shared<std::wstring>(app.processName));
279 ptr->m_data = pMainModule;
281 ns1__Application* soapApp = ptr->get();
282 soapApp->applicationGUID = app.applicationGUID;
283 soapApp->v1 = app.v[0];
284 soapApp->v2 = app.v[1];
285 soapApp->v3 = app.v[2];
286 soapApp->v4 = app.v[3];
287 soapApp->hotfix = app.hotfix;
288 soapApp->mainModule = pMainModule.get();
289 m_log.Info(_T("App %d.%d.%d.%d %ls"), soapApp->v1, soapApp->v2, soapApp->v3, soapApp->v4, soapApp->applicationGUID.c_str());
290 return soapApp;
293 ns1__AppAdditionalInfo* DumpUploaderWebServiceEx::CreateAppAddInfo(DeferredDelete& context, std::wstring& appName, std::wstring& companyName)
295 SOAP_SHARED_STRUCT(ns1__AppAdditionalInfo, ptr);
296 context.emplace_back(ptr);
298 ns1__AppAdditionalInfo* soapAppAddInfo = ptr->get();
299 soapAppAddInfo->appName = &appName;
300 soapAppAddInfo->companyName = &companyName;
301 return soapAppAddInfo;
304 ns1__DumpAdditionalInfo* DumpUploaderWebServiceEx::CreateDumpAddInfo(DeferredDelete& context, const DumpAdditionalInfo &dumpAddInfo)
306 SOAP_SHARED_STRUCT(ns1__DumpAdditionalInfo, ptr);
307 context.emplace_back(ptr);
309 ns1__DumpAdditionalInfo* soapAddInfo = ptr->get();
310 soapAddInfo->crashDate = dumpAddInfo.crashDate;
311 soapAddInfo->PCID = dumpAddInfo.PCID;
312 soapAddInfo->submitterID = dumpAddInfo.submitterID;
313 soapAddInfo->group = const_cast<std::wstring*>(&dumpAddInfo.group);
314 soapAddInfo->description = const_cast<std::wstring*>(&dumpAddInfo.description);
315 return soapAddInfo;
318 void DumpUploaderWebServiceEx::ThrowOnSoapFail(int res)
320 if (res != SOAP_OK)
321 throw SoapException(m_webService.error, (const char*)CW2A(m_webService.GetErrorText().c_str()));
324 std::unique_ptr<Response> DumpUploaderWebServiceEx::Hello(
325 const Application& app,
326 std::wstring appName,
327 std::wstring companyName,
328 const DumpAdditionalInfo& addInfo)
330 m_log.Info(_T("Sending Hello..."));
332 DeferredDelete deleteList;
334 SOAP_STRUCT(_ns1__Hello, request);
335 request->clientLib = CreateClientLib(deleteList);
336 request->app = CreateApp(deleteList, app);
337 request->appAddInfo = CreateAppAddInfo(deleteList, appName, companyName);
338 request->addInfo = CreateDumpAddInfo(deleteList, addInfo);
340 SOAP_STRUCT(_ns1__HelloResponse, response);
341 ThrowOnSoapFail(m_webService.Hello(request, response));
343 return Response::CreateResponse(*response->HelloResult, m_log);
346 std::unique_ptr<Response> DumpUploaderWebServiceEx::UploadMiniDump(const std::vector<BYTE>& context, const Application& app, const DumpAdditionalInfo& addInfo, const std::wstring& dumpFile)
348 m_log.Info(_T("Sending UploadMiniDump..."));
350 DeferredDelete deleteList;
352 SOAP_STRUCT(_ns1__UploadMiniDump, request);
353 request->client = CreateClientLib(deleteList);
354 request->app = CreateApp(deleteList, app);
355 request->addInfo = CreateDumpAddInfo(deleteList, addInfo);
356 request->dump = CreateXopIncludeFromFile(deleteList, dumpFile);
357 request->context = CreateXopInclude(deleteList, context);
359 SOAP_STRUCT(_ns1__UploadMiniDumpResponse, response);
360 ThrowOnSoapFail(m_webService.UploadMiniDump(request, response));
362 return Response::CreateResponse(*response->UploadMiniDumpResult, m_log);
365 std::unique_ptr<Response> DumpUploaderWebServiceEx::UploadFullDump(const std::vector<BYTE>& context, const Application& app, int miniDumpId, const std::wstring& fullDumpZipPath, IUploadProgress* uploadProgress)
367 m_log.Info(_T("Sending UploadFullDump..."));
369 DeferredDelete deleteList;
371 SOAP_STRUCT(_ns1__UploadFullDump, request);
372 request->client = CreateClientLib(deleteList);
373 request->app = CreateApp(deleteList, app);
374 request->miniDumpID = &miniDumpId;
375 request->dumpInZip = CreateXopIncludeFromFile(deleteList, fullDumpZipPath);
376 request->context = CreateXopInclude(deleteList, context);
378 std::unique_ptr<ProgressNotifier> scopedProgress;
379 if (uploadProgress)
380 scopedProgress.reset(new ProgressNotifier(m_webService, request->dumpInZip->__size, *uploadProgress));
382 SOAP_STRUCT(_ns1__UploadFullDumpResponse, response);
383 ThrowOnSoapFail(m_webService.UploadFullDump(request, response));
385 return Response::CreateResponse(*response->UploadFullDumpResult, m_log);
388 std::unique_ptr<Response> DumpUploaderWebServiceEx::UploadAdditionalInfo(const std::vector<BYTE>& context, const Application& app, int miniDumpId, const std::wstring& addInfoFile, IUploadProgress* uploadProgress)
390 m_log.Info(_T("Sending UploadAdditionalInfo..."));
392 DeferredDelete deleteList;
394 SOAP_STRUCT(_ns1__UploadAdditionalInfo, request);
395 request->client = CreateClientLib(deleteList);
396 request->app = CreateApp(deleteList, app);
397 request->miniDumpID = &miniDumpId;
398 request->info = CreateXopIncludeFromFile(deleteList, addInfoFile);
399 request->context = CreateXopInclude(deleteList, context);
401 std::unique_ptr<ProgressNotifier> scopedProgress;
402 if (uploadProgress)
403 scopedProgress.reset(new ProgressNotifier(m_webService, request->info->__size, *uploadProgress));
405 SOAP_STRUCT(_ns1__UploadAdditionalInfoResponse, response);
406 ThrowOnSoapFail(m_webService.UploadAdditionalInfo(request, response));
408 return Response::CreateResponse(*response->UploadAdditionalInfoResult, m_log);
411 std::unique_ptr<Response> DumpUploaderWebServiceEx::RejectedToSendAdditionalInfo(const std::vector<BYTE>& context, const Application& app, int miniDumpId)
413 m_log.Info(_T("Sending SendAdditionalInfoUploadRejected..."));
415 DeferredDelete deleteList;
417 SOAP_STRUCT(_ns1__RejectedToSendAdditionalInfo, request);
418 request->client = CreateClientLib(deleteList);
419 request->app = CreateApp(deleteList, app);
420 request->miniDumpID = &miniDumpId;
421 request->context = CreateXopInclude(deleteList, context);
423 SOAP_STRUCT(_ns1__RejectedToSendAdditionalInfoResponse, response);
424 ThrowOnSoapFail(m_webService.RejectedToSendAdditionalInfo(request, response));
426 return Response::CreateResponse(*response->RejectedToSendAdditionalInfoResult, m_log);