All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.protocols.TUNNEL Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
package org.jgroups.protocols;


import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.PhysicalAddress;
import org.jgroups.annotations.Component;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.annotations.Property;
import org.jgroups.conf.AttributeType;
import org.jgroups.stack.GossipData;
import org.jgroups.stack.IpAddress;
import org.jgroups.stack.RouterStub;
import org.jgroups.stack.RouterStubManager;
import org.jgroups.util.SocketFactory;
import org.jgroups.util.TLS;
import org.jgroups.util.Util;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * Replacement for UDP. Instead of sending packets via UDP, a TCP connection is opened to a Router
 * (using the RouterStub client-side stub), the IP address/port of which was given using channel
 * properties {@code router_host} and {@code router_port}. All outgoing traffic is sent
 * via this TCP socket to the Router which distributes it to all connected TUNNELs in this group.
 * Incoming traffic received from Router will simply be passed up the stack.
 * 
 * 

* A TUNNEL layer can be used to penetrate a firewall, most firewalls allow creating TCP connections * to the outside world, however, they do not permit outside hosts to initiate a TCP connection to a * host inside the firewall. Therefore, the connection created by the inside host is reused by * Router to send traffic from an outside host to a host inside the firewall. * * @author Bela Ban * @author Vladimir Blagojevic */ public class TUNNEL extends TP implements RouterStub.StubReceiver { public interface TUNNELPolicy { void sendToAllMembers(String group, Address sender, byte[] data, int offset, int length) throws Exception; void sendToSingleMember(String group, Address dest, Address sender, byte[] data, int offset, int length) throws Exception; } /* ----------------------------------------- Properties -------------------------------------------------- */ @Property(description = "Interval in msec to attempt connecting back to router in case of torn connection", type=AttributeType.TIME) protected long reconnect_interval=5000; @Property(description="Should TCP no delay flag be turned on") protected boolean tcp_nodelay; @Property(description="Whether to use blocking (false) or non-blocking (true) connections. If GossipRouter is used, " + "this needs to be false; if GossipRouterNio is used, it needs to be true") protected boolean use_nio; @Property(description="A comma-separated list of GossipRouter hosts, e.g. HostA[12001],HostB[12001]") protected String gossip_router_hosts; @Property(description="Sends a heartbeat to the GossipRouter every heartbeat_interval ms (0 disables this)", type=AttributeType.TIME) protected long heartbeat_interval; @Property(description="Max time (ms) with no received message or heartbeat after which the connection to a " + "GossipRouter is closed. Ignored when heartbeat_interval is 0.", type=AttributeType.TIME) protected long heartbeat_timeout; @Property(description="SO_LINGER in seconds. Default of -1 disables it") protected int linger=-1; // SO_LINGER (number of seconds, -1 disables it) @Property(description="use bounded queues for sending (https://issues.redhat.com/browse/JGRP-2759)") protected boolean non_blocking_sends; @Property(description="when sending and non_blocking, how many messages to queue max") protected int max_send_queue=128; /* ------------------------------------------ Fields ----------------------------------------------------- */ protected final List gossip_routers=new ArrayList<>(); protected TUNNELPolicy tunnel_policy=new DefaultTUNNELPolicy(); protected DatagramSocket sock; // used to get a unique client address protected volatile RouterStubManager stubManager; @Component(name="tls",description="Contains the attributes for TLS (SSL sockets) when enabled=true") protected TLS tls=new TLS(); public TUNNEL() { } public long getReconnectInterval() {return reconnect_interval;} public TUNNEL setReconnectInterval(long r) {this.reconnect_interval=r; return this;} public boolean isTcpNodelay() {return tcp_nodelay;} public TUNNEL setTcpNodelay(boolean nd) {this.tcp_nodelay=nd;return this;} public boolean useNio() {return use_nio;} public TUNNEL useNio(boolean use_nio) {this.use_nio=use_nio; return this;} public TLS tls() {return tls;} public TUNNEL tls(TLS t) {this.tls=t; return this;} public int getLinger() {return linger;} public TUNNEL setLinger(int l) {this.linger=l; return this;} public boolean nonBlockingSends() {return non_blocking_sends;} public TUNNEL nonBlockingSends(boolean b) {this.non_blocking_sends=b; return this;} public int maxSendQueue() {return max_send_queue;} public TUNNEL maxSendQueue(int s) {this.max_send_queue=s; return this;} /** We can simply send a message with dest == null and the GossipRouter will take care of routing it to all * members in the cluster */ public boolean supportsMulticasting() { return true; } public TUNNEL setGossipRouterHosts(String hosts) throws UnknownHostException { gossip_routers.clear(); // if we get passed value of List#toString() we have to strip [] if(hosts.startsWith("[") && hosts.endsWith("]")) hosts=hosts.substring(1, hosts.length() - 1); gossip_router_hosts=hosts; return this; } @ManagedAttribute(description="Is the reconnector task running?") public boolean isReconnectorTaskRunning() { return stubManager != null && stubManager.reconnectorRunning(); } @ManagedAttribute(description="Is the heartbeat task running?") public boolean isHeartbeatTaskRunning() { return stubManager != null && stubManager.heartbeaterRunning(); } @ManagedAttribute(description="Is the timeout check task running?") public boolean isTimeoutCheckTaskRunning() { return stubManager != null && stubManager.timeouterRunning(); } @ManagedOperation(description="Prints all stubs and the reconnect list") public String print() { RouterStubManager mgr=stubManager; return mgr != null? mgr.print() : "n/a"; } @ManagedOperation(description="Prints all currently connected stubs") public String printStubs() { RouterStubManager mgr=stubManager; return mgr != null? mgr.printStubs() : "n/a"; } @ManagedOperation(description="Prints the reconnect list") public String printReconnectList() { RouterStubManager mgr=stubManager; return mgr != null? mgr.printReconnectList() : "n/a"; } public RouterStubManager getStubManager() {return stubManager;} public String toString() { return "TUNNEL"; } /*------------------------------ Protocol interface ------------------------------ */ public synchronized TUNNEL setTUNNELPolicy(TUNNELPolicy policy) { if (policy == null) throw new IllegalArgumentException("Tunnel policy has to be non null"); tunnel_policy = policy; return this; } public void init() throws Exception { super.init(); if(timer == null) throw new Exception("timer cannot be retrieved from protocol stack"); if(port_range > 0) { log.warn("%s: port_range=%d; setting it to 0 (https://issues.redhat.com/browse/JGRP-2806)", local_addr, port_range); port_range=0; // https://issues.redhat.com/browse/JGRP-2806 } gossip_routers.clear(); gossip_routers.addAll(Util.parseCommaDelimitedHosts2(gossip_router_hosts, port_range)); if(gossip_routers.isEmpty()) throw new IllegalStateException("gossip_router_hosts needs to contain at least one address of a GossipRouter"); log.debug("gossip routers are %s", gossip_routers); stubManager=RouterStubManager.emptyGossipClientStubManager(log, timer).useNio(this.use_nio) .nonBlockingSends(non_blocking_sends).maxSendQueue(max_send_queue); sock=getSocketFactory().createDatagramSocket("jgroups.tunnel.ucast_sock", 0, bind_addr); } @Override public void start() throws Exception { super.start(); if(tls.enabled()) { SocketFactory factory=tls.createSocketFactory(); setSocketFactory(factory); } } public void destroy() { if(stubManager != null) stubManager.destroyStubs(); Util.close(sock); super.destroy(); } private void disconnectStub() { stubManager.disconnectStubs(); } @Override public Object down(Event evt) { Object retEvent = super.down(evt); switch (evt.getType()) { case Event.CONNECT: case Event.CONNECT_WITH_STATE_TRANSFER: case Event.CONNECT_USE_FLUSH: case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH: String group=evt.getArg(); Address local=local_addr; if(stubManager != null) stubManager.destroyStubs(); PhysicalAddress physical_addr=getPhysicalAddressFromCache(local); String logical_name=org.jgroups.util.NameCache.get(local); stubManager=new RouterStubManager(log,timer,group,local, logical_name, physical_addr, reconnect_interval) .useNio(this.use_nio).socketFactory(getSocketFactory()).heartbeat(heartbeat_interval, heartbeat_timeout) .nonBlockingSends(non_blocking_sends).maxSendQueue(max_send_queue); for(InetSocketAddress gr: gossip_routers) { try { InetSocketAddress target=gr.isUnresolved()? new InetSocketAddress(gr.getHostString(), gr.getPort()) : new InetSocketAddress(gr.getAddress(), gr.getPort()); stubManager.createAndRegisterStub(new InetSocketAddress(bind_addr, bind_port), target, linger) .receiver(this).tcpNoDelay(tcp_nodelay); } catch(Throwable t) { log.error("%s: failed creating stub to %s: %s", local, bind_addr + ":" + bind_port, t); } } stubManager.connectStubs(); break; case Event.DISCONNECT: disconnectStub(); break; } return retEvent; } @Override public void receive(GossipData data) { switch (data.getType()) { case MESSAGE: if(Objects.equals(local_addr, data.getSender())) return; byte[] msg=data.getBuffer(); receive(data.getSender(), msg, 0, msg.length); break; case SUSPECT: Address suspect=data.getAddress(); if(suspect != null) { log.debug("%s: firing suspect event for %s", local_addr, suspect); up(new Event(Event.SUSPECT, Collections.singletonList(suspect))); } break; } } @Override public void sendToAll(byte[] data, int offset, int length) throws Exception { String group=cluster_name != null? cluster_name.toString() : null; tunnel_policy.sendToAllMembers(group, local_addr, data, offset, length); } public void sendUnicast(PhysicalAddress dest, byte[] data, int offset, int length) throws Exception { String group=cluster_name != null? cluster_name.toString() : null; tunnel_policy.sendToSingleMember(group, dest, local_addr, data, offset, length); } protected void sendTo(final Address dest, byte[] buf, int offset, int length) throws Exception { if(dest instanceof PhysicalAddress) throw new IllegalArgumentException(String.format("destination %s cannot be a physical address", dest)); sendUnicast(dest, buf, offset, length); } protected void sendUnicast(Address dest, byte[] data, int offset, int length) throws Exception { String group=cluster_name != null? cluster_name.toString() : null; tunnel_policy.sendToSingleMember(group, dest, local_addr, data, offset, length); } public String getInfo() { return stubManager.printStubs(); } protected PhysicalAddress getPhysicalAddress() { return sock != null ? new IpAddress(bind_addr, sock.getLocalPort()) : null; } private class DefaultTUNNELPolicy implements TUNNELPolicy { public void sendToAllMembers(final String group, Address sender, final byte[] data, final int offset, final int length) throws Exception { stubManager.forAny( stub -> { try { if(log.isTraceEnabled()) log.trace("%s: sending a message to all members, GR used %s", local_addr, stub.gossipRouterAddress()); stub.sendToAllMembers(group, sender, data, offset, length); } catch(Exception ex) { log.warn("%s: failed sending a message to all members, router used %s: %s", local_addr, stub.gossipRouterAddress(), ex); } }); } public void sendToSingleMember(final String group, final Address dest, Address sender, final byte[] data, final int offset, final int length) throws Exception { stubManager.forAny( stub -> { try { if(log.isTraceEnabled()) log.trace("%s: sending a message to %s (router used %s)", local_addr, dest, stub.gossipRouterAddress()); stub.sendToMember(group, dest, sender, data, offset, length); } catch(Exception ex) { log.warn("%s: failed sending a message to %s (router used %s): %s", local_addr, dest, stub.gossipRouterAddress(), ex); } }); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy