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

com.gemstone.org.jgroups.protocols.obsolete.TCP.txt Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
// $Id: TCP.java.txt,v 1.1 2005/06/27 08:48:12 belaban Exp $

package org.jgroups.protocols;


import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.Message;
import org.jgroups.View;
import org.jgroups.blocks.ConnectionTable;
import org.jgroups.stack.IpAddress;
import org.jgroups.stack.Protocol;
import org.jgroups.util.BoundedList;
import org.jgroups.util.Util;

import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Properties;
import java.util.Vector;




/**
 * TCP based protocol. Creates a server socket, which gives us the local address of this group member. For
 * each accept() on the server socket, a new thread is created that listens on the socket.
 * For each outgoing message m, if m.dest is in the ougoing hashtable, the associated socket will be reused
 * to send message, otherwise a new socket is created and put in the hashtable.
 * When a socket connection breaks or a member is removed from the group, the corresponding items in the
 * incoming and outgoing hashtables will be removed as well.
* This functionality is in ConnectionTable, which isT used by TCP. TCP sends messages using ct.send() and * registers with the connection table to receive all incoming messages. * @author Bela Ban */ public class TCP extends Protocol implements ConnectionTable.Receiver { private ConnectionTable ct=null; protected Address local_addr=null; private String group_addr=null; private InetAddress bind_addr=null; // local IP address to bind srv sock to (m-homed systems) private InetAddress external_addr=null; // the IP address which is broadcast to other group members private int start_port=7800; // find first available port starting at this port private int end_port=0; // maximum port to bind to private final Vector members=new Vector(11); private long reaper_interval=0; // time in msecs between connection reaps private long conn_expire_time=0; // max time a conn can be idle before being reaped boolean loopback=false; // loops back msgs to self if true /** If set it will be added to local_addr. Used to implement * for example transport independent addresses */ byte[] additional_data=null; /** List the maintains the currently suspected members. This is used so we don't send too many SUSPECT * events up the stack (one per message !) */ final BoundedList suspected_mbrs=new BoundedList(20); /** Should we drop unicast messages to suspected members or not */ boolean skip_suspected_members=true; int recv_buf_size=150000; int send_buf_size=150000; int sock_conn_timeout=2000; // max time in millis for a socket creation in ConnectionTable static final String name="TCP"; static final String IGNORE_BIND_ADDRESS_PROPERTY="ignore.bind.address"; int num_msgs_sent=0, num_msgs_received=0; public TCP() { } public String toString() { return "Protocol TCP(local address: " + local_addr + ')'; } public String getName() { return "TCP"; } public long getNumMessagesSent() {return num_msgs_sent;} public long getNumMessagesReceived() {return num_msgs_received;} public int getOpenConnections() {return ct.getNumConnections();} public InetAddress getBindAddr() {return bind_addr;} public void setBindAddr(InetAddress bind_addr) {this.bind_addr=bind_addr;} public int getStartPort() {return start_port;} public void setStartPort(int start_port) {this.start_port=start_port;} public int getEndPort() {return end_port;} public void setEndPort(int end_port) {this.end_port=end_port;} public long getReaperInterval() {return reaper_interval;} public void setReaperInterval(long reaper_interval) {this.reaper_interval=reaper_interval;} public long getConnExpireTime() {return conn_expire_time;} public void setConnExpireTime(long conn_expire_time) {this.conn_expire_time=conn_expire_time;} public boolean isLoopback() {return loopback;} public void setLoopback(boolean loopback) {this.loopback=loopback;} public String printConnections() {return ct.toString();} public void resetStats() { super.resetStats(); num_msgs_sent=num_msgs_received=0; } protected final Vector getMembers() { return members; } /** DON'T REMOVE ! This prevents the up-handler thread to be created, which essentially is superfluous: messages are received from the network rather than from a layer below. */ public void startUpHandler() { ; } public void start() throws Exception { ct=getConnectionTable(reaper_interval,conn_expire_time,bind_addr,external_addr,start_port,end_port); // ct.addConnectionListener(this); ct.setReceiveBufferSize(recv_buf_size); ct.setSendBufferSize(send_buf_size); ct.setSocketConnectionTimeout(sock_conn_timeout); local_addr=ct.getLocalAddress(); if(additional_data != null && local_addr instanceof IpAddress) ((IpAddress)local_addr).setAdditionalData(additional_data); passUp(new Event(Event.SET_LOCAL_ADDRESS, local_addr)); } /** * @param reaperInterval * @param connExpireTime * @param bindAddress * @param startPort * @throws Exception * @return ConnectionTable * Sub classes overrides this method to initialize a different version of * ConnectionTable. */ protected ConnectionTable getConnectionTable(long reaperInterval, long connExpireTime, InetAddress bindAddress, InetAddress externalAddress, int startPort, int endPort) throws Exception { ConnectionTable cTable=null; if(reaperInterval == 0 && connExpireTime == 0) { cTable=new ConnectionTable(this, bindAddress, externalAddress, startPort, endPort); } else { if(reaperInterval == 0) { reaperInterval=5000; if(log.isWarnEnabled()) log.warn("reaper_interval was 0, set it to " + reaperInterval); } if(connExpireTime == 0) { connExpireTime=1000 * 60 * 5; if(log.isWarnEnabled()) log.warn("conn_expire_time was 0, set it to " + connExpireTime); } cTable=new ConnectionTable(this, bindAddress, externalAddress, startPort, endPort, reaperInterval, connExpireTime); } return cTable; } public void stop() { ct.stop(); } /** Sent to destination(s) using the ConnectionTable class. */ public void down(Event evt) { Message msg; Object dest_addr; if(evt.getType() != Event.MSG) { handleDownEvent(evt); return; } msg=(Message)evt.getArg(); num_msgs_sent++; if(group_addr != null) { // added patch sent by Roland Kurmann (bela March 20 2003) /* Add header (includes channel name) */ msg.putHeader(name, new TcpHeader(group_addr)); } dest_addr=msg.getDest(); /* Because we don't call Protocol.passDown(), we notify the observer directly (e.g. PerfObserver). This way, we still have performance numbers for TCP */ if(observer != null) observer.passDown(evt); if(dest_addr == null) { // broadcast (to all members) if(group_addr == null) { if(log.isWarnEnabled()) log.warn("dest address of message is null, and " + "sending to default address fails as group_addr is null, too !" + " Discarding message."); return; } else { sendMulticastMessage(msg); // send to current membership } } else { sendUnicastMessage(msg); // send to a single member } } /** ConnectionTable.Receiver interface */ public void receive(Message msg) { TcpHeader hdr=null; Event evt=new Event(Event.MSG, msg); /* Because Protocol.up() is never called by this bottommost layer, we call up() directly in the observer. This allows e.g. PerfObserver to get the time of reception of a message */ if(observer != null) observer.up(evt, up_queue.size()); if(log.isTraceEnabled()) log.trace("received msg " + msg); num_msgs_received++; hdr=(TcpHeader)msg.removeHeader(name); if(hdr != null) { /* Discard all messages destined for a channel with a different name */ String ch_name=null; if(hdr.group_addr != null) ch_name=hdr.group_addr; // below lines were commented as patch sent by Roland Kurmann (bela March 20 2003) // if(group_addr == null) { // if(log.isWarnEnabled()) log.warn("TCP.receive()", "group address in header was null, discarded"); // return; // } // Discard if message's group name is not the same as our group name unless the // message is a diagnosis message (special group name DIAG_GROUP) if(ch_name != null && !group_addr.equals(ch_name) && !ch_name.equals(Util.DIAG_GROUP)) { if(log.isWarnEnabled()) log.warn("discarded message from different group (" + ch_name + "). Sender was " + msg.getSrc()); return; } } passUp(evt); } // ConnectionTable.ConnectionListener interface // public void connectionOpened(Address peer_addr) { // if(log.isTraceEnabled()) log.trace("opened connection to " + peer_addr); // } // // public void connectionClosed(Address peer_addr) { // if(peer_addr != null) // if(log.isTraceEnabled()) log.trace("closed connection to " + peer_addr); // } /** Setup the Protocol instance acording to the configuration string */ public boolean setProperties(Properties props) { String str, tmp=null; super.setProperties(props); str=props.getProperty("start_port"); if(str != null) { start_port=Integer.parseInt(str); props.remove("start_port"); } str=props.getProperty("end_port"); if(str != null) { end_port=Integer.parseInt(str); props.remove("end_port"); } // PropertyPermission not granted if running in an untrusted environment with JNLP. try { tmp=System.getProperty("bind.address"); // set by JBoss if(Boolean.getBoolean(IGNORE_BIND_ADDRESS_PROPERTY)) { tmp=null; } } catch (SecurityException ex){ } if(tmp != null) str=tmp; else str=props.getProperty("bind_addr"); if(str != null) { try { bind_addr=InetAddress.getByName(str); } catch(UnknownHostException unknown) { if(log.isFatalEnabled()) log.fatal("(bind_addr): host " + str + " not known"); return false; } props.remove("bind_addr"); } str=props.getProperty("external_addr"); if(str != null) { try { external_addr=InetAddress.getByName(str); } catch(UnknownHostException unknown) { if(log.isFatalEnabled()) log.fatal("(external_addr): host " + str + " not known"); return false; } props.remove("external_addr"); } str=props.getProperty("reaper_interval"); if(str != null) { reaper_interval=Long.parseLong(str); props.remove("reaper_interval"); } str=props.getProperty("conn_expire_time"); if(str != null) { conn_expire_time=Long.parseLong(str); props.remove("conn_expire_time"); } str=props.getProperty("sock_conn_timeout"); if(str != null) { sock_conn_timeout=Integer.parseInt(str); props.remove("sock_conn_timeout"); } str=props.getProperty("recv_buf_size"); if(str != null) { recv_buf_size=Integer.parseInt(str); props.remove("recv_buf_size"); } str=props.getProperty("send_buf_size"); if(str != null) { send_buf_size=Integer.parseInt(str); props.remove("send_buf_size"); } str=props.getProperty("loopback"); if(str != null) { loopback=Boolean.valueOf(str).booleanValue(); props.remove("loopback"); } str=props.getProperty("skip_suspected_members"); if(str != null) { skip_suspected_members=Boolean.valueOf(str).booleanValue(); props.remove("skip_suspected_members"); } if(props.size() > 0) { log.error("TCP.setProperties(): the following properties are not recognized: " + props); return false; } return true; } /** If the sender is null, set our own address. We cannot just go ahead and set the address anyway, as we might be sending a message on behalf of someone else ! E.g. in case of retransmission, when the original sender has crashed, or in a FLUSH protocol when we have to return all unstable messages with the FLUSH_OK response. */ private void setSourceAddress(Message msg) { if(msg.getSrc() == null) msg.setSrc(local_addr); } /** Send a message to the address specified in msg.dest */ private void sendUnicastMessage(Message msg) { IpAddress dest; Message copy; Object hdr; Event evt; dest=(IpAddress)msg.getDest(); // guaranteed not to be null if(!(dest instanceof IpAddress)) { if(log.isErrorEnabled()) log.error("destination address is not of type IpAddress !"); return; } setSourceAddress(msg); /* Don't send if destination is local address. Instead, switch dst and src and put in up_queue */ if(loopback && local_addr != null && dest != null && dest.equals(local_addr)) { copy=msg.copy(); hdr=copy.getHeader(name); if(hdr != null && hdr instanceof TcpHeader) copy.removeHeader(name); copy.setSrc(local_addr); copy.setDest(local_addr); evt=new Event(Event.MSG, copy); /* Because Protocol.up() is never called by this bottommost layer, we call up() directly in the observer. This allows e.g. PerfObserver to get the time of reception of a message */ if(observer != null) observer.up(evt, up_queue.size()); passUp(evt); return; } if(log.isTraceEnabled()) log.trace("dest=" + msg.getDest() + ", hdrs:\n" + msg.printObjectHeaders()); try { if(skip_suspected_members) { if(suspected_mbrs.contains(dest)) { if(log.isTraceEnabled()) log.trace("will not send unicast message to " + dest + " as it is currently suspected"); return; } } ct.send(msg); } catch(SocketException e) { if(members.contains(dest)) { if(!suspected_mbrs.contains(dest)) { suspected_mbrs.add(dest); passUp(new Event(Event.SUSPECT, dest)); } } } } protected void sendMulticastMessage(Message msg) { Address dest; Vector mbrs=(Vector)members.clone(); for(int i=0; i < mbrs.size(); i++) { dest=(Address)mbrs.elementAt(i); msg.setDest(dest); sendUnicastMessage(msg); } } protected void handleDownEvent(Event evt) { switch(evt.getType()) { case Event.TMP_VIEW: case Event.VIEW_CHANGE: suspected_mbrs.removeAll(); synchronized(members) { members.clear(); members.addAll(((View)evt.getArg()).getMembers()); } break; case Event.GET_LOCAL_ADDRESS: // return local address -> Event(SET_LOCAL_ADDRESS, local) passUp(new Event(Event.SET_LOCAL_ADDRESS, local_addr)); break; case Event.CONNECT: group_addr=(String)evt.getArg(); // removed March 18 2003 (bela), not needed (handled by GMS) // Can't remove it; otherwise TCPGOSSIP breaks (bela May 8 2003) ! passUp(new Event(Event.CONNECT_OK)); break; case Event.DISCONNECT: passUp(new Event(Event.DISCONNECT_OK)); break; case Event.CONFIG: if(log.isTraceEnabled()) log.trace("received CONFIG event: " + evt.getArg()); handleConfigEvent((HashMap)evt.getArg()); break; } } void handleConfigEvent(HashMap map) { if(map == null) return; if(map.containsKey("additional_data")) additional_data=(byte[])map.get("additional_data"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy