View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.protocol.localhandler;
21  
22  import org.waarp.common.command.exception.CommandAbstractException;
23  import org.waarp.common.database.exception.WaarpDatabaseException;
24  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
25  import org.waarp.common.digest.FilesystemBasedDigest;
26  import org.waarp.common.digest.FilesystemBasedDigest.DigestAlgo;
27  import org.waarp.common.exception.FileTransferException;
28  import org.waarp.common.file.DataBlock;
29  import org.waarp.common.logging.SysErrLogger;
30  import org.waarp.common.logging.WaarpLogger;
31  import org.waarp.common.logging.WaarpLoggerFactory;
32  import org.waarp.openr66.commander.ClientRunner;
33  import org.waarp.openr66.context.ErrorCode;
34  import org.waarp.openr66.context.R66Result;
35  import org.waarp.openr66.context.task.AbstractTask;
36  import org.waarp.openr66.context.task.TaskType;
37  import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
38  import org.waarp.openr66.database.data.DbRule;
39  import org.waarp.openr66.database.data.DbTaskRunner;
40  import org.waarp.openr66.protocol.configuration.Configuration;
41  import org.waarp.openr66.protocol.configuration.Messages;
42  import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
43  import org.waarp.openr66.protocol.exception.OpenR66DatabaseGlobalException;
44  import org.waarp.openr66.protocol.exception.OpenR66Exception;
45  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessException;
46  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessQueryAlreadyFinishedException;
47  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessQueryStillRunningException;
48  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoCorrectAuthenticationException;
49  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotAuthenticatedException;
50  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotYetConnectionException;
51  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
52  import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException;
53  import org.waarp.openr66.protocol.localhandler.packet.DataPacket;
54  import org.waarp.openr66.protocol.localhandler.packet.EndRequestPacket;
55  import org.waarp.openr66.protocol.localhandler.packet.EndTransferPacket;
56  import org.waarp.openr66.protocol.localhandler.packet.ErrorPacket;
57  import org.waarp.openr66.protocol.localhandler.packet.JsonCommandPacket;
58  import org.waarp.openr66.protocol.localhandler.packet.LocalPacketFactory;
59  import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
60  import org.waarp.openr66.protocol.localhandler.packet.ValidPacket;
61  import org.waarp.openr66.protocol.localhandler.packet.json.RequestJsonPacket;
62  import org.waarp.openr66.protocol.networkhandler.NetworkTransaction;
63  import org.waarp.openr66.protocol.utils.ChannelCloseTimer;
64  import org.waarp.openr66.protocol.utils.ChannelUtils;
65  import org.waarp.openr66.protocol.utils.FileUtils;
66  import org.waarp.openr66.protocol.utils.R66Future;
67  
68  import java.security.NoSuchAlgorithmException;
69  
70  import static org.waarp.common.database.DbConstant.*;
71  import static org.waarp.openr66.context.R66FiniteDualStates.*;
72  
73  /**
74   * Class to implement actions related to real transfer: request initialization,
75   * data transfer, end of transfer
76   * and of request, changing filename or filesize.
77   */
78  public class TransferActions extends ServerActions {
79    /**
80     * Internal Logger
81     */
82    private static final WaarpLogger logger =
83        WaarpLoggerFactory.getLogger(TransferActions.class);
84    public static final String RANK_SET = "Rank set: {}";
85    public static final String RUNNER_BEFORE_ANY_ACTION =
86        "Runner before any action: {} {}";
87  
88    public TransferActions() {
89      // nothing
90    }
91  
92    /**
93     * Finalize a request initialization in error
94     *
95     * @param code
96     * @param runner
97     * @param e1
98     * @param packet
99     *
100    * @throws OpenR66ProtocolPacketException
101    */
102   private void endInitRequestInError(final ErrorCode code,
103                                      final DbTaskRunner runner,
104                                      final OpenR66Exception e1,
105                                      final RequestPacket packet)
106       throws OpenR66ProtocolPacketException {
107     logger.error("TaskRunner initialisation in error: " + code.getMesg() + ' ' +
108                  session + " {} runner {}",
109                  e1 != null? e1.getMessage() : "no exception",
110                  runner != null? runner.toShortString() : "no runner");
111     logger.debug("DEBUG Full stack", e1);
112     localChannelReference.invalidateRequest(
113         new R66Result(e1, session, true, code, null));
114 
115     if (packet.isToValidate()) {
116       // / answer with a wrong request since runner is not set on remote host
117       if (runner != null) {
118         if (runner.isSender()) {
119           // In case Wildcard was used
120           logger.debug("New FILENAME: {}", runner.getOriginalFilename());
121           packet.setFilename(runner.getOriginalFilename());
122           logger.debug(RANK_SET, runner.getRank());
123           packet.setRank(runner.getRank());
124         } else {
125           logger.debug(RANK_SET, runner.getRank());
126           packet.setRank(runner.getRank());
127         }
128       }
129       packet.validate();
130       packet.setCode(code.code);
131       session.newState(ERROR);
132       ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
133                                             false);
134     } else {
135       session.newState(ERROR);
136       final ErrorPacket error = new ErrorPacket(
137           "TaskRunner initialisation in error: " +
138           (e1 != null? e1.getMessage() : "Unknown Error") + " for " + packet +
139           " since " + code.getMesg(), code.getCode(),
140           ErrorPacket.FORWARDCLOSECODE);
141       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
142                                             false);
143     }
144     session.setStatus(47);
145     ChannelCloseTimer.closeFutureTransaction(this);
146   }
147 
148   /**
149    * Receive a request of Transfer
150    *
151    * @param packet
152    *
153    * @throws OpenR66ProtocolPacketException
154    * @throws OpenR66ProtocolBusinessException
155    * @throws OpenR66ProtocolSystemException
156    * @throws OpenR66RunnerErrorException
157    */
158   public final void request(RequestPacket packet)
159       throws OpenR66ProtocolPacketException, OpenR66RunnerErrorException,
160              OpenR66ProtocolSystemException, OpenR66ProtocolBusinessException {
161     session.setStatus(99);
162     if (!session.isAuthenticated()) {
163       session.setStatus(48);
164       throw new OpenR66ProtocolNotAuthenticatedException(
165           Messages.getString("LocalServerHandler.3")); //$NON-NLS-1$
166     }
167     if (packet.isToValidate()) {
168       session.newState(REQUESTR);
169     }
170     // XXX validLimit only on requested side
171     if (checkRequest(packet)) {
172       return;
173     }
174     final DbRule rule;
175     try {
176       rule = new DbRule(packet.getRulename());
177     } catch (final WaarpDatabaseException e) {
178       logger.info("Rule is unknown: {} {}", packet.getRulename(),
179                   e.getMessage());
180       session.setStatus(49);
181       endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
182                             new OpenR66ProtocolBusinessException(
183                                 Messages.getString("LocalServerHandler.9") +
184                                 //$NON-NLS-1$
185                                 packet.getRulename()), packet);
186       return;
187     }
188     packet = computeBlockSizeFromRequest(packet, rule);
189     final DbTaskRunner runner;
190     // requested
191     final boolean isRetrieve = DbTaskRunner.getSenderByRequestPacket(packet);
192     if (packet.getSpecialId() != ILLEGALVALUE) {
193       runner = getPreviousDbTaskRunnerFromRequest(packet, rule, isRetrieve);
194       if (runner == null) {
195         return;
196       }
197     } else {
198       // Very new request
199       // should not be the case (the requester should always set the id)
200       logger.error("NO TransferID specified: SHOULD NOT BE THE CASE");
201       try {
202         runner = new DbTaskRunner(session, rule, isRetrieve, packet);
203       } catch (final WaarpDatabaseException e) {
204         session.setStatus(37);
205         endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
206                               new OpenR66DatabaseGlobalException(e), packet);
207         return;
208       }
209       packet.setSpecialId(runner.getSpecialId());
210     }
211     runner.setSender(isRetrieve);
212     logger.debug(RUNNER_BEFORE_ANY_ACTION, runner.shallIgnoreSave(), runner);
213     // Check now if request is a valid one
214     if (packet.getCode() != ErrorCode.InitOk.code) {
215       createErrorFromRequestInitKo(packet, runner);
216       return;
217     }
218     // Receiver can specify a rank different from database
219     setRankAtStartupFromRequest(packet, runner);
220     runner.setBlocksize(packet.getBlocksize());
221     logger.debug("Filesize: {}:{}", packet.getOriginalSize(),
222                  runner.isSender());
223     logger.debug("I am {} acting as sender {} while packet said {} and " +
224                  "runner said {} and session said {} but will changed",
225                  Configuration.configuration.getHostId(), isRetrieve,
226                  packet.isRetrieve(), runner.isSender(), session.isSender());
227     logger.debug(
228         "COMPRESSION was {} and could become {} while remote " + "host said {}",
229         session.isCompressionEnabled(),
230         AbstractTask.isCompressionRequested(runner.getFileInformation(),
231                                             session),
232         localChannelReference.getPartner());
233     session.setCompressionEnabled(
234         AbstractTask.isCompressionRequested(runner.getFileInformation(),
235                                             session));
236     runner.setBlockCompression(session.isCompressionEnabled());
237     try {
238       runner.update();
239     } catch (final WaarpDatabaseException ignored) {
240       // Ignore
241     }
242     boolean shouldInformBack = false;
243     try {
244       session.setRunner(runner);
245       if (packet.isToValidate() && isRetrieve && session.isSender() == false) {
246         logger.warn("isSend is True while requested is called on a {} mode",
247                     packet.isRetrieve()? "Retrieve" : "Receive");
248       }
249       // Fix to ensure that recv request are not trying to access to not chroot files
250       session.startup(Configuration.configuration.isChrootChecked() &&
251                       packet.isToValidate() && runner.isSender());
252       if (isRetrieve && !runner.isSendThrough()) {
253         if (packet.getOriginalSize() != runner.getOriginalSize()) {
254           packet.setOriginalSize(runner.getOriginalSize());
255           shouldInformBack = true;
256           logger.debug("Filesize2: {}:{}", packet.getOriginalSize(),
257                        runner.isSender());
258         }
259       }
260     } catch (final OpenR66RunnerErrorException e) {
261       try {
262         runner.saveStatus();
263       } catch (final OpenR66RunnerErrorException e1) {
264         logger.error("Cannot save Status: " + runner, e1);
265       }
266       if (runner.getErrorInfo() == ErrorCode.InitOk ||
267           runner.getErrorInfo() == ErrorCode.PreProcessingOk ||
268           runner.getErrorInfo() == ErrorCode.TransferOk) {
269         runner.setErrorExecutionStatus(ErrorCode.ExternalOp);
270       }
271       logger.error("PreTask in error {}", e.getMessage(), e);
272       errorToSend("PreTask in error: " + e.getMessage(), runner.getErrorInfo(),
273                   38);
274       return;
275     }
276     setFileSizeFromRequest(packet, runner, shouldInformBack);
277     session.setReady(true);
278     Configuration.configuration.getLocalTransaction()
279                                .setFromId(runner, localChannelReference);
280 
281     // Set read/write limit
282     final long remoteLimit = packet.getLimit();
283     long localLimit = localChannelReference.getChannelLimit(runner.isSender());
284     // Take the minimum speed
285     if (localLimit <= 0 || (remoteLimit > 0 && remoteLimit < localLimit)) {
286       localLimit = remoteLimit;
287     }
288     localChannelReference.setChannelLimit(runner.isSender(), localLimit);
289     packet.setLimit(localLimit);
290 
291     session.initializeDigest();
292     // inform back
293     informBackFromRequest(packet, runner);
294     if (!isRetrieve) {
295       prepareGlobalDigests();
296     }
297     // if retrieve => START the retrieve operation except if in Send Through mode
298     sendDataFromRequest(runner);
299     session.setStatus(39);
300   }
301 
302   private RequestPacket computeBlockSizeFromRequest(RequestPacket packet,
303                                                     final DbRule rule)
304       throws OpenR66ProtocolNoCorrectAuthenticationException {
305     int blocksize = packet.getBlocksize();
306     if (packet.isToValidate()) {
307       if (!rule.checkHostAllow(session.getAuth().getUser())) {
308         session.setStatus(30);
309         throw new OpenR66ProtocolNoCorrectAuthenticationException(
310             Messages.getString("LocalServerHandler.10")); //$NON-NLS-1$
311       }
312       // Check if the blocksize is greater than local value
313       if (Configuration.configuration.getBlockSize() < blocksize) {
314         logger.warn("Blocksize is greater than allowed {} < {}",
315                     Configuration.configuration.getBlockSize(), blocksize);
316         blocksize = Configuration.configuration.getBlockSize();
317         final String sep = localChannelReference.getPartner().getSeperator();
318         packet = new RequestPacket(packet.getRulename(), packet.getMode(),
319                                    packet.getFilename(), blocksize,
320                                    packet.getRank(), packet.getSpecialId(),
321                                    packet.getTransferInformation(),
322                                    packet.getOriginalSize(), sep);
323       }
324     }
325     if (!RequestPacket.isCompatibleMode(rule.getMode(), packet.getMode())) {
326       // not compatible Rule and mode in request
327       throw new OpenR66ProtocolNoCorrectAuthenticationException(
328           Messages.getString("LocalServerHandler.12") + rule.getMode() + " vs "
329           //$NON-NLS-1$
330           + packet.getMode());
331     }
332     session.setBlockSize(blocksize);
333     return packet;
334   }
335 
336   private boolean checkRequest(final RequestPacket packet)
337       throws OpenR66ProtocolPacketException {
338     if (packet.isToValidate()) {
339       if (Configuration.configuration.isShutdown()) {
340         logger.warn(Messages.getString("LocalServerHandler.7") //$NON-NLS-1$
341                     + packet.getRulename() + " from " + session.getAuth());
342         session.setStatus(100);
343         endInitRequestInError(ErrorCode.ServerOverloaded, null,
344                               new OpenR66ProtocolNotYetConnectionException(
345                                   "All new Request blocked"), packet);
346         session.setStatus(100);
347         return true;
348       }
349       if (Configuration.configuration.getConstraintLimitHandler()
350                                      .checkConstraints()) {
351         requestCheckConstraintsTrue(packet);
352         return true;
353       }
354     } else if (packet.getCode() == ErrorCode.ServerOverloaded.code) {
355       // XXX unvalid limit on requested host received
356       logger.info("TaskRunner initialisation in error: {}",
357                   ErrorCode.ServerOverloaded.getMesg());
358       localChannelReference.invalidateRequest(
359           new R66Result(null, session, true, ErrorCode.ServerOverloaded, null));
360       session.setStatus(101);
361       ChannelCloseTimer.closeFutureTransaction(this);
362       return true;
363     }
364     return false;
365   }
366 
367   private static void setRankAtStartupFromRequest(final RequestPacket packet,
368                                                   final DbTaskRunner runner) {
369     if (runner.isSender()) {
370       logger.debug("Rank was: {} -> {}", runner.getRank(), packet.getRank());
371       runner.setRankAtStartup(packet.getRank());
372     } else {
373       if (runner.getRank() > packet.getRank()) {
374         logger.debug("Recv Rank was: {} -> {}", runner.getRank(),
375                      packet.getRank());
376         // if receiver, change only if current rank is upper proposed rank
377         runner.setRankAtStartup(packet.getRank());
378       }
379       if (packet.getOriginalSize() > 0) {
380         runner.setOriginalSize(packet.getOriginalSize());
381       }
382     }
383   }
384 
385   private void setFileSizeFromRequest(final RequestPacket packet,
386                                       final DbTaskRunner runner,
387                                       boolean shouldInformBack)
388       throws OpenR66ProtocolPacketException {
389     logger.debug("Filesize: {}:{}", packet.getOriginalSize(),
390                  runner.isSender());
391     if (!shouldInformBack) {
392       shouldInformBack =
393           !packet.getTransferInformation().equals(runner.getFileInformation());
394     }
395     if (runner.isFileMoved() && runner.isSender() && runner.isInTransfer() &&
396         runner.getRank() == 0 && !packet.isToValidate()) {
397       // File was moved during PreTask and very beginning of the transfer
398       // and the remote host has already received the request packet
399       // => Informs the receiver of the new name
400       sendFilenameFilesizeChanging(packet, runner,
401                                    "Will send a modification of filename due to pretask: ",
402                                    "Change Filename by Pre action on sender");
403     } else if (!packet.getFilename().equals(runner.getOriginalFilename()) &&
404                runner.isSender() && runner.isInTransfer() &&
405                runner.getRank() == 0 && !packet.isToValidate()) {
406       // File was modify at the very beginning (using wildcards)
407       // and the remote host has already received the request packet
408       // => Informs the receiver of the new name
409       sendFilenameFilesizeChanging(packet, runner,
410                                    "Will send a modification of filename due to wildcard: ",
411                                    "Change Filename by Wildcard on sender");
412     } else if (runner.isSelfRequest() && runner.isSender() &&
413                runner.isInTransfer() && runner.getRank() == 0 &&
414                !packet.isToValidate()) {
415       // FIX SelfRequest
416       // File could be modified at the very beginning (using wildcards)
417       // and the remote host has already received the request packet
418       // => Informs the receiver of the new name
419       sendFilenameFilesizeChanging(packet, runner,
420                                    "Will send a modification of filename due to wildcard in SelfMode: ",
421                                    "Change Filename by Wildcard on sender in SelfMode");
422     } else if (shouldInformBack && !packet.isToValidate()) {
423       // Was only (shouldInformBack)
424       // File length is now known, so inform back
425       sendFilenameFilesizeChanging(packet, runner,
426                                    "Will send a modification of filesize or fileInfo: ",
427                                    "Change Filesize / FileInfo on sender");
428     }
429   }
430 
431   private void informBackFromRequest(final RequestPacket packet,
432                                      final DbTaskRunner runner)
433       throws OpenR66ProtocolPacketException {
434     if (packet.isToValidate()) {
435       if (Configuration.configuration.getMonitoring() != null) {
436         Configuration.configuration.getMonitoring().lastInActiveTransfer =
437             System.currentTimeMillis();
438       }
439       if (runner.isSender()) {
440         // In case Wildcard was used
441         logger.debug("New FILENAME: {}", runner.getOriginalFilename());
442         packet.setFilename(runner.getOriginalFilename());
443         logger.debug(RANK_SET, runner.getRank());
444         packet.setRank(runner.getRank());
445       } else {
446         logger.debug(RANK_SET, runner.getRank());
447         packet.setRank(runner.getRank());
448       }
449       packet.validate();
450       session.newState(REQUESTD);
451       ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
452                                             false);
453     } else {
454       session.newState(REQUESTD);
455       // requester => might be a client
456       // Save the runner into the session and validate the request so begin transfer
457       session.getLocalChannelReference().getFutureRequest().setRunner(runner);
458       localChannelReference.getFutureValidRequest().setSuccess();
459       if (Configuration.configuration.getMonitoring() != null) {
460         Configuration.configuration.getMonitoring().lastOutActiveTransfer =
461             System.currentTimeMillis();
462       }
463     }
464   }
465 
466   private void sendDataFromRequest(final DbTaskRunner runner) {
467     logger.debug("Try to send Data: isSender {} isSendThrough {}",
468                  runner.isSender(), runner.isSendThrough());
469     if (runner.isSender()) {
470       if (runner.isSendThrough()) {
471         // it is legal to send data from now
472         logger.debug("Now ready to continue with send through");
473         localChannelReference.validateEndTransfer(
474             new R66Result(session, false, ErrorCode.PreProcessingOk, runner));
475       } else {
476         // Automatically send data now
477         logger.debug("Now ready to continue with runRetrieve");
478         NetworkTransaction.runRetrieve(session);
479         try {
480           Thread.sleep(Configuration.RETRYINMS);
481         } catch (final InterruptedException ignore) { //NOSONAR
482           SysErrLogger.FAKE_LOGGER.ignoreLog(ignore);
483         }
484       }
485     }
486   }
487 
488   private void createErrorFromRequestInitKo(final RequestPacket packet,
489                                             final DbTaskRunner runner)
490       throws OpenR66RunnerErrorException, OpenR66ProtocolSystemException,
491              OpenR66ProtocolBusinessException {
492     // not valid so create an error from there
493     final ErrorCode code =
494         ErrorCode.getFromCode(String.valueOf(packet.getCode()));
495     session.setBadRunner(runner, code);
496     if (!runner.shallIgnoreSave()) {
497       runner.saveStatus();
498     }
499     session.newState(ERROR);
500     logger.error("Bad runner at startup {} {}", packet, session);
501     final ErrorPacket errorPacket =
502         new ErrorPacket(code.getMesg(), code.getCode(),
503                         ErrorPacket.FORWARDCLOSECODE);
504     errorMesg(errorPacket);
505   }
506 
507   private DbTaskRunner getPreviousDbTaskRunnerFromRequest(
508       final RequestPacket packet, final DbRule rule, final boolean isRetrieve)
509       throws OpenR66ProtocolPacketException {
510     final DbTaskRunner runner;// Reload or create
511     final String requested = DbTaskRunner.getRequested(session, packet);
512     final String requester = DbTaskRunner.getRequester(session, packet);
513     logger.debug("DEBUG: {}:{}", packet.getSpecialId(), isRetrieve);
514     if (packet.isToValidate()) {
515       // Id could be a creation or a reload
516       // Try reload
517       runner =
518           reloadDbTaskRunner(packet, rule, isRetrieve, requested, requester);
519       if (runner == null) {
520         return null;
521       }
522       final LocalChannelReference lcr =
523           Configuration.configuration.getLocalTransaction().getFromRequest(
524               requested + ' ' + requester + ' ' + packet.getSpecialId());
525       if (checkRunnerConsistency(packet, runner, lcr)) {
526         return null;
527       }
528 
529       if (runner.isAllDone()) {
530         // truly an error since done
531         session.setStatus(31);
532         endInitRequestInError(ErrorCode.QueryAlreadyFinished, runner,
533                               new OpenR66ProtocolBusinessQueryAlreadyFinishedException(
534                                   Messages.getString("LocalServerHandler.13")
535                                   //$NON-NLS-1$
536                                   + packet.getSpecialId()), packet);
537         return null;
538       }
539       if (lcr != null) {
540         // truly an error since still running
541         session.setStatus(32);
542         endInitRequestInError(ErrorCode.QueryStillRunning, runner,
543                               new OpenR66ProtocolBusinessQueryStillRunningException(
544                                   Messages.getString("LocalServerHandler.14")
545                                   //$NON-NLS-1$
546                                   + packet.getSpecialId()), packet);
547         return null;
548       }
549       logger.debug(RUNNER_BEFORE_ANY_ACTION, runner.shallIgnoreSave(), runner);
550       // ok to restart
551       runner.restart(false);
552       // Change the SpecialID! => could generate an error ?
553       if (packet.getSpecialId() == ILLEGALVALUE) {
554         packet.setSpecialId(runner.getSpecialId());
555       }
556     } else {
557       // Id should be a reload
558       runner = reloadDbTaskRunnerFromId(packet, rule, isRetrieve, requested,
559                                         requester);
560     }
561     return runner;
562   }
563 
564   private boolean checkRunnerConsistency(final RequestPacket packet,
565                                          final DbTaskRunner runner,
566                                          final LocalChannelReference lcr) {
567     // Check correctness of packet received vs current LCR
568     if (runner == null) {
569       logger.info("Id is unknown: {}}", packet.getSpecialId());
570       return true;
571     }
572     if (lcr != null && localChannelReference != null &&
573         !runner.isSelfRequest() &&
574         (!lcr.getLocalId().equals(localChannelReference.getLocalId()) ||
575          !lcr.getRemoteId().equals(localChannelReference.getRemoteId()))) {
576       logger.warn("LocalChannelReference differs: {}\n\t {}\n\tWill while " +
577                   "runner is AllDone: {}", localChannelReference, lcr,
578                   runner.isAllDone());
579       logger.info("Id is unknown: {}}", packet.getSpecialId());
580       if (runner.isAllDone()) {
581         try {
582           lcr.getServerHandler().tryFinalizeRequest(
583               new R66Result(lcr.getSession(), false, ErrorCode.Internal,
584                             runner));
585         } catch (final OpenR66RunnerErrorException ignore) {//NOSONAR
586           SysErrLogger.FAKE_LOGGER.ignoreLog(ignore);
587         } catch (final OpenR66ProtocolSystemException ignore) {//NOSONAR
588           SysErrLogger.FAKE_LOGGER.ignoreLog(ignore);
589         }
590         lcr.close();
591         if (localChannelReference.getClientRunner() != null &&
592             localChannelReference.getClientRunner().getTaskRunner() != null &&
593             localChannelReference.getClientRunner().getTaskRunner()
594                                  .isAllDone()) {
595           localChannelReference.close();
596         }
597         return true;
598       }
599       return false;
600     }
601     return false;
602   }
603 
604   private DbTaskRunner reloadDbTaskRunnerFromId(final RequestPacket packet,
605                                                 final DbRule rule,
606                                                 final boolean isRetrieve,
607                                                 final String requested,
608                                                 final String requester)
609       throws OpenR66ProtocolPacketException {
610     DbTaskRunner runner;
611     try {
612       runner = new DbTaskRunner(session, rule, packet.getSpecialId(), requester,
613                                 requested);
614     } catch (final WaarpDatabaseException e) {
615       if (localChannelReference.getDbSession() == null) {
616         // Special case of no database client
617         try {
618           runner = new DbTaskRunner(session, rule, isRetrieve, packet);
619           logger.debug(RUNNER_BEFORE_ANY_ACTION, runner.shallIgnoreSave(),
620                        runner);
621         } catch (final WaarpDatabaseException e1) {
622           session.setStatus(35);
623           endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
624                                 new OpenR66DatabaseGlobalException(e1), packet);
625           return null;
626         }
627       } else {
628         endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
629                               new OpenR66DatabaseGlobalException(e), packet);
630         session.setStatus(36);
631         return null;
632       }
633     }
634     final LocalChannelReference lcr =
635         Configuration.configuration.getLocalTransaction().getFromRequest(
636             requested + ' ' + requester + ' ' + packet.getSpecialId());
637     if (checkRunnerConsistency(packet, runner, lcr)) {
638       return null;
639     }
640     runner.setSender(isRetrieve);
641     // FIX check for SelfRequest
642     if (runner.isSelfRequest()) {
643       runner.setFilename(runner.getOriginalFilename());
644     }
645     if (!runner.isSender()) {
646       logger.debug("New filename ? :{}", packet.getFilename());
647       runner.setOriginalFilename(packet.getFilename());
648       if (runner.getRank() == 0) {
649         runner.setFilename(packet.getFilename());
650       }
651     }
652     logger.debug(RUNNER_BEFORE_ANY_ACTION, runner.shallIgnoreSave(), runner);
653     runner.restart(false);
654     return runner;
655   }
656 
657   private DbTaskRunner reloadDbTaskRunner(final RequestPacket packet,
658                                           final DbRule rule,
659                                           final boolean isRetrieve,
660                                           final String requested,
661                                           final String requester)
662       throws OpenR66ProtocolPacketException {
663     DbTaskRunner runner = null;
664     try {
665       runner = new DbTaskRunner(session, rule, packet.getSpecialId(), requester,
666                                 requested);
667       // Patch to prevent self request to be stored by sender
668       final boolean ignoreSave = runner.shallIgnoreSave();
669       runner.setSender(isRetrieve);
670       logger.debug("DEBUG: {}:{}:{}:{}", runner.getSpecialId(), ignoreSave,
671                    runner.shallIgnoreSave(), isRetrieve);
672       if (ignoreSave && !runner.shallIgnoreSave() &&
673           !runner.checkFromDbForSubmit()) {
674         // Since status changed, it means that object should be created and not reloaded
675         // But in case of submit, item already exist so shall be loaded from database
676         throw new WaarpDatabaseNoDataException(
677             "False load, must reopen and create DbTaskRunner");
678       }
679     } catch (final WaarpDatabaseNoDataException e) {
680       // Reception of request from requester host
681       try {
682         runner = new DbTaskRunner(session, rule, isRetrieve, packet);
683         logger.debug(RUNNER_BEFORE_ANY_ACTION, runner.shallIgnoreSave(),
684                      runner);
685       } catch (final WaarpDatabaseException e1) {
686         session.setStatus(33);
687         endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
688                               new OpenR66DatabaseGlobalException(e), packet);
689         return null;
690       }
691     } catch (final WaarpDatabaseException e) {
692       session.setStatus(34);
693       endInitRequestInError(ErrorCode.QueryRemotelyUnknown, null,
694                             new OpenR66DatabaseGlobalException(e), packet);
695       return null;
696     }
697     return runner;
698   }
699 
700   private void requestCheckConstraintsTrue(final RequestPacket packet)
701       throws OpenR66ProtocolPacketException {
702     if (Configuration.configuration.getR66Mib() != null) {
703       Configuration.configuration.getR66Mib().notifyOverloaded(
704           "Rule: " + packet.getRulename() + " from " + session.getAuth(),
705           Configuration.configuration.getConstraintLimitHandler().lastAlert);
706     }
707     logger.warn(Messages.getString("LocalServerHandler.8") //$NON-NLS-1$
708                 + packet.getRulename() + " while " +
709                 Configuration.configuration.getConstraintLimitHandler().lastAlert +
710                 " from " + session.getAuth());
711     session.setStatus(100);
712     endInitRequestInError(ErrorCode.ServerOverloaded, null,
713                           new OpenR66ProtocolNotYetConnectionException(
714                               "Limit exceeded " +
715                               Configuration.configuration.getConstraintLimitHandler().lastAlert),
716                           packet);
717     session.setStatus(100);
718   }
719 
720   /**
721    * Send a Filename/Filesize change to the partner
722    *
723    * @param packet
724    * @param runner
725    *
726    * @throws OpenR66ProtocolPacketException
727    */
728   private void sendFilenameFilesizeChanging(final RequestPacket packet,
729                                             final DbTaskRunner runner,
730                                             final String debug,
731                                             final String info)
732       throws OpenR66ProtocolPacketException {
733     logger.debug("{}{}", debug, runner.getFilename());
734     session.newState(VALID);
735     if (localChannelReference.getPartner().useJson()) {
736       final RequestJsonPacket request = new RequestJsonPacket();
737       request.setComment(info);
738       request.setFilename(runner.getFilename());
739       request.setFilesize(packet.getOriginalSize());
740       final String infoTransfer = runner.getFileInformation();
741       if (infoTransfer != null &&
742           !infoTransfer.equals(packet.getTransferInformation())) {
743         request.setFileInfo(runner.getFileInformation());
744       }
745       final JsonCommandPacket validPacket =
746           new JsonCommandPacket(request, LocalPacketFactory.REQUESTPACKET);
747       ChannelUtils.writeAbstractLocalPacket(localChannelReference, validPacket,
748                                             false);
749     } else {
750       final String infoTransfer = runner.getFileInformation();
751       final ValidPacket validPacket;
752       if (infoTransfer != null &&
753           !infoTransfer.equals(packet.getTransferInformation()) &&
754           localChannelReference.getPartner().changeFileInfoEnabled()) {
755         validPacket = new ValidPacket(info, runner.getFilename() +
756                                             PartnerConfiguration.BAR_SEPARATOR_FIELD +
757                                             packet.getOriginalSize() +
758                                             PartnerConfiguration.BAR_SEPARATOR_FIELD +
759                                             packet.getTransferInformation(),
760                                       LocalPacketFactory.REQUESTPACKET);
761       } else {
762         validPacket = new ValidPacket(info, runner.getFilename() +
763                                             PartnerConfiguration.BAR_SEPARATOR_FIELD +
764                                             packet.getOriginalSize(),
765                                       LocalPacketFactory.REQUESTPACKET);
766       }
767       ChannelUtils.writeAbstractLocalPacket(localChannelReference, validPacket,
768                                             false);
769     }
770   }
771 
772   /**
773    * Send an error
774    *
775    * @param message
776    * @param code
777    *
778    * @throws OpenR66ProtocolPacketException
779    */
780   private void errorToSend(final String message, final ErrorCode code,
781                            final int status)
782       throws OpenR66ProtocolPacketException {
783     session.newState(ERROR);
784     try {
785       session.setFinalizeTransfer(false, new R66Result(
786           new OpenR66ProtocolPacketException(message), session, true, code,
787           session.getRunner()));
788     } catch (final OpenR66RunnerErrorException e1) {
789       localChannelReference.invalidateRequest(
790           new R66Result(e1, session, true, code, session.getRunner()));
791     } catch (final OpenR66ProtocolSystemException e1) {
792       localChannelReference.invalidateRequest(
793           new R66Result(e1, session, true, code, session.getRunner()));
794     }
795     final ErrorPacket error =
796         new ErrorPacket(message, code.getCode(), ErrorPacket.FORWARDCLOSECODE);
797     ChannelUtils.writeAbstractLocalPacket(localChannelReference, error, false);
798     session.setStatus(status);
799     ChannelCloseTimer.closeFutureTransaction(this);
800   }
801 
802   /**
803    * Receive a data block
804    *
805    * @param packet
806    *
807    * @throws OpenR66ProtocolNotAuthenticatedException
808    * @throws OpenR66ProtocolBusinessException
809    * @throws OpenR66ProtocolPacketException
810    */
811   public final void data(final DataPacket packet)
812       throws OpenR66ProtocolNotAuthenticatedException,
813              OpenR66ProtocolBusinessException, OpenR66ProtocolPacketException {
814     if (!session.isAuthenticated()) {
815       logger.info("Not authenticated while Data received");
816       packet.clear();
817       throw new OpenR66ProtocolNotAuthenticatedException(
818           "Not authenticated while Data received");
819     }
820     if (!session.isReady()) {
821       logger.info("No request prepared");
822       packet.clear();
823       throw new OpenR66ProtocolBusinessException("No request prepared");
824     }
825     if (session.getRunner().isSender()) {
826       logger.error("Not in receive MODE but receive a packet");
827       packet.clear();
828       throw new OpenR66ProtocolBusinessException(
829           "Not in receive MODE but receive a packet");
830     }
831     if (!session.getRunner().continueTransfer()) {
832       logger.debug("EndTransfer failed ? {}",
833                    localChannelReference.getFutureEndTransfer().isFailed());
834       if (localChannelReference.getFutureEndTransfer().isFailed()) {
835         // nothing to do since already done
836         session.setStatus(94);
837         packet.clear();
838         return;
839       }
840       errorToSend("Transfer in error due previously aborted transmission",
841                   ErrorCode.TransferError, 95);
842       packet.clear();
843       return;
844     }
845     if (packet.getPacketRank() != session.getRunner().getRank()) {
846       logger.info("Issue on rank: {}:{}", packet.getPacketRank(),
847                   session.getRunner().getRank());
848       if (!session.addError()) {
849         // cannot continue
850         logger.error(Messages.getString("LocalServerHandler.15") +
851                      packet.getPacketRank() + " : " + //$NON-NLS-1$
852                      session.getRunner().getRank() + " from {}",
853                      session.getRunner());
854         errorToSend(
855             "Too much Bad Rank in transmission: " + packet.getPacketRank(),
856             ErrorCode.TransferError, 96);
857         packet.clear();
858         return;
859       }
860       // Fix the rank if possible
861       if (packet.getPacketRank() < session.getRunner().getRank()) {
862         logger.info("Bad RANK: {} : {}", packet.getPacketRank(),
863                     session.getRunner().getRank());
864         session.getRunner().setRankAtStartup(packet.getPacketRank());
865         session.getRestart().restartMarker(
866             (long) session.getRunner().getBlocksize() *
867             session.getRunner().getRank());
868         try {
869           session.getFile().restartMarker(session.getRestart());
870         } catch (final CommandAbstractException e) {
871           logger.error("Bad RANK: " + packet.getPacketRank() + " : " +
872                        session.getRunner().getRank());
873           errorToSend("Bad Rank in transmission even after retry: " +
874                       packet.getPacketRank(), ErrorCode.TransferError, 96);
875           packet.clear();
876           return;
877         }
878       } else {
879         // really bad
880         logger.error("Bad RANK: " + packet.getPacketRank() + " : " +
881                      session.getRunner().getRank());
882         errorToSend(
883             "Bad Rank in transmission: " + packet.getPacketRank() + " > " +
884             session.getRunner().getRank(), ErrorCode.TransferError, 20);
885         packet.clear();
886         return;
887       }
888     }
889     // Check global size
890     final long originalSize = session.getRunner().getOriginalSize();
891     if (originalSize > 0) {
892       if ((long) session.getRunner().getBlocksize() *
893           (session.getRunner().getRank() - 1) > originalSize) {
894         // cannot continue
895         logger.error(Messages.getString("LocalServerHandler.16") +
896                      packet.getPacketRank() + " : " + //$NON-NLS-1$
897                      (originalSize / session.getRunner().getBlocksize() + 1) +
898                      " from {}", session.getRunner());
899         errorToSend("Too much data transferred: " + packet.getPacketRank(),
900                     ErrorCode.TransferError, 96);
901         packet.clear();
902         return;
903       }
904     }
905     // if MD5 check MD5
906     if (RequestPacket.isMD5Mode(session.getRunner().getMode())) {
907       logger.debug("AlgoDigest: {}",
908                    (localChannelReference.getPartner() != null?
909                        localChannelReference.getPartner().getDigestAlgo() :
910                        "usual algo"));
911       if (Configuration.configuration.isGlobalDigest()) {
912         // Cumulate all three digests
913         if (!packet.isKeyValid(session.getDigestBlock(), globalDigest,
914                                localDigest)) {
915           // Wrong packet
916           logger.error(Messages.getString("LocalServerHandler.17"), packet,
917                        //$NON-NLS-1$
918                        localChannelReference.getPartner()
919                                             .getDigestAlgo().algoName);
920           errorToSend("Transfer in error due to bad Hash on data packet " +
921                       "during multiple Digests (" +
922                       localChannelReference.getPartner()
923                                            .getDigestAlgo().algoName + ')',
924                       ErrorCode.MD5Error, 21);
925           packet.clear();
926           return;
927         }
928         // Only Packet digest and maybe localDigest
929       } else if (!packet.isKeyValid(session.getDigestBlock(), null,
930                                     localDigest)) {
931         // Wrong packet
932         logger.error(Messages.getString("LocalServerHandler.17"), packet,
933                      //$NON-NLS-1$
934                      localChannelReference.getPartner()
935                                           .getDigestAlgo().algoName);
936         errorToSend("Transfer in error due to bad Hash on data packet (" +
937                     localChannelReference.getPartner()
938                                          .getDigestAlgo().algoName + ')',
939                     ErrorCode.MD5Error, 21);
940         packet.clear();
941         return;
942       }
943     } else if (Configuration.configuration.isGlobalDigest()) {
944       // Only Global digests
945       FileUtils.computeGlobalHash(globalDigest, localDigest, packet.getData(),
946                                   packet.getLengthPacket());
947     }
948     if ((session.getRunner().isRecvThrough() ||
949          ClientRunner.isRecvHandlerJunit()) &&
950         localChannelReference.isRecvThroughMode()) {
951       try {
952         localChannelReference.getRecvThroughHandler()
953                              .writeBytes(packet.getData(),
954                                          packet.getLengthPacket());
955         session.getRunner().incrementRank();
956         if (packet.getPacketRank() % 100 == 1) {
957           logger.debug("Good RANK: {} : {}", packet.getPacketRank(),
958                        session.getRunner().getRank());
959         }
960       } finally {
961         packet.clear();
962       }
963     } else {
964       final DataBlock dataBlock = new DataBlock();
965       dataBlock.setBlock(packet.getData());
966       dataBlock.setByteCount(packet.getLengthPacket());
967       try {
968         session.getFile().writeDataBlock(dataBlock);
969         session.getRunner().incrementRank();
970         if (packet.getPacketRank() % 100 == 1) {
971           logger.debug("Good RANK: {} : {}", packet.getPacketRank(),
972                        session.getRunner().getRank());
973         }
974       } catch (final FileTransferException e) {
975         errorToSend("Transfer in error", ErrorCode.TransferError, 22);
976       } finally {
977         dataBlock.clear();
978         packet.clear();
979       }
980     }
981   }
982 
983   private void prepareGlobalDigests() {
984     if (Configuration.configuration.isGlobalDigest()) {
985       if (globalDigest == null) {
986         try {
987           // check if first block, since if not, digest will be only partial
988           if (session.getRunner().getRank() > 0) {
989             localChannelReference.setPartialHash();
990           }
991           if (localChannelReference.getPartner() != null &&
992               localChannelReference.getPartner().useFinalHash()) {
993             final DigestAlgo algo =
994                 localChannelReference.getPartner().getDigestAlgo();
995             if (algo != Configuration.configuration.getDigest()) {
996               globalDigest = new FilesystemBasedDigest(algo);
997               if (Configuration.configuration.isLocalDigest() &&
998                   !localChannelReference.isPartialHash()) {
999                 localDigest = new FilesystemBasedDigest(
1000                     Configuration.configuration.getDigest());
1001               }
1002             }
1003           }
1004           if (globalDigest == null &&
1005               Configuration.configuration.isLocalDigest() &&
1006               !localChannelReference.isPartialHash()) {
1007             globalDigest = new FilesystemBasedDigest(
1008                 Configuration.configuration.getDigest());
1009             localDigest = null;
1010           }
1011         } catch (final NoSuchAlgorithmException ignored) {
1012           // nothing
1013         }
1014         logger.debug("GlobalDigest: {} different? {}",
1015                      localChannelReference.getPartner().getDigestAlgo(),
1016                      localDigest != null);
1017       }
1018     } else if (Configuration.configuration.isLocalDigest()) {
1019       // check if first block, since if not, digest will be only partial
1020       if (session.getRunner().getRank() > 0) {
1021         localChannelReference.setPartialHash();
1022       } else {
1023         try {
1024           localDigest = new FilesystemBasedDigest(
1025               Configuration.configuration.getDigest());
1026         } catch (final NoSuchAlgorithmException ignored) {
1027           // nothing
1028         }
1029       }
1030       logger.debug("LocalDigest: {}", Configuration.configuration.getDigest());
1031     }
1032   }
1033 
1034   /**
1035    * Receive an End of Transfer
1036    *
1037    * @param packet
1038    *
1039    * @throws OpenR66ProtocolNotAuthenticatedException
1040    */
1041   public final void endTransfer(final EndTransferPacket packet)
1042       throws OpenR66ProtocolNotAuthenticatedException {
1043     if (!session.isAuthenticated()) {
1044       throw new OpenR66ProtocolNotAuthenticatedException(
1045           "Not authenticated while EndTransfer received");
1046     }
1047     // Check end of transfer
1048     final long originalSize = session.getRunner().getOriginalSize();
1049     logger.debug("OSize: {} isSender: {}", originalSize,
1050                  session.getRunner().isSender());
1051     try {
1052       session.getFile().closeFile();
1053     } catch (final CommandAbstractException e) {
1054       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
1055     }
1056     if (packet.isToValidate()) {
1057       // check if possible originalSize
1058       if (originalSize > 0 && checkOriginalSize(originalSize)) {
1059         return;
1060       }
1061       // check if possible Global Digest
1062       if (checkGlobalDigest(packet)) {
1063         return;
1064       }
1065       session.newState(ENDTRANSFERS);
1066       fromEndTransferSToTransferR(packet);
1067     } else {
1068       session.newState(ENDTRANSFERR);
1069       // Validation of end of transfer
1070       if (!localChannelReference.getFutureRequest().isDone() &&
1071           endTransferR()) {
1072         // nothing
1073       }
1074     }
1075   }
1076 
1077   private void fromEndTransferSToTransferR(final EndTransferPacket packet) {
1078     if (!localChannelReference.getFutureRequest().isDone()) {
1079       session.newState(ENDTRANSFERR);
1080       if (endTransferR()) {
1081         return;
1082       }
1083       // Now can send validation
1084       packet.validate();
1085       try {
1086         ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
1087                                               false);
1088       } catch (final OpenR66ProtocolPacketException e) {
1089         // ignore
1090       }
1091     } else {
1092       // in error due to a previous status (like bad MD5)
1093       logger.error(Messages.getString("LocalServerHandler.20")); //$NON-NLS-1$
1094       session.setStatus(23);
1095       localChannelReference.close();
1096     }
1097   }
1098 
1099   private boolean checkGlobalDigest(final EndTransferPacket packet) {
1100     final String hash = packet.getOptional();
1101     logger.debug("GlobalDigest: {} different? {} remoteHash? {}",
1102                  localChannelReference.getPartner().getDigestAlgo(),
1103                  localDigest != null, hash != null);
1104     if (hash != null && globalDigest != null) {
1105       String localhash = FilesystemBasedDigest.getHex(globalDigest.Final());
1106       globalDigest = null;
1107       if (!localhash.equalsIgnoreCase(hash)) {
1108         // bad global Hash
1109         logger.warn("Partner GlobalHash error: {}",
1110                     localChannelReference.getPartner());
1111         final R66Result result = new R66Result(new OpenR66RunnerErrorException(
1112             Messages.getString("LocalServerHandler.19") + //$NON-NLS-1$
1113             localChannelReference.getPartner().getDigestAlgo().algoName + ')'),
1114                                                session, true,
1115                                                ErrorCode.MD5Error,
1116                                                session.getRunner());
1117         try {
1118           session.setFinalizeTransfer(false, result);
1119         } catch (final OpenR66RunnerErrorException ignored) {
1120           // nothing
1121         } catch (final OpenR66ProtocolSystemException ignored) {
1122           // nothing
1123         }
1124         final ErrorPacket error = new ErrorPacket(
1125             "Global Hash in error, transfer in error and rank should be reset to 0 (using " +
1126             localChannelReference.getPartner().getDigestAlgo().algoName + ')',
1127             ErrorCode.MD5Error.getCode(), ErrorPacket.FORWARDCLOSECODE);
1128         try {
1129           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1130                                                 false);
1131         } catch (final OpenR66ProtocolPacketException ignored) {
1132           // nothing
1133         }
1134         session.setStatus(23);
1135         ChannelCloseTimer.closeFutureTransaction(this);
1136         localDigest = null;
1137         globalDigest = null;
1138         return true;
1139       } else if (Configuration.configuration.isLocalDigest()) {
1140         if (localDigest != null) {
1141           localhash = FilesystemBasedDigest.getHex(localDigest.Final());
1142         }
1143         localChannelReference.setHashComputeDuringTransfer(localhash);
1144         logger.debug("Global digest ok");
1145       }
1146     } else if (Configuration.configuration.isLocalDigest() &&
1147                (globalDigest != null || localDigest != null)) {
1148       final String localhash;
1149       if (localDigest != null) {
1150         localhash = FilesystemBasedDigest.getHex(localDigest.Final());
1151       } else {
1152         localhash = FilesystemBasedDigest.getHex(globalDigest.Final());
1153       }
1154       globalDigest = null;
1155       localChannelReference.setHashComputeDuringTransfer(localhash);
1156     }
1157     localDigest = null;
1158     globalDigest = null;
1159     return false;
1160   }
1161 
1162   private boolean checkOriginalSize(final long originalSize) {
1163     try {
1164       if (!session.getRunner().isRecvThrough() &&
1165           session.getFile().length() != originalSize ||
1166           session.getFile().length() == 0) {
1167         final String sizesDiffer =
1168             ": size differs from " + originalSize + " to " +
1169             session.getFile().length() + " at rank " +
1170             session.getRunner().getRank();
1171         final R66Result result = new R66Result(new OpenR66RunnerErrorException(
1172             Messages.getString("LocalServerHandler.18") + sizesDiffer),//$NON
1173                                                // -NLS-1$
1174                                                session, true,
1175                                                ErrorCode.TransferError,
1176                                                session.getRunner());
1177         try {
1178           session.setFinalizeTransfer(false, result);
1179         } catch (final OpenR66RunnerErrorException ignored) {
1180           // nothing
1181         } catch (final OpenR66ProtocolSystemException ignored) {
1182           // nothing
1183         }
1184         final ErrorPacket error = new ErrorPacket(
1185             "Final size in error, transfer in error and rank should be reset to 0" +
1186             sizesDiffer, ErrorCode.TransferError.getCode(),
1187             ErrorPacket.FORWARDCLOSECODE);
1188         try {
1189           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1190                                                 false);
1191         } catch (final OpenR66ProtocolPacketException ignored) {
1192           // nothing
1193         }
1194         session.setStatus(23);
1195         ChannelCloseTimer.closeFutureTransaction(this);
1196         return true;
1197       }
1198     } catch (final CommandAbstractException e) {
1199       // ignore
1200     }
1201     return false;
1202   }
1203 
1204   private void errorEndTransferR() {
1205     session.newState(ERROR);
1206     final ErrorPacket error;
1207     if (localChannelReference.getFutureRequest().getResult() != null) {
1208       final R66Result result =
1209           localChannelReference.getFutureRequest().getResult();
1210       error = new ErrorPacket(
1211           "Error while finalizing transfer: " + result.getMessage(),
1212           result.getCode().getCode(), ErrorPacket.FORWARDCLOSECODE);
1213     } else {
1214       error = new ErrorPacket("Error while finalizing transfer",
1215                               ErrorCode.FinalOp.getCode(),
1216                               ErrorPacket.FORWARDCLOSECODE);
1217     }
1218     try {
1219       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1220                                             false);
1221     } catch (final OpenR66ProtocolPacketException ignored) {
1222       // nothing
1223     }
1224     session.setStatus(23);
1225     ChannelCloseTimer.closeFutureTransaction(this);
1226   }
1227 
1228   private boolean endTransferR() {
1229     // Finish with post Operation
1230     final R66Result result = new R66Result(session, false, ErrorCode.TransferOk,
1231                                            session.getRunner());
1232     try {
1233       session.setFinalizeTransfer(true, result);
1234     } catch (final OpenR66RunnerErrorException e) {
1235       errorEndTransferR();
1236       return true;
1237     } catch (final OpenR66ProtocolSystemException e) {
1238       errorEndTransferR();
1239       return true;
1240     }
1241     return false;
1242   }
1243 
1244   /**
1245    * Receive an End of Request
1246    *
1247    * @param packet
1248    *
1249    * @throws OpenR66RunnerErrorException
1250    * @throws OpenR66ProtocolSystemException
1251    * @throws OpenR66ProtocolNotAuthenticatedException
1252    */
1253   public final void endRequest(final EndRequestPacket packet) {
1254     // Validate the last post action on a transfer from receiver remote host
1255     logger.info("Valid Request {} Packet {}", localChannelReference, packet);
1256     final DbTaskRunner runner = session.getRunner();
1257     logger.debug("Runner endRequest: {}", session.getRunner() != null);
1258     if (runner != null) {
1259       runner.setAllDone();
1260       try {
1261         runner.saveStatus();
1262       } catch (final OpenR66RunnerErrorException e) {
1263         // ignore
1264       }
1265       runner.clean();
1266     }
1267     String optional = null;
1268     if (session.getExtendedProtocol()) {
1269       optional = packet.getOptional();
1270     }
1271     if (!localChannelReference.getFutureRequest().isDone()) {
1272       // end of request
1273       final R66Future transfer = localChannelReference.getFutureEndTransfer();
1274       transfer.awaitOrInterruptible();
1275       if (transfer.isSuccess()) {
1276         if (session.getExtendedProtocol() &&
1277             session.getBusinessObject() != null) {
1278           if (session.getBusinessObject().getInfo(session) == null) {
1279             session.getBusinessObject().setInfo(session, optional);
1280           } else {
1281             final String temp = session.getBusinessObject().getInfo(session);
1282             session.getBusinessObject().setInfo(session, optional);
1283             optional = temp;
1284           }
1285         } else if (session.getExtendedProtocol() &&
1286                    transfer.getResult().getOther() == null &&
1287                    optional != null) {
1288           transfer.getResult().setOther(optional);
1289         }
1290         localChannelReference.validateRequest(transfer.getResult());
1291       }
1292     }
1293     session.setStatus(1);
1294     if (packet.isToValidate()) {
1295       session.newState(ENDREQUESTS);
1296       packet.validate();
1297       if (session.getExtendedProtocol()) {
1298         packet.setOptional(optional);
1299       }
1300       session.newState(ENDREQUESTR);
1301       try {
1302         ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
1303                                               false);
1304       } catch (final OpenR66ProtocolPacketException ignored) {
1305         // nothing
1306       }
1307     } else {
1308       if (session.getState() != CLOSEDCHANNEL) {
1309         session.newState(ENDREQUESTR);
1310       }
1311     }
1312     if (runner != null &&
1313         (runner.isRequestOnRequested() || runner.isSelfRequest())) {
1314       ChannelCloseTimer.closeFutureTransaction(this);
1315     }
1316   }
1317 
1318   /**
1319    * Update if necessary after Filename or size changed
1320    *
1321    * @throws OpenR66RunnerErrorException
1322    */
1323   public final void saveAfterChangingFileInfo()
1324       throws OpenR66RunnerErrorException {
1325     final DbTaskRunner runner = session.getRunner();
1326     try {
1327       runner.update();
1328     } catch (final WaarpDatabaseException e) {
1329       runner.saveStatus();
1330       runner.setErrorExecutionStatus(ErrorCode.ExternalOp);
1331       session.newState(ERROR);
1332       logger.error("File info changing in error {}", e.getMessage());
1333       final ErrorPacket error = new ErrorPacket(
1334           "File changing information in error: " + e.getMessage(),
1335           runner.getErrorInfo().getCode(), ErrorPacket.FORWARDCLOSECODE);
1336       try {
1337         ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1338                                               false);
1339       } catch (final OpenR66ProtocolPacketException ignored) {
1340         // nothing
1341       }
1342       try {
1343         session.setFinalizeTransfer(false, new R66Result(
1344             new OpenR66RunnerErrorException(e), session, true,
1345             runner.getErrorInfo(), runner));
1346       } catch (final OpenR66RunnerErrorException e1) {
1347         localChannelReference.invalidateRequest(
1348             new R66Result(new OpenR66RunnerErrorException(e), session, true,
1349                           runner.getErrorInfo(), runner));
1350       } catch (final OpenR66ProtocolSystemException e1) {
1351         localChannelReference.invalidateRequest(
1352             new R66Result(new OpenR66RunnerErrorException(e), session, true,
1353                           runner.getErrorInfo(), runner));
1354       }
1355       session.setStatus(97);
1356       ChannelCloseTimer.closeFutureTransaction(this);
1357     }
1358   }
1359 
1360   /**
1361    * If newFileInfo is provided and different than current value
1362    *
1363    * @param newFileInfo
1364    *
1365    * @throws OpenR66RunnerErrorException
1366    */
1367   public final void requestChangeFileInfo(final String newFileInfo)
1368       throws OpenR66RunnerErrorException {
1369     final DbTaskRunner runner = session.getRunner();
1370     logger.debug("NewFileInfo {}", newFileInfo);
1371     runner.setFileInformation(newFileInfo);
1372   }
1373 
1374   /**
1375    * Change the filename and the filesize
1376    *
1377    * @param newfilename
1378    * @param newSize
1379    *
1380    * @throws OpenR66RunnerErrorException
1381    */
1382   public final void requestChangeNameSize(final String newfilename,
1383                                           final long newSize)
1384       throws OpenR66RunnerErrorException {
1385     session.newState(VALID);
1386     final DbTaskRunner runner = session.getRunner();
1387     logger.debug("NewSize {} NewName {}", newSize, newfilename);
1388     // The filename or filesize from sender is changed due to PreTask so change it too in receiver
1389     // comment, filename, filesize
1390     // Close only if an error occurs!
1391     if (runner != null && newSize > 0) {
1392       runner.setOriginalSize(newSize);
1393       // Check if a CHKFILE task was supposedly needed to run
1394       if (checkIfAnyTaskCheckFile(newfilename, newSize, runner)) {
1395         return;
1396       }
1397     }
1398     // check if send is already on going
1399     if (runner != null && runner.getRank() > 0) {
1400       // already started so not changing the filename
1401       // Success: No write back at all
1402       return;
1403     }
1404     // Pre execution was already done since this packet is only received once
1405     // the request is already validated by the receiver
1406     try {
1407       session.renameReceiverFile(newfilename);
1408     } catch (final OpenR66RunnerErrorException e) {
1409       if (runner != null) {
1410         runner.saveStatus();
1411         runner.setErrorExecutionStatus(ErrorCode.FileNotFound);
1412         session.newState(ERROR);
1413         logger.error("File renaming in error {}", e.getMessage(), e);
1414         final ErrorPacket error =
1415             new ErrorPacket("File renaming in error: " + e.getMessage(),
1416                             runner.getErrorInfo().getCode(),
1417                             ErrorPacket.FORWARDCLOSECODE);
1418         try {
1419           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1420                                                 false);
1421         } catch (final OpenR66ProtocolPacketException ignored) {
1422           // nothing
1423         }
1424         try {
1425           session.setFinalizeTransfer(false, new R66Result(e, session, true,
1426                                                            runner.getErrorInfo(),
1427                                                            runner));
1428         } catch (final OpenR66RunnerErrorException e1) {
1429           localChannelReference.invalidateRequest(
1430               new R66Result(e, session, true, runner.getErrorInfo(), runner));
1431         } catch (final OpenR66ProtocolSystemException e1) {
1432           localChannelReference.invalidateRequest(
1433               new R66Result(e, session, true, runner.getErrorInfo(), runner));
1434         }
1435       }
1436       session.setStatus(97);
1437       ChannelCloseTimer.closeFutureTransaction(this);
1438     }
1439     // Success: No write back at all
1440   }
1441 
1442   private boolean checkIfAnyTaskCheckFile(final String newfilename,
1443                                           final long newSize,
1444                                           final DbTaskRunner runner)
1445       throws OpenR66RunnerErrorException {
1446     final String[][] rpretasks = runner.getRule().getRpreTasksArray();
1447     if (rpretasks != null) {
1448       for (final String[] strings : rpretasks) {
1449         final AbstractTask task = runner.getTask(strings, session);
1450         if (task.getType() == TaskType.CHKFILE) {
1451           // re run this in case
1452           task.run();
1453           task.getFutureCompletion().awaitOrInterruptible();
1454           if (!task.getFutureCompletion().isSuccess()) {
1455             // not valid so create an error from there
1456             final ErrorCode code = ErrorCode.SizeNotAllowed;
1457             runner.setErrorExecutionStatus(code);
1458             runner.saveStatus();
1459             session.setBadRunner(runner, code);
1460             session.newState(ERROR);
1461             logger.error(
1462                 "File length is not compatible with Rule or capacity {} {}",
1463                 newfilename + " : " + newSize, session);
1464             final ErrorPacket errorPacket = new ErrorPacket(
1465                 "File length is not compatible with Rule or capacity",
1466                 code.getCode(), ErrorPacket.FORWARDCLOSECODE);
1467             try {
1468               ChannelUtils.writeAbstractLocalPacket(localChannelReference,
1469                                                     errorPacket, true);
1470             } catch (final OpenR66ProtocolPacketException ignored) {
1471               // nothing
1472             }
1473             try {
1474               session.setFinalizeTransfer(false, new R66Result(
1475                   new OpenR66RunnerErrorException(errorPacket.getSheader()),
1476                   session, true, runner.getErrorInfo(), runner));
1477             } catch (final OpenR66RunnerErrorException e1) {
1478               localChannelReference.invalidateRequest(new R66Result(
1479                   new OpenR66RunnerErrorException(errorPacket.getSheader()),
1480                   session, true, runner.getErrorInfo(), runner));
1481             } catch (final OpenR66ProtocolSystemException e1) {
1482               localChannelReference.invalidateRequest(new R66Result(
1483                   new OpenR66RunnerErrorException(errorPacket.getSheader()),
1484                   session, true, runner.getErrorInfo(), runner));
1485             }
1486             session.setStatus(97);
1487             ChannelCloseTimer.closeFutureTransaction(this);
1488             return true;
1489           }
1490         }
1491       }
1492     }
1493     return false;
1494   }
1495 }