Fixed thrown errot on file download job cancelation throught server job view + Change...
[public/netxms.git] / src / server / core / download_job.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 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 General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: download_job.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Constructor for download job
27 */
28 FileDownloadJob::FileDownloadJob(Node *node, const TCHAR *remoteFile, UINT32 maxFileSize, bool follow, ClientSession *session, UINT32 requestId)
29 : ServerJob(_T("DOWNLOAD_FILE"), _T("Download file"), node->getId(), session->getUserId(), false)
30 {
31 m_session = session;
32 session->incRefCount();
33
34 m_agentConnection = NULL;
35
36 m_node = node;
37 node->incRefCount();
38
39 m_requestId = requestId;
40
41 m_remoteFile = _tcsdup(remoteFile);
42
43 TCHAR buffer[1024];
44 buildServerFileName(node->getId(), m_remoteFile, buffer, 1024);
45 m_localFile = _tcsdup(buffer);
46
47 _sntprintf(buffer, 1024, _T("Download file %s@%s"), m_remoteFile, node->getName());
48 setDescription(buffer);
49
50 _sntprintf(buffer, 1024, _T("Local file: %s; Remote file: %s"), m_localFile, m_remoteFile);
51 m_info = _tcsdup(buffer);
52
53 setAutoCancelDelay(60);
54
55 m_maxFileSize = maxFileSize;
56 m_follow = follow;
57 m_currentSize = 0;
58
59 DbgPrintf(5, _T("FileDownloadJob: job created for file %s at node %s, follow = %s"), m_remoteFile, m_node->getName(), m_follow ? _T("true") : _T("false"));
60 }
61
62 /**
63 * Destructor for download job
64 */
65 FileDownloadJob::~FileDownloadJob()
66 {
67 m_node->decRefCount();
68 m_session->decRefCount();
69 if (m_agentConnection != NULL)
70 m_agentConnection->decRefCount();
71 free(m_localFile);
72 free(m_remoteFile);
73 free(m_info);
74 }
75
76 /**
77 * Returns localFileName
78 */
79 const TCHAR *FileDownloadJob::getLocalFileName()
80 {
81 return m_localFile;
82 }
83
84 /**
85 * Send message callback
86 */
87 void FileDownloadJob::fileResendCallback(NXCP_MESSAGE *msg, void *arg)
88 {
89 msg->id = htonl(((FileDownloadJob *)arg)->m_requestId);
90 ((FileDownloadJob *)arg)->m_session->sendRawMessage(msg);
91 }
92
93 /**
94 * Progress callback
95 */
96 void FileDownloadJob::progressCallback(size_t size, void *arg)
97 {
98 ((FileDownloadJob *)arg)->m_currentSize += (INT64)size;
99 if (((FileDownloadJob *)arg)->m_fileSize > 0)
100 ((FileDownloadJob *)arg)->markProgress((int)(((FileDownloadJob *)arg)->m_currentSize * _LL(90) / ((FileDownloadJob *)arg)->m_fileSize));
101 else
102 ((FileDownloadJob *)arg)->markProgress(90);
103 }
104
105 /**
106 * Job implementation
107 */
108 ServerJobResult FileDownloadJob::run()
109 {
110 UINT32 rcc = 0xFFFFFFFF;
111 ServerJobResult success = JOB_RESULT_FAILED;
112
113 MONITORED_FILE * newFile = new MONITORED_FILE();
114 _tcscpy(newFile->fileName, m_localFile);
115 newFile->nodeID = m_node->getId();
116 newFile->session = m_session;
117
118 if (g_monitoringList.checkDuplicate(newFile))
119 {
120 DbgPrintf(6, _T("FileDownloadJob: follow flag cancelled by checkDuplicate()"));
121 m_follow = false;
122 }
123
124 m_agentConnection = m_node->createAgentConnection();
125 if (m_agentConnection != NULL)
126 {
127 NXCPMessage msg(m_agentConnection->getProtocolVersion()), *response;
128
129 m_agentConnection->setDeleteFileOnDownloadFailure(false);
130
131 DbgPrintf(5, _T("FileDownloadJob: Sending file stat request for file %s@%s"), m_remoteFile, m_node->getName());
132 msg.setCode(CMD_GET_FILE_DETAILS);
133 msg.setId(m_agentConnection->generateRequestId());
134 msg.setField(VID_FILE_NAME, m_remoteFile);
135 response = m_agentConnection->customRequest(&msg);
136 if (response != NULL)
137 {
138 NXCPMessage notify;
139 m_fileSize = (INT64)response->getFieldAsUInt64(VID_FILE_SIZE);
140 notify.setCode(CMD_REQUEST_COMPLETED);
141 notify.setId(m_requestId);
142 notify.setField(VID_FILE_SIZE, m_fileSize);
143 m_session->sendMessage(&notify);
144
145 rcc = response->getFieldAsUInt32(VID_RCC);
146 DbgPrintf(5, _T("FileDownloadJob: Stat request for file %s@%s RCC=%d"), m_remoteFile, m_node->getName(), rcc);
147 if (rcc == ERR_SUCCESS)
148 {
149 delete response;
150
151 DbgPrintf(5, _T("FileDownloadJob: Sending download request for file %s@%s"), m_remoteFile, m_node->getName());
152 msg.setCode(CMD_GET_AGENT_FILE);
153 msg.setId(m_agentConnection->generateRequestId());
154 msg.setField(VID_FILE_NAME, m_remoteFile);
155
156 // default - get parameters
157 if (m_maxFileSize > 0)
158 {
159 msg.setField(VID_FILE_OFFSET, (UINT32)(-((int)m_maxFileSize)));
160 }
161 else
162 {
163 msg.setField(VID_FILE_OFFSET, 0);
164 }
165 msg.setField(VID_FILE_FOLLOW, m_follow);
166 msg.setField(VID_NAME, m_localFile);
167 msg.setField(VID_ENABLE_COMPRESSION, (m_session == NULL) || m_session->isCompressionEnabled());
168
169 response = m_agentConnection->customRequest(&msg, m_localFile, false, progressCallback, fileResendCallback, this);
170 if (response != NULL)
171 {
172 rcc = response->getFieldAsUInt32(VID_RCC);
173 DbgPrintf(5, _T("FileDownloadJob: Download request for file %s@%s RCC=%d"), m_remoteFile, m_node->getName(), rcc);
174 if (rcc == ERR_SUCCESS)
175 {
176 success = JOB_RESULT_SUCCESS;
177 }
178 else if(getStatus() != JOB_CANCELLED && getStatus() != JOB_CANCEL_PENDING)
179 {
180 TCHAR buffer[1024];
181
182 _sntprintf(buffer, 1024, _T("Error %d: %s"), rcc, AgentErrorCodeToText((int)rcc));
183 setFailureMessage(buffer);
184 }
185 delete response;
186 }
187 else
188 {
189 setFailureMessage(_T("Request timed out"));
190 }
191 }
192 else
193 {
194 TCHAR buffer[1024];
195
196 _sntprintf(buffer, 1024, _T("Error %d: %s"), rcc, AgentErrorCodeToText((int)rcc));
197 setFailureMessage(buffer);
198
199 delete response;
200 }
201 }
202 else
203 {
204 setFailureMessage(_T("Request timed out"));
205 }
206 }
207 else
208 {
209 setFailureMessage(_T("Agent connection not available"));
210 }
211
212 NXCPMessage response;
213 response.setCode(CMD_REQUEST_COMPLETED);
214 response.setId(m_requestId);
215 if (success == JOB_RESULT_SUCCESS)
216 {
217 response.setField(VID_RCC, RCC_SUCCESS);
218 m_session->sendMessage(&response);
219 if (m_follow)
220 {
221 g_monitoringList.addMonitoringFile(newFile, m_node, m_agentConnection);
222 }
223 else
224 {
225 delete newFile;
226 }
227 }
228 else
229 {
230 // Send "abort file transfer" command to client
231 NXCPMessage abortCmd;
232 abortCmd.setCode(CMD_ABORT_FILE_TRANSFER);
233 abortCmd.setId(m_requestId);
234 abortCmd.setField(VID_JOB_CANCELED, getStatus() != JOB_CANCELLED || getStatus() != JOB_CANCEL_PENDING);
235 m_session->sendMessage(&abortCmd);
236
237 if(getStatus() != JOB_CANCELLED || getStatus() != JOB_CANCEL_PENDING)
238 {
239 response.setField(VID_RCC, RCC_SUCCESS);
240 }
241 else
242 {
243 switch(rcc)
244 {
245 case ERR_ACCESS_DENIED:
246 response.setField(VID_RCC, RCC_ACCESS_DENIED);
247 break;
248 case ERR_IO_FAILURE:
249 response.setField(VID_RCC, RCC_IO_ERROR);
250 break;
251 case ERR_FILE_OPEN_ERROR:
252 case ERR_FILE_STAT_FAILED:
253 response.setField(VID_RCC, RCC_FILE_IO_ERROR);
254 break;
255 default:
256 response.setField(VID_RCC, RCC_COMM_FAILURE);
257 break;
258 }
259 }
260 m_session->sendMessage(&response);
261 }
262
263 if (m_agentConnection != NULL)
264 {
265 m_agentConnection->decRefCount();
266 m_agentConnection = NULL;
267 }
268 return success;
269 }
270
271 /**
272 * Job cancellation handler
273 */
274 bool FileDownloadJob::onCancel()
275 {
276 m_agentConnection->cancelFileDownload();
277 return true;
278 }
279
280 /**
281 * Get additional info for logging
282 */
283 const TCHAR *FileDownloadJob::getAdditionalInfo()
284 {
285 return m_info;
286 }
287
288 /**
289 * Build file ID
290 */
291 TCHAR *FileDownloadJob::buildServerFileName(UINT32 nodeId, const TCHAR *remoteFile, TCHAR *buffer, size_t bufferSize)
292 {
293 BYTE hash[MD5_DIGEST_SIZE];
294 TCHAR hashStr[128];
295
296 CalculateMD5Hash((BYTE *)remoteFile, _tcslen(remoteFile) * sizeof(TCHAR), hash);
297 _sntprintf(buffer, bufferSize, _T("agent_file_%u_%s"), nodeId, BinToStr(hash, MD5_DIGEST_SIZE, hashStr));
298 return buffer;
299 }