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.networkhandler;
21  
22  import io.netty.bootstrap.Bootstrap;
23  import io.netty.channel.Channel;
24  import io.netty.channel.ChannelFuture;
25  import io.netty.channel.ChannelId;
26  import io.netty.channel.ChannelPipelineException;
27  import io.netty.channel.group.ChannelGroup;
28  import io.netty.channel.group.DefaultChannelGroup;
29  import io.netty.util.Timeout;
30  import io.netty.util.TimerTask;
31  import org.waarp.common.crypto.ssl.WaarpSslUtility;
32  import org.waarp.common.database.DbAdmin;
33  import org.waarp.common.digest.FilesystemBasedDigest;
34  import org.waarp.common.future.WaarpLock;
35  import org.waarp.common.logging.SysErrLogger;
36  import org.waarp.common.logging.WaarpLogger;
37  import org.waarp.common.logging.WaarpLoggerFactory;
38  import org.waarp.common.lru.ConcurrentUtility;
39  import org.waarp.common.lru.SynchronizedLruCache;
40  import org.waarp.common.utility.WaarpNettyUtil;
41  import org.waarp.common.utility.WaarpShutdownHook;
42  import org.waarp.common.utility.WaarpSystemUtil;
43  import org.waarp.openr66.context.ErrorCode;
44  import org.waarp.openr66.context.R66Result;
45  import org.waarp.openr66.context.R66Session;
46  import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
47  import org.waarp.openr66.database.data.DbHostAuth;
48  import org.waarp.openr66.protocol.configuration.Configuration;
49  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBlackListedException;
50  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNetworkException;
51  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoConnectionException;
52  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoDataException;
53  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoSslException;
54  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotAuthenticatedException;
55  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
56  import org.waarp.openr66.protocol.exception.OpenR66ProtocolRemoteShutdownException;
57  import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException;
58  import org.waarp.openr66.protocol.localhandler.LocalChannelReference;
59  import org.waarp.openr66.protocol.localhandler.RetrieveRunner;
60  import org.waarp.openr66.protocol.localhandler.packet.AuthentPacket;
61  import org.waarp.openr66.protocol.localhandler.packet.ConnectionErrorPacket;
62  import org.waarp.openr66.protocol.networkhandler.packet.NetworkPacket;
63  import org.waarp.openr66.protocol.networkhandler.ssl.NetworkSslServerHandler;
64  import org.waarp.openr66.protocol.networkhandler.ssl.NetworkSslServerInitializer;
65  import org.waarp.openr66.protocol.utils.ChannelUtils;
66  import org.waarp.openr66.protocol.utils.R66Future;
67  
68  import java.net.ConnectException;
69  import java.net.InetAddress;
70  import java.net.InetSocketAddress;
71  import java.net.SocketAddress;
72  import java.util.Enumeration;
73  import java.util.Set;
74  import java.util.concurrent.ConcurrentHashMap;
75  import java.util.concurrent.TimeUnit;
76  import java.util.concurrent.locks.ReentrantLock;
77  
78  import static org.waarp.common.utility.WaarpShutdownHook.*;
79  import static org.waarp.openr66.context.R66FiniteDualStates.*;
80  import static org.waarp.openr66.protocol.configuration.Configuration.*;
81  
82  /**
83   * This class handles Network Transaction connections
84   */
85  public class NetworkTransaction {
86    /**
87     * Internal Logger
88     */
89    private static final WaarpLogger logger =
90        WaarpLoggerFactory.getLogger(NetworkTransaction.class);
91  
92    /**
93     * To protect access to socketLocks when no address associated
94     */
95    private static final WaarpLock emptyLock = new WaarpLock();
96    /**
97     * Lock for Lock management operations
98     */
99    private static final ReentrantLock lockOfLock = new ReentrantLock();
100   /**
101    * Hashmap for lock based on remote address
102    */
103   private static final SynchronizedLruCache<Integer, WaarpLock>
104       reentrantLockOnSocketAddressConcurrentHashMap =
105       new SynchronizedLruCache<Integer, WaarpLock>(20000, 180000);
106   /**
107    * Hashmap for Currently Shutdown remote host based on
108    * socketAddress.hashCode()
109    */
110   private static final ConcurrentHashMap<Integer, NetworkChannelReference>
111       networkChannelShutdownOnSocketAddressConcurrentHashMap =
112       new ConcurrentHashMap<Integer, NetworkChannelReference>();
113   /**
114    * Hashmap for Currently blacklisted remote host based on IP
115    * address(String).hashCode()
116    */
117   private static final ConcurrentHashMap<Integer, NetworkChannelReference>
118       networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap =
119       new ConcurrentHashMap<Integer, NetworkChannelReference>();
120 
121   /**
122    * Hashmap for currently active remote host based on
123    * socketAddress.hashCode()
124    */
125   private static final ConcurrentHashMap<Integer, NetworkChannelReference>
126       networkChannelOnSocketAddressConcurrentHashMap =
127       new ConcurrentHashMap<Integer, NetworkChannelReference>();
128   /**
129    * Remote Client NetworkChannels: used to centralize remote requester hosts
130    * (possible different address used)
131    */
132   private static final ConcurrentHashMap<String, ClientNetworkChannels>
133       clientNetworkChannelsPerHostId =
134       new ConcurrentHashMap<String, ClientNetworkChannels>();
135   /**
136    * Hashmap for currently active Retrieve Runner (sender)
137    */
138   private static final ConcurrentHashMap<Integer, RetrieveRunner>
139       retrieveRunnerConcurrentHashMap =
140       new ConcurrentHashMap<Integer, RetrieveRunner>();
141 
142   private final Bootstrap clientBootstrap;
143   private final Bootstrap clientSslBootstrap;
144   private ChannelGroup networkChannelGroup;
145 
146   public NetworkTransaction() {
147     clearPreviousStates();
148     networkChannelGroup = new DefaultChannelGroup("NetworkChannels",
149                                                   Configuration.configuration.getSubTaskGroup()
150                                                                              .next());
151     Configuration.configuration.setupLimitHandler();
152     clientBootstrap = new Bootstrap();
153     if (Configuration.configuration.isUseNOSSL() &&
154         Configuration.configuration.getHostId() != null) {
155       final NetworkServerInitializer networkServerInitializer =
156           new NetworkServerInitializer(false);
157       WaarpNettyUtil.setBootstrap(clientBootstrap,
158                                   Configuration.configuration.getNetworkWorkerGroup(),
159                                   (int) Configuration.configuration.getTimeoutCon(),
160                                   configuration.getBlockSize() + 64, false);
161       clientBootstrap.handler(networkServerInitializer);
162     }
163     clientSslBootstrap = new Bootstrap();
164     if (Configuration.configuration.isUseSSL() &&
165         Configuration.configuration.getHostSslId() != null) {
166       final NetworkSslServerInitializer networkSslServerInitializer =
167           new NetworkSslServerInitializer(true);
168       WaarpNettyUtil.setBootstrap(clientSslBootstrap,
169                                   Configuration.configuration.getNetworkWorkerGroup(),
170                                   (int) Configuration.configuration.getTimeoutCon(),
171                                   configuration.getBlockSize() + 64, false);
172       clientSslBootstrap.handler(networkSslServerInitializer);
173     } else {
174       if (Configuration.configuration.isWarnOnStartup()) {
175         logger.warn("No SSL support configured");
176       } else {
177         logger.info("No SSL support configured");
178       }
179     }
180   }
181 
182   private final void clearPreviousStates() {
183     if (WaarpSystemUtil.isJunit()) {
184       for (final NetworkChannelReference ncr : networkChannelOnSocketAddressConcurrentHashMap.values()) {
185         if (ncr.channel != null &&
186             ncr.channel.hasAttr(NetworkServerHandler.REUSABLE_AUTH_KEY)) {
187           logger.debug("DEBUG clear {}",
188                        ncr.channel.attr(NetworkServerHandler.REUSABLE_AUTH_KEY)
189                                   .get());
190           ncr.channel.attr(NetworkServerHandler.REUSABLE_AUTH_KEY).set(null);
191         }
192       }
193       for (final ClientNetworkChannels cnc : clientNetworkChannelsPerHostId.values()) {
194         for (final NetworkChannelReference ncr : cnc.getNetworkChannelReferences()) {
195           if (ncr.channel != null &&
196               ncr.channel.hasAttr(NetworkServerHandler.REUSABLE_AUTH_KEY)) {
197             logger.debug("DEBUG clear {}", ncr.channel.attr(
198                 NetworkServerHandler.REUSABLE_AUTH_KEY).get());
199             ncr.channel.attr(NetworkServerHandler.REUSABLE_AUTH_KEY).set(null);
200           }
201         }
202       }
203     }
204   }
205 
206   public static String hashStatus() {
207     final StringBuilder partial =
208         new StringBuilder("NetworkTransaction: [InShutdown: ");
209     partial.append(
210                networkChannelShutdownOnSocketAddressConcurrentHashMap.size())
211            .append(" Blacklisted: ").append(
212                networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.size())
213            .append("\n RetrieveRunner: ")
214            .append(retrieveRunnerConcurrentHashMap.size())
215            .append(" ClientNetworkChannels: ")
216            .append(clientNetworkChannelsPerHostId.size());
217     int nb = 0;
218     for (final ClientNetworkChannels clientNetworkChannels : clientNetworkChannelsPerHostId.values()) {
219       nb += clientNetworkChannels.size();
220     }
221     partial.append(" Sum of ClientNetworkChannels NetworkClients: ").append(nb);
222     nb = 0;
223     for (final NetworkChannelReference ncr : networkChannelOnSocketAddressConcurrentHashMap.values()) {
224       nb += ncr.nbLocalChannels();
225       partial.append("\n NetworkChannels: ").append(ncr.toString());
226     }
227     partial.append("\n NetworkChannels: ")
228            .append(networkChannelOnSocketAddressConcurrentHashMap.size())
229            .append(" LockOnSocketAddress: ")
230            .append(reentrantLockOnSocketAddressConcurrentHashMap.size())
231            .append(" Sum of NetworkChannels LocalClients: ").append(nb)
232            .append("] ");
233     return partial.toString();
234   }
235 
236   private static WaarpLock getLockNCR(final SocketAddress sa) {
237     final int key = sa.hashCode();
238     final WaarpLock value =
239         reentrantLockOnSocketAddressConcurrentHashMap.get(key);
240     if (value != null) {
241       reentrantLockOnSocketAddressConcurrentHashMap.updateTtl(key);
242     }
243     return value;
244   }
245 
246   private static void addLockNCR(final SocketAddress sa, final WaarpLock lock) {
247     reentrantLockOnSocketAddressConcurrentHashMap.put(sa.hashCode(), lock);
248   }
249 
250   private static void addNCR(final NetworkChannelReference ncr) {
251     networkChannelOnSocketAddressConcurrentHashMap.put(ncr.getSocketHashCode(),
252                                                        ncr);
253   }
254 
255   private static NetworkChannelReference removeNCR(
256       final NetworkChannelReference ncr) {
257     return networkChannelOnSocketAddressConcurrentHashMap.remove(
258         ncr.getSocketHashCode());
259   }
260 
261   private static NetworkChannelReference getNCR(final SocketAddress sa) {
262     return networkChannelOnSocketAddressConcurrentHashMap.get(sa.hashCode());
263   }
264 
265   private static boolean containsNCR(final SocketAddress address) {
266     return networkChannelOnSocketAddressConcurrentHashMap.containsKey(
267         address.hashCode());
268   }
269 
270   private static void addShutdownNCR(final NetworkChannelReference ncr) {
271     networkChannelShutdownOnSocketAddressConcurrentHashMap.put(
272         ncr.getSocketHashCode(), ncr);
273   }
274 
275   private static NetworkChannelReference removeShutdownNCR(
276       final NetworkChannelReference ncr) {
277     return networkChannelShutdownOnSocketAddressConcurrentHashMap.remove(
278         ncr.getSocketHashCode());
279   }
280 
281   private static boolean containsShutdownNCR(
282       final NetworkChannelReference ncr) {
283     return networkChannelShutdownOnSocketAddressConcurrentHashMap.containsKey(
284         ncr.getSocketHashCode());
285   }
286 
287   private static boolean containsShutdownNCR(final SocketAddress sa) {
288     return networkChannelShutdownOnSocketAddressConcurrentHashMap.containsKey(
289         sa.hashCode());
290   }
291 
292   private static NetworkChannelReference getShutdownNCR(
293       final SocketAddress sa) {
294     return networkChannelShutdownOnSocketAddressConcurrentHashMap.get(
295         sa.hashCode());
296   }
297 
298   private static void addBlacklistNCR(final NetworkChannelReference ncr) {
299     networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.put(
300         ncr.getAddressHashCode(), ncr);
301   }
302 
303   private static NetworkChannelReference removeBlacklistNCR(
304       final NetworkChannelReference ncr) {
305     return networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.remove(
306         ncr.getAddressHashCode());
307   }
308 
309   private static boolean containsBlacklistNCR(
310       final NetworkChannelReference ncr) {
311     return networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.containsKey(
312         ncr.getAddressHashCode());
313   }
314 
315   private static boolean containsBlacklistNCR(final SocketAddress address) {
316     return networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.containsKey(
317         address.hashCode());
318   }
319 
320   private static NetworkChannelReference getBlacklistNCR(
321       final SocketAddress sa) {
322     final InetAddress address = ((InetSocketAddress) sa).getAddress();
323     if (address == null) {
324       return null;
325     }
326 
327     return networkChannelBlacklistedOnInetSocketAddressConcurrentHashMap.get(
328         address.getHostAddress().hashCode());
329   }
330 
331   private static WaarpLock getChannelLock(final SocketAddress socketAddress) {
332     lockOfLock.lock();
333     try {
334       if (socketAddress == null) {
335         // should not
336         logger.info("SocketAddress empty here !");
337         return emptyLock;
338       }
339       WaarpLock socketLock = getLockNCR(socketAddress);
340       if (socketLock == null) {
341         socketLock = new WaarpLock(true);
342       }
343       // update TTL
344       addLockNCR(socketAddress, socketLock);
345       return socketLock;
346     } finally {
347       lockOfLock.unlock();
348     }
349   }
350 
351   private static void removeChannelLock() {
352     lockOfLock.lock();
353     try {
354       reentrantLockOnSocketAddressConcurrentHashMap.forceClearOldest();
355     } finally {
356       lockOfLock.unlock();
357     }
358   }
359 
360   /**
361    * Create a connection to the specified socketAddress with multiple retries
362    *
363    * @param socketAddress
364    * @param isSSL
365    * @param futureRequest
366    *
367    * @return the LocalChannelReference
368    */
369   public final LocalChannelReference createConnectionWithRetry(
370       final SocketAddress socketAddress, final boolean isSSL,
371       final R66Future futureRequest) {
372     try {
373       return createConnectionWithRetryWithAuthenticationException(socketAddress,
374                                                                   isSSL,
375                                                                   futureRequest);
376     } catch (final OpenR66ProtocolNotAuthenticatedException e) {
377       // Correct return!
378       return null;
379     }
380   }
381 
382   /**
383    * Create a connection to the specified socketAddress with multiple retries
384    *
385    * @param socketAddress
386    * @param isSSL
387    * @param futureRequest
388    *
389    * @return the LocalChannelReference
390    *
391    * @throws OpenR66ProtocolNotAuthenticatedException
392    */
393   public final LocalChannelReference createConnectionWithRetryWithAuthenticationException(
394       final SocketAddress socketAddress, final boolean isSSL,
395       final R66Future futureRequest)
396       throws OpenR66ProtocolNotAuthenticatedException {
397     LocalChannelReference localChannelReference = null;
398     for (int i = 0; i < Configuration.RETRYNB; i++) {
399       if (WaarpShutdownHook.isShutdownStarting()) {
400         logger.error("Cannot connect : Local system in shutdown");
401         break;
402       }
403       try {
404         localChannelReference =
405             createConnection(socketAddress, isSSL, futureRequest);
406         break;
407       } catch (final OpenR66ProtocolRemoteShutdownException e) {
408         logger.warn("Cannot connect : {}", e.getMessage());
409         logger.debug(e);
410         break;
411       } catch (final OpenR66ProtocolBlackListedException e) {
412         logger.error("Cannot connect : {}", e.getMessage());
413         logger.debug(e);
414         break;
415       } catch (final OpenR66ProtocolNoConnectionException e) {
416         logger.error("Cannot connect : {}", e.getMessage());
417         logger.debug(e);
418         break;
419       } catch (final OpenR66ProtocolNotAuthenticatedException e) {
420         logger.error("Cannot be authenticated : {}", e.getMessage());
421         logger.debug(e);
422         throw e;
423       } catch (final OpenR66ProtocolNetworkException e) {
424         // Can retry
425         logger.error("Cannot connect : {}. Will retry", e.getMessage());
426         logger.warn(e);
427         try {
428           Thread.sleep(Configuration.configuration.getDelayRetry());
429         } catch (final InterruptedException e1) {//NOSONAR
430           SysErrLogger.FAKE_LOGGER.ignoreLog(e1);
431         }
432       }
433     }
434     if (localChannelReference != null) {
435       logger.info("Connected");
436     }
437     return localChannelReference;
438   }
439 
440   /**
441    * Create a connection to the specified socketAddress
442    *
443    * @param socketAddress
444    * @param isSSL
445    * @param futureRequest
446    *
447    * @return the LocalChannelReference
448    *
449    * @throws OpenR66ProtocolNetworkException
450    * @throws OpenR66ProtocolRemoteShutdownException
451    * @throws OpenR66ProtocolBlackListedException
452    * @throws OpenR66ProtocolNoConnectionException
453    * @throws OpenR66ProtocolNotAuthenticatedException
454    */
455   private LocalChannelReference createConnection(
456       final SocketAddress socketAddress, final boolean isSSL,
457       final R66Future futureRequest) throws OpenR66ProtocolNetworkException,
458                                             OpenR66ProtocolRemoteShutdownException,
459                                             OpenR66ProtocolNoConnectionException,
460                                             OpenR66ProtocolNotAuthenticatedException,
461                                             OpenR66ProtocolBlackListedException {
462     NetworkChannelReference networkChannelReference = null;
463     LocalChannelReference localChannelReference;
464     boolean ok = false;
465     // check valid limit on server side only (could be the initiator but not a client)
466     final DbHostAuth auth =
467         isSSL? Configuration.configuration.getHostSslAuth() :
468             Configuration.configuration.getHostAuth();
469     if (!auth.isClient()) {
470       boolean valid = false;
471       for (int i = 0; i < Configuration.RETRYNB * 2; i++) {
472         if (Configuration.configuration.getConstraintLimitHandler()
473                                        .checkConstraintsSleep(i)) {
474           logger.info("Constraints exceeded: {}", i);
475         } else {
476           logger.debug("Constraints NOT exceeded");
477           valid = true;
478           break;
479         }
480       }
481       if (!valid) {
482         // Limit is locally exceeded
483         throw new OpenR66ProtocolNetworkException(
484             "Cannot connect to remote server due to local overload");
485       }
486     }
487     try {
488       // Ensure networkChannelReference and localChannelReference are linked
489       networkChannelReference = createNewConnection(socketAddress, isSSL);
490       try {
491         localChannelReference =
492             Configuration.configuration.getLocalTransaction()
493                                        .createNewClient(networkChannelReference,
494                                                         ChannelUtils.NOCHANNEL,
495                                                         futureRequest, isSSL);
496       } catch (final NullPointerException e) {
497         throw new OpenR66ProtocolNetworkException(e);
498       }
499       ok = true;
500     } finally {
501       if (!ok && networkChannelReference != null) {
502         checkClosingNetworkChannel(networkChannelReference, null);
503       }
504     }
505     if (localChannelReference.getFutureValidateStartup().isSuccess()) {
506       sendValidationConnection(localChannelReference);
507     } else {
508       final OpenR66ProtocolNetworkException exc =
509           new OpenR66ProtocolNetworkException("Startup is invalid");
510       logger.info("Startup is Invalid", exc);
511       final R66Result finalValue =
512           new R66Result(exc, null, true, ErrorCode.ConnectionImpossible, null);
513       localChannelReference.invalidateRequest(finalValue);
514       localChannelReference.close();
515       throw exc;
516     }
517     return localChannelReference;
518   }
519 
520   /**
521    * @param socketServerAddress
522    * @param isSSL
523    *
524    * @return the NetworkChannelReference
525    *
526    * @throws OpenR66ProtocolNetworkException
527    * @throws OpenR66ProtocolRemoteShutdownException
528    * @throws OpenR66ProtocolBlackListedException
529    * @throws OpenR66ProtocolNoConnectionException
530    */
531   private NetworkChannelReference createNewConnection(
532       final SocketAddress socketServerAddress, final boolean isSSL)
533       throws OpenR66ProtocolNetworkException,
534              OpenR66ProtocolRemoteShutdownException,
535              OpenR66ProtocolBlackListedException,
536              OpenR66ProtocolNoConnectionException {
537     final WaarpLock socketLock = getChannelLock(socketServerAddress);
538     NetworkChannelReference networkChannelReference;
539     socketLock.lock();
540     try {
541       try {
542         networkChannelReference = getRemoteChannel(socketServerAddress);
543       } catch (final OpenR66ProtocolNoDataException e1) {
544         networkChannelReference = null;
545       }
546       if (networkChannelReference != null) {
547         networkChannelReference.use();
548         logger.info("Already Connected: {}", networkChannelReference);
549         return networkChannelReference;
550       }
551       logger.debug("NEW PHYSICAL CONNECTION REQUIRED");
552       ChannelFuture channelFuture = null;
553       for (int i = 0; i < Configuration.RETRYNB; i++) {
554         if (WaarpShutdownHook.isShutdownStarting()) {
555           throw new OpenR66ProtocolNoConnectionException(
556               "Local system in shutdown");
557         }
558         try {
559           if (isSSL) {
560             if (Configuration.configuration.getHostSslId() != null) {
561               channelFuture = clientSslBootstrap.connect(socketServerAddress);
562             } else {
563               throw new OpenR66ProtocolNoConnectionException("No SSL support");
564             }
565           } else {
566             channelFuture = clientBootstrap.connect(socketServerAddress);
567           }
568         } catch (final ChannelPipelineException e) {
569           throw new OpenR66ProtocolNoConnectionException(
570               "Cannot connect to remote server due to a channel exception");
571         }
572         WaarpNettyUtil.awaitOrInterrupted(channelFuture,
573                                           Configuration.configuration.getTimeoutCon());
574         if (channelFuture.isSuccess()) {
575           final Channel channel = channelFuture.channel();
576           if (isSSL &&
577               !NetworkSslServerHandler.isSslConnectedChannel(channel)) {
578             logger.info("KO CONNECT since SSL handshake is over");
579             channel.close();
580             throw new OpenR66ProtocolNoConnectionException(
581                 "Cannot finish connect to remote server");
582           }
583           if (networkChannelGroup != null) {
584             networkChannelGroup.add(channel);
585           }
586           networkChannelReference =
587               new NetworkChannelReference(channel, socketLock, isSSL);
588           addNCR(networkChannelReference);
589           logger.info("New Real Connection: {}", networkChannelReference);
590           return networkChannelReference;
591         } else {
592           try {
593             Thread.sleep(Configuration.RETRYINMS);
594           } catch (final InterruptedException e) {//NOSONAR
595             SysErrLogger.FAKE_LOGGER.ignoreLog(e);
596           }
597           if (!channelFuture.isDone()) {
598             throw new OpenR66ProtocolNoConnectionException(
599                 "Cannot connect to remote server since received an " +
600                 "interruption");
601           }
602           if (channelFuture.cause() instanceof ConnectException) {
603             logger.debug("KO CONNECT: {}", channelFuture.cause().getMessage());
604             throw new OpenR66ProtocolNoConnectionException(
605                 channelFuture.cause().getMessage(), channelFuture.cause());
606           } else {
607             logger.debug("KO CONNECT but retry", channelFuture.cause());
608           }
609         }
610       }
611       if (channelFuture != null) {
612         throw new OpenR66ProtocolNetworkException(
613             "Cannot connect to remote server", channelFuture.cause());
614       } else {
615         throw new OpenR66ProtocolNetworkException(
616             "Cannot connect to remote server");
617       }
618     } finally {
619       socketLock.unlock();
620     }
621   }
622 
623   /**
624    * Create the LocalChannelReference when a remote local channel starts its
625    * connection
626    *
627    * @param networkChannelReference
628    * @param startupPacket
629    *
630    * @return TransferReference
631    */
632   public static LocalChannelReference createConnectionFromNetworkChannelStartup(
633       final NetworkChannelReference networkChannelReference,
634       final NetworkPacket startupPacket, final boolean fromSsl) {
635     logger.debug("Startup {}", startupPacket);
636     final Channel channel = networkChannelReference.channel();
637     try {
638       return Configuration.configuration.getLocalTransaction().createNewClient(
639           networkChannelReference, startupPacket.getRemoteId(), null, fromSsl);
640     } catch (final OpenR66ProtocolRemoteShutdownException e1) {
641       logger.info("Will Close Local from Network Channel");
642       WaarpSslUtility.closingSslChannel(channel);
643       startupPacket.clear();
644     } catch (final OpenR66ProtocolNoConnectionException e1) {
645       logger.error(
646           "Cannot create LocalChannel for: " + startupPacket + " due to " +
647           e1.getMessage());
648       final ConnectionErrorPacket error = new ConnectionErrorPacket(
649           "Cannot connect to localChannel since cannot create it", null);
650       NetworkServerHandler.writeError(channel, startupPacket.getRemoteId(),
651                                       startupPacket.getLocalId(), error);
652       checkClosingNetworkChannel(networkChannelReference, null);
653       startupPacket.clear();
654     }
655     return null;
656   }
657 
658   /**
659    * Send a validation of connection with Authentication
660    *
661    * @param localChannelReference
662    *
663    * @throws OpenR66ProtocolNetworkException
664    * @throws OpenR66ProtocolNotAuthenticatedException
665    */
666   private void sendValidationConnection(
667       final LocalChannelReference localChannelReference)
668       throws OpenR66ProtocolNetworkException,
669              OpenR66ProtocolNotAuthenticatedException {
670     if (localChannelReference.getServerHandler()
671                              .validateAuthenticationReuse()) {
672       // Already authenticated
673       return;
674     }
675     final AuthentPacket authent;
676 
677     try {
678       final DbHostAuth auth =
679           localChannelReference.getNetworkServerHandler().isSsl()?
680               Configuration.configuration.getHostSslAuth() :
681               Configuration.configuration.getHostAuth();
682       authent = new AuthentPacket(Configuration.configuration.getHostId(
683           localChannelReference.getNetworkServerHandler().isSsl()),
684                                   FilesystemBasedDigest.passwdCrypt(
685                                       auth.getHostkey()),
686                                   localChannelReference.getLocalId());
687     } catch (final OpenR66ProtocolNoSslException e1) {
688       final R66Result finalValue = new R66Result(
689           new OpenR66ProtocolSystemException("No SSL support", e1),
690           localChannelReference.getSession(), true,
691           ErrorCode.ConnectionImpossible, null);
692       logger.error("Authent is Invalid due to no SSL: {}", e1.getMessage());
693       if (localChannelReference.getRemoteId()
694                                .compareTo(ChannelUtils.NOCHANNEL) == 0) {
695         final ConnectionErrorPacket error = new ConnectionErrorPacket(
696             "Cannot connect to localChannel since SSL is not supported", null);
697         try {
698           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
699                                                 false);
700         } catch (final OpenR66ProtocolPacketException ignored) {
701           // nothing
702         }
703       }
704       localChannelReference.invalidateRequest(finalValue);
705       localChannelReference.close();
706       throw new OpenR66ProtocolNetworkException(e1);
707     }
708     logger.debug("Will send request of connection validation");
709     localChannelReference.sessionNewState(AUTHENTR);
710     try {
711       ChannelUtils.writeAbstractLocalPacket(localChannelReference, authent,
712                                             false);
713     } catch (final OpenR66ProtocolPacketException e) {
714       final R66Result finalValue = new R66Result(
715           new OpenR66ProtocolSystemException("Wrong Authent Protocol", e),
716           localChannelReference.getSession(), true,
717           ErrorCode.ConnectionImpossible, null);
718       logger.error("Authent is Invalid due to protocol: {}", e.getMessage());
719       localChannelReference.invalidateRequest(finalValue);
720       if (!localChannelReference.getRemoteId().equals(ChannelUtils.NOCHANNEL)) {
721         final ConnectionErrorPacket error = new ConnectionErrorPacket(
722             "Cannot connect to localChannel since Authent Protocol is invalid",
723             null);
724         try {
725           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
726                                                 false);
727         } catch (final OpenR66ProtocolPacketException ignored) {
728           // nothing
729         }
730       }
731       localChannelReference.close();
732       throw new OpenR66ProtocolNetworkException("Bad packet", e);
733     }
734     final R66Future future =
735         localChannelReference.getFutureValidateConnection();
736     if (future.isFailed()) {
737       logger.debug("Will close NETWORK channel since Future cancelled: {}",
738                    future);
739       final R66Result finalValue = new R66Result(
740           new OpenR66ProtocolSystemException(
741               "Connection invalid during Authentication"),
742           localChannelReference.getSession(), true,
743           ErrorCode.ConnectionImpossible, null);
744       logger.info("Authent is Invalid due to: {} {}",
745                   finalValue.getException().getMessage(), future.toString());
746       localChannelReference.invalidateRequest(finalValue);
747       if (!localChannelReference.getRemoteId().equals(ChannelUtils.NOCHANNEL)) {
748         final ConnectionErrorPacket error = new ConnectionErrorPacket(
749             "Cannot connect to localChannel with Out of Time", null);
750         try {
751           ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
752                                                 false);
753         } catch (final OpenR66ProtocolPacketException ignored) {
754           // nothing
755         }
756       }
757       localChannelReference.close();
758       throw new OpenR66ProtocolNotAuthenticatedException(
759           "Cannot validate connection: " + future.getResult(),
760           future.getCause());
761     }
762   }
763 
764   /**
765    * Add a new NetworkChannel from connection
766    *
767    * @param channel
768    * @param isSsl
769    *
770    * @throws OpenR66ProtocolRemoteShutdownException
771    * @throws OpenR66ProtocolBlackListedException
772    */
773   public static NetworkChannelReference addNetworkChannel(final Channel channel,
774                                                           final boolean isSsl)
775       throws OpenR66ProtocolRemoteShutdownException,
776              OpenR66ProtocolBlackListedException {
777     final SocketAddress socketAddress = channel.remoteAddress();
778     final WaarpLock socketLock = getChannelLock(socketAddress);
779     socketLock.lock();
780     try {
781       NetworkChannelReference nc = null;
782       try {
783         nc = getRemoteChannel(socketAddress);
784       } catch (final OpenR66ProtocolNoDataException ignored) {
785         // nothing
786       }
787       if (nc == null) {
788         // not an issue: needs to be created
789         nc = new NetworkChannelReference(channel, socketLock, isSsl);
790         addNCR(nc);
791       }
792       return nc;
793     } finally {
794       socketLock.unlock();
795     }
796   }
797 
798   /**
799    * To be called when a remote server seems to be down for a while, so to not
800    * retry immediately
801    *
802    * @param socketAddress
803    */
804   public static void proposeShutdownNetworkChannel(
805       final SocketAddress socketAddress, final boolean isSSL) {
806     final WaarpLock lock = getChannelLock(socketAddress);
807     lock.lock(Configuration.WAITFORNETOP, TimeUnit.MILLISECONDS);
808     try {
809       logger.info("Seem Shutdown: {}", socketAddress);
810       if (containsShutdownNCR(socketAddress)) {
811         // already done
812         logger.debug("Already set as shutdown");
813         return;
814       }
815       if (containsBlacklistNCR(socketAddress)) {
816         // already done
817         logger.debug("Already set as blocked");
818         return;
819       }
820       if (containsNCR(socketAddress)) {
821         // already done
822         logger.debug("Still existing so shutdown is refused");
823         return;
824       }
825       logger.warn(
826           "This host address will be set as unavailable for 3xTIMEOUT since not reacheable multiple times: {}",
827           socketAddress);
828       final NetworkChannelReference networkChannelReference =
829           new NetworkChannelReference(socketAddress, lock, isSSL);
830       addShutdownNCR(networkChannelReference);
831       if (Configuration.configuration.isTimerCloseReady()) {
832         final R66ShutdownNetworkChannelTimerTask timerTask;
833         try {
834           timerTask =
835               new R66ShutdownNetworkChannelTimerTask(networkChannelReference,
836                                                      false);
837           Configuration.configuration.getTimerClose().newTimeout(timerTask,
838                                                                  Configuration.configuration.getTimeoutCon(),
839                                                                  TimeUnit.MILLISECONDS);
840         } catch (final OpenR66RunnerErrorException e) {
841           // ignore
842         }
843       }
844     } finally {
845       lock.unlock();
846     }
847   }
848 
849   /**
850    * Shutdown one Network Channel
851    *
852    * @param networkChannelReference
853    */
854   private static void shuttingDownNetworkChannelInternal(
855       final NetworkChannelReference networkChannelReference) {
856     logger.info("Shutdown: {}", networkChannelReference);
857     if (networkChannelReference != null &&
858         containsShutdownNCR(networkChannelReference)) {
859       // already done
860       logger.debug("Already set as shutdown");
861       return;
862     }
863     logger.debug("Set as shutdown");
864     if (networkChannelReference != null) {
865       addShutdownNCR(networkChannelReference);
866       if (!networkChannelReference.isShuttingDown) {
867         networkChannelReference.shutdownAllLocalChannels();
868       }
869       if (Configuration.configuration.isTimerCloseReady()) {
870         final R66ShutdownNetworkChannelTimerTask timerTask;
871         try {
872           timerTask =
873               new R66ShutdownNetworkChannelTimerTask(networkChannelReference,
874                                                      false);
875           Configuration.configuration.getTimerClose().newTimeout(timerTask,
876                                                                  Configuration.configuration.getTimeoutCon(),
877                                                                  TimeUnit.MILLISECONDS);
878         } catch (final OpenR66RunnerErrorException e) {
879           // ignore
880         }
881       }
882     }
883   }
884 
885   /**
886    * Shutdown one Network Channel
887    *
888    * @param networkChannelReference
889    */
890   public static void shuttingDownNetworkChannel(
891       final NetworkChannelReference networkChannelReference) {
892     shuttingDownNetworkChannelInternal(networkChannelReference);
893   }
894 
895   /**
896    * Shutdown a NetworkChannel and add it to BlaclList
897    *
898    * @param networkChannelReference
899    *
900    * @return True if this channel is now blacklisted for a while
901    */
902   public static boolean shuttingDownNetworkChannelBlackList(
903       final NetworkChannelReference networkChannelReference) {
904     shuttingDownNetworkChannelInternal(networkChannelReference);
905     if (!Configuration.configuration.isBlacklistBadAuthent()) {
906       return false;
907     }
908     if (containsBlacklistNCR(networkChannelReference)) {
909       return false;
910     }
911     addBlacklistNCR(networkChannelReference);
912     if (Configuration.configuration.isTimerCloseReady()) {
913       final R66ShutdownNetworkChannelTimerTask timerTask;
914       try {
915         timerTask =
916             new R66ShutdownNetworkChannelTimerTask(networkChannelReference,
917                                                    true);
918         Configuration.configuration.getTimerClose().newTimeout(timerTask,
919                                                                Configuration.configuration.getTimeoutCon() *
920                                                                5,
921                                                                TimeUnit.MILLISECONDS);
922       } catch (final OpenR66RunnerErrorException e) {
923         // ignore
924       }
925     }
926     return true;
927   }
928 
929   /**
930    * @param channel
931    *
932    * @return True if this channel is blacklisted
933    */
934   public static boolean isBlacklisted(final Channel channel) {
935     if (!Configuration.configuration.isBlacklistBadAuthent()) {
936       return false;
937     }
938     final SocketAddress address = channel.remoteAddress();
939     if (address == null) {
940       return false;
941     }
942 
943     final NetworkChannelReference networkChannelReference =
944         getBlacklistNCR(address);
945     return networkChannelReference != null;
946   }
947 
948   /**
949    * @param address
950    *
951    * @return True if this address (associated channel) is currently in
952    *     shutdown (or if this channel is not valid)
953    */
954   public static boolean isShuttingdownNetworkChannel(
955       final SocketAddress address) {
956     return !isAddressValid(address);
957   }
958 
959   /**
960    * Shutdown NetworkChannelReference as client
961    *
962    * @param requester
963    *
964    * @return True if shutdown occurs
965    */
966   public static boolean shuttingdownNetworkChannelsPerHostID(
967       final String requester) {
968     if (requester == null) {
969       return false;
970     }
971     final ClientNetworkChannels clientNetworkChannels =
972         clientNetworkChannelsPerHostId.get(requester);
973     logger.debug("AddClient: shutdown previous exist? " +
974                  (clientNetworkChannels != null) + " for :" + requester);
975     if (clientNetworkChannels != null) {
976       return clientNetworkChannels.shutdownAllNetworkChannels();
977     }
978     return false;
979   }
980 
981   /**
982    * Add a requester channel
983    *
984    * @param networkChannelReference
985    * @param requester
986    */
987   public static void addClient(
988       final NetworkChannelReference networkChannelReference,
989       final String requester) {
990     synchronized (clientNetworkChannelsPerHostId) {
991       if (networkChannelReference != null && requester != null) {
992         ClientNetworkChannels clientNetworkChannels =
993             clientNetworkChannelsPerHostId.get(requester);
994         if (clientNetworkChannels == null) {
995           clientNetworkChannels = new ClientNetworkChannels(requester);
996           clientNetworkChannelsPerHostId.put(requester, clientNetworkChannels);
997         }
998         clientNetworkChannels.add(networkChannelReference);
999         logger.debug("AddClient: add count? {} for {}",
1000                      clientNetworkChannels.size(), requester);
1001       }
1002     }
1003   }
1004 
1005   private static void removeClient(
1006       final NetworkChannelReference networkChannelReference,
1007       final String requester,
1008       final ClientNetworkChannels clientNetworkChannels) {
1009     if (networkChannelReference != null && clientNetworkChannels != null &&
1010         requester != null) {
1011       clientNetworkChannels.remove(networkChannelReference);
1012       logger.debug("removeClient: remove for :{} still {}", requester,
1013                    clientNetworkChannels.size());
1014       if (clientNetworkChannels.isEmpty()) {
1015         clientNetworkChannelsPerHostId.remove(requester);
1016       }
1017     }
1018   }
1019 
1020   /**
1021    * @param requester
1022    *
1023    * @return The number of NetworkChannels associated with this requester
1024    */
1025   public static int getNumberClients(final String requester) {
1026     final ClientNetworkChannels clientNetworkChannels =
1027         clientNetworkChannelsPerHostId.get(requester);
1028     if (clientNetworkChannels != null) {
1029       return clientNetworkChannels.size();
1030     }
1031     return 0;
1032   }
1033 
1034   /**
1035    * Force remove of NetworkChannelReference when it is closed
1036    *
1037    * @param networkChannelReference
1038    */
1039   public static void closedNetworkChannel(
1040       final NetworkChannelReference networkChannelReference) {
1041     if (networkChannelReference == null) {
1042       return;
1043     }
1044     try {
1045       if (!networkChannelReference.isShuttingDown) {
1046         networkChannelReference.shutdownAllLocalChannels();
1047       }
1048       logger.debug("NC left: {}", networkChannelReference);
1049       removeNCR(networkChannelReference);
1050       if (networkChannelReference.clientNetworkChannels != null) {
1051         final String requester =
1052             networkChannelReference.clientNetworkChannels.getHostId();
1053         removeClient(networkChannelReference, requester,
1054                      networkChannelReference.clientNetworkChannels);
1055       } else if (networkChannelReference.getHostId() != null) {
1056         final String requester = networkChannelReference.getHostId();
1057         final ClientNetworkChannels clientNetworkChannels =
1058             clientNetworkChannelsPerHostId.get(requester);
1059         if (clientNetworkChannels != null) {
1060           removeClient(networkChannelReference, requester,
1061                        clientNetworkChannels);
1062         }
1063       }
1064     } finally {
1065       removeChannelLock();
1066     }
1067   }
1068 
1069   /**
1070    * Force remove of NetworkChannelReference when it is closed
1071    *
1072    * @param address
1073    */
1074   public static void closedNetworkChannel(final SocketAddress address) {
1075     if (address == null) {
1076       return;
1077     }
1078     final NetworkChannelReference networkChannelReference =
1079         networkChannelOnSocketAddressConcurrentHashMap.get(address.hashCode());
1080     closedNetworkChannel(networkChannelReference);
1081   }
1082 
1083   /**
1084    * Class to close the Network Channel if after some delays it has really no
1085    * Local Channel attached
1086    */
1087   private static class CloseFutureChannel implements TimerTask {
1088 
1089     private static final Set<ChannelId> inCloseRunning =
1090         ConcurrentUtility.newConcurrentSet();
1091     private final NetworkChannelReference networkChannelReference;
1092 
1093     /**
1094      * @param networkChannelReference
1095      *
1096      * @throws OpenR66RunnerErrorException
1097      */
1098     private CloseFutureChannel(
1099         final NetworkChannelReference networkChannelReference)
1100         throws OpenR66RunnerErrorException {
1101       if (!inCloseRunning.add(networkChannelReference.channel.id())) {
1102         throw new OpenR66RunnerErrorException("Already scheduled");
1103       }
1104       this.networkChannelReference = networkChannelReference;
1105     }
1106 
1107     @Override
1108     public void run(final Timeout timeout) {
1109       final long time = networkChannelReference.shutdownAllowed();
1110       if (time > 0) {
1111         Configuration.configuration.getTimerClose().newTimeout(this, time,
1112                                                                TimeUnit.MILLISECONDS);
1113         return;
1114       } else if (time == 0) {
1115         networkChannelReference.isShuttingDown = true;
1116         WaarpSslUtility.closingSslChannel(networkChannelReference.channel);
1117       }
1118     }
1119 
1120   }
1121 
1122   /**
1123    * Check if closing of the localChannel will bring future closing of
1124    * NetworkChannel
1125    *
1126    * @param networkChannelReference
1127    * @param localChannelReference
1128    *
1129    * @return the number of local channel still connected to this channel
1130    */
1131   public static int checkClosingNetworkChannel(
1132       final NetworkChannelReference networkChannelReference,
1133       final LocalChannelReference localChannelReference) {
1134     networkChannelReference.lock.lock(Configuration.WAITFORNETOP,
1135                                       TimeUnit.MILLISECONDS);
1136     try {
1137       logger.debug("Close con: {}", networkChannelReference);
1138       if (localChannelReference != null) {
1139         networkChannelReference.closeAndRemove(localChannelReference);
1140       }
1141       final int count = networkChannelReference.nbLocalChannels();
1142       if (count <= 0) {
1143         logger.debug("Will try to Close con: {}", networkChannelReference);
1144         final CloseFutureChannel cfc;
1145         try {
1146           cfc = new CloseFutureChannel(networkChannelReference);
1147           Configuration.configuration.getTimerClose().newTimeout(cfc,
1148                                                                  Configuration.configuration.getTimeoutCon() *
1149                                                                  2,
1150                                                                  TimeUnit.MILLISECONDS);
1151         } catch (final OpenR66RunnerErrorException ignored) {
1152           // nothing
1153         } catch (final IllegalStateException ignored) {
1154           // nothing
1155         }
1156       } else {
1157         networkChannelReference.use();
1158         logger.debug("Ignore shutdown after checking");
1159       }
1160       logger.debug("NC left: {}", networkChannelReference);
1161       return count;
1162     } finally {
1163       networkChannelReference.lock.unlock();
1164     }
1165   }
1166 
1167   /**
1168    * @param address
1169    * @param host
1170    *
1171    * @return a number > 0 if a connection is still active on this socket or
1172    *     for
1173    *     this host
1174    */
1175   public static int nbAttachedConnection(final SocketAddress address,
1176                                          final String host) {
1177     if (logger.isDebugEnabled()) {
1178       logger.debug("nbAttachedConnection: {}:{}",
1179                    networkChannelOnSocketAddressConcurrentHashMap.containsKey(
1180                        address.hashCode()), getNumberClients(host));
1181     }
1182     return (networkChannelOnSocketAddressConcurrentHashMap.containsKey(
1183         address.hashCode())? 1 : 0) + getNumberClients(host);
1184   }
1185 
1186   /**
1187    * @param address
1188    *
1189    * @return True if this socket Address is currently valid for connection
1190    */
1191   private static boolean isAddressValid(final SocketAddress address) {
1192     if (WaarpShutdownHook.isShutdownStarting()) {
1193       logger.debug("IS IN SHUTDOWN");
1194       return false;
1195     }
1196     if (address == null) {
1197       logger.debug("ADDRESS IS NULL");
1198       return false;
1199     }
1200     try {
1201       final NetworkChannelReference networkChannelReference =
1202           getRemoteChannel(address);
1203       logger.debug("IS IN SHUTDOWN: {}",
1204                    networkChannelReference.isShuttingDown);
1205       return !networkChannelReference.isShuttingDown;
1206     } catch (final OpenR66ProtocolRemoteShutdownException e) {
1207       logger.debug("ALREADY IN SHUTDOWN");
1208       return false;
1209     } catch (final OpenR66ProtocolNoDataException e) {
1210       logger.debug("NOT FOUND SO NO SHUTDOWN");
1211       return true;
1212     } catch (final OpenR66ProtocolBlackListedException e) {
1213       logger.warn("BLACK LISTED HOST");
1214       return false;
1215     }
1216   }
1217 
1218   /**
1219    * Returns the NetworkChannelReference if it exists associated with this
1220    * address
1221    *
1222    * @param address
1223    *
1224    * @return NetworkChannelReference
1225    *
1226    * @throws OpenR66ProtocolRemoteShutdownException
1227    * @throws OpenR66ProtocolNoDataException
1228    * @throws OpenR66ProtocolBlackListedException
1229    */
1230   private static NetworkChannelReference getRemoteChannel(
1231       final SocketAddress address)
1232       throws OpenR66ProtocolRemoteShutdownException,
1233              OpenR66ProtocolNoDataException,
1234              OpenR66ProtocolBlackListedException {
1235     if (WaarpShutdownHook.isShutdownStarting()) {
1236       logger.debug("IS IN SHUTDOWN");
1237       throw new OpenR66ProtocolRemoteShutdownException(
1238           "Local Host already in shutdown");
1239     }
1240     if (address == null) {
1241       logger.debug("ADDRESS IS NULL");
1242       throw new OpenR66ProtocolRemoteShutdownException(
1243           "Cannot connect to remote server since address is not specified");
1244     }
1245     NetworkChannelReference nc = getShutdownNCR(address);
1246     if (nc != null) {
1247       logger.debug("HOST STILL IN SHUTDOWN STATUS: {}", address);
1248       throw new OpenR66ProtocolRemoteShutdownException(
1249           "Remote Host already in shutdown");
1250     }
1251     nc = getBlacklistNCR(address);
1252     if (nc != null) {
1253       logger.debug("HOST IN BLACKLISTED STATUS: {}", address);
1254       throw new OpenR66ProtocolBlackListedException(
1255           "Remote Host is blacklisted");
1256     }
1257     nc = getNCR(address);
1258     if (nc != null && (nc.isShuttingDown || !nc.channel().isActive())) {
1259       logger.debug("HOST IS DisActive: {}", address);
1260       throw new OpenR66ProtocolRemoteShutdownException(
1261           "Remote Host is disActive");
1262     }
1263     if (nc == null) {
1264       throw new OpenR66ProtocolNoDataException("Channel not found");
1265     }
1266     return nc;
1267   }
1268 
1269   /**
1270    * @param channel
1271    *
1272    * @return the associated NetworkChannelReference immediately (if known)
1273    */
1274   public static NetworkChannelReference getImmediateNetworkChannel(
1275       final Channel channel) {
1276     if (channel.remoteAddress() != null) {
1277       return getNCR(channel.remoteAddress());
1278     }
1279     return null;
1280   }
1281 
1282   /**
1283    * Remover of Shutdown Remote Host
1284    */
1285   private static class R66ShutdownNetworkChannelTimerTask implements TimerTask {
1286     private static final Set<ChannelId> inShutdownRunning =
1287         ConcurrentUtility.newConcurrentSet();
1288     private static final Set<ChannelId> inBlacklistedRunning =
1289         ConcurrentUtility.newConcurrentSet();
1290     /**
1291      * NCR to remove
1292      */
1293     private final NetworkChannelReference ncr;
1294     private final boolean isBlacklisted;
1295 
1296     /**
1297      * Constructor from type
1298      *
1299      * @throws OpenR66RunnerErrorException
1300      */
1301     private R66ShutdownNetworkChannelTimerTask(
1302         final NetworkChannelReference ncr, final boolean blackListed)
1303         throws OpenR66RunnerErrorException {
1304       if (blackListed) {
1305         if (!inBlacklistedRunning.add(ncr.channel.id())) {
1306           throw new OpenR66RunnerErrorException("Already scheduled");
1307         }
1308       } else {
1309         if (ncr.channel != null && !inShutdownRunning.add(ncr.channel.id())) {
1310           throw new OpenR66RunnerErrorException("Already scheduled");
1311         }
1312       }
1313       this.ncr = ncr;
1314       isBlacklisted = blackListed;
1315     }
1316 
1317     @Override
1318     public void run(final Timeout timeout) {
1319       if (isBlacklisted) {
1320         logger.debug("Will remove Blacklisted for : {}", ncr);
1321         removeBlacklistNCR(ncr);
1322         inBlacklistedRunning.remove(ncr.channel.id());
1323         return;
1324       }
1325       logger.debug("Will remove Shutdown for : {}", ncr);
1326       if (ncr.channel != null && ncr.channel.isActive()) {
1327         WaarpSslUtility.closingSslChannel(ncr.channel);
1328       }
1329       removeShutdownNCR(ncr);
1330       if (ncr.channel != null) {
1331         inShutdownRunning.remove(ncr.channel.id());
1332       }
1333     }
1334   }
1335 
1336   /**
1337    * @return the current number of active RetrieveRunner
1338    */
1339   public static int getRetrieveRunnerActive() {
1340     return Configuration.configuration.getRetrieveRunnerGroup()
1341                                       .getActiveCount();
1342   }
1343 
1344   /**
1345    * Start retrieve operation
1346    *
1347    * @param session
1348    */
1349   public static void runRetrieve(final R66Session session) {
1350     final RetrieveRunner retrieveRunner = new RetrieveRunner(session);
1351     retrieveRunnerConcurrentHashMap.put(
1352         session.getLocalChannelReference().getLocalId(), retrieveRunner);
1353     Configuration.configuration.getRetrieveRunnerGroup()
1354                                .execute(retrieveRunner);
1355   }
1356 
1357   /**
1358    * Stop a retrieve operation
1359    *
1360    * @param localChannelReference
1361    */
1362   public static void stopRetrieve(
1363       final LocalChannelReference localChannelReference) {
1364     final RetrieveRunner retrieveRunner =
1365         retrieveRunnerConcurrentHashMap.remove(
1366             localChannelReference.getLocalId());
1367     if (retrieveRunner != null) {
1368       retrieveRunner.stopRunner();
1369     }
1370   }
1371 
1372   /**
1373    * Normal end of a Retrieve Operation
1374    *
1375    * @param localChannelReference
1376    */
1377   public static void normalEndRetrieve(
1378       final LocalChannelReference localChannelReference) {
1379     retrieveRunnerConcurrentHashMap.remove(localChannelReference.getLocalId());
1380   }
1381 
1382   /**
1383    * Close all Network Ttransaction
1384    */
1385   public final void closeAll() {
1386     closeAll(true);
1387   }
1388 
1389   /**
1390    * Close all Network Ttransaction
1391    */
1392   public final void closeAll(final boolean quickShutdown) {
1393     logger.debug("close All Network Channels");
1394     if (!Configuration.configuration.isServer()) {
1395       if (shutdownHook != null) {
1396         shutdownHook.launchFinalExit();
1397       }
1398     }
1399     if (networkChannelGroup != null) {
1400       WaarpNettyUtil.awaitOrInterrupted(networkChannelGroup.close());
1401       networkChannelGroup = null;
1402     }
1403     try {
1404       Thread.sleep(Configuration.WAITFORNETOP);
1405     } catch (final InterruptedException e) {//NOSONAR
1406       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
1407     }
1408     stopAllEndRetrieve();
1409     DbAdmin.closeAllConnection();
1410     Configuration.configuration.clientStop(quickShutdown);
1411     if (!Configuration.configuration.isServer()) {
1412       logger.debug("Last action before exit");
1413       WaarpSystemUtil.stopLogger(false);
1414     }
1415   }
1416 
1417 
1418   public static void stopAllEndRetrieve() {
1419     final Enumeration<RetrieveRunner> enumeration =
1420         retrieveRunnerConcurrentHashMap.elements();
1421     while (enumeration.hasMoreElements()) {
1422       final RetrieveRunner runner = enumeration.nextElement();
1423       runner.stopRunner();
1424     }
1425     retrieveRunnerConcurrentHashMap.clear();
1426   }
1427 }