1 // Copyright 2014 Idol Software, Inc.
3 // This file is part of Doctor Dump SDK.
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.
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/>.
19 #include "DoctorDump.h"
20 #include "..\..\CommonLibs\Log\log.h"
21 #include "..\..\CommonLibs\Zlib\ZipUnzip.h"
24 using namespace doctor_dump
;
26 class ProgressNotifier
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);
37 m_webService
.SetProgressCallback(nullptr, nullptr);
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
)
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
;
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
)
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)
82 text
.Format("failed (err %d) to open file %ls", err
, path
.c_str());
83 throw std::runtime_error(text
);
88 if (FAILED(file
.GetSize(fileSize
)))
89 throw std::runtime_error(std::string("failed to get file size ") + (const char*)CW2A(path
.c_str()));
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()));
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
);
114 res
->url
= resp
.url
->c_str();
115 log
.Debug(_T("\t\tURL\t%ls"), res
->url
.c_str());
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
);
145 res
->infoModule
.clear();
146 if (resp
.infoModuleCfg
)
147 res
->infoModuleCfg
= resp
.infoModuleCfg
->c_str();
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
);
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());
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
);
190 result
->context
.clear();
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();
203 soapXop
->__ptr
= const_cast<BYTE
*>(data
.data());
204 soapXop
->__size
= static_cast<int>(data
.size());
208 soapXop
->__ptr
= NULL
;
212 soapXop
->options
= NULL
;
213 soapXop
->type
= "binary";
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
;
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) */)
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
;
247 ns4__ClientLib_Architecture__x64
249 ns4__ClientLib_Architecture__x86
253 TCHAR path
[MAX_PATH
];
254 if (!GetModuleFileName(NULL
, path
, _countof(path
)))
257 std::vector
<BYTE
> verInfo(GetFileVersionInfoSize(path
, NULL
));
258 VS_FIXEDFILEINFO
* lpFileinfo
= NULL
;
261 || !GetFileVersionInfo(path
, 0, static_cast<DWORD
>(verInfo
.size()), &verInfo
[0])
262 || !VerQueryValue(&verInfo
[0], _T("\\"), (LPVOID
*)&lpFileinfo
, &uLen
))
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
);
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());
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
);
318 void DumpUploaderWebServiceEx::ThrowOnSoapFail(int res
)
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
;
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
;
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
);