![JAR search and dependency download from the Maven repository](/logo.png)
org.jgroups.protocols.UDP Maven / Gradle / Ivy
package org.jgroups.protocols;
import org.jgroups.Event;
import org.jgroups.Global;
import org.jgroups.PhysicalAddress;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.annotations.Property;
import org.jgroups.conf.AttributeType;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.SuppressLog;
import org.jgroups.util.Util;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.Formatter;
import java.util.List;
import java.util.Map;
/**
* IP multicast transport based on UDP. Messages to the group (msg.dest == null)
* will be multicast (to all group members), whereas point-to-point messages
* (msg.dest != null) will be unicast to a single member. Uses a multicast and a
* unicast socket.
*
* The following properties are read by the UDP protocol:
*
* - param mcast_addr - the multicast address to use; default is 239.8.8.8.
*
- param mcast_port - (int) the port that the multicast is sent on; default
* is 7600
*
- param ip_mcast - (boolean) flag whether to use IP multicast; default is
* true.
*
- param ip_ttl - the default time-to-live for multicast packets sent out
* on this socket; default is 8.
*
- param use_packet_handler - boolean, defaults to false. If set, the mcast
* and ucast receiver threads just put the datagram's payload (a byte buffer)
* into a queue, from where a separate thread will dequeue and handle them
* (unmarshal and pass up). This frees the receiver threads from having to do
* message unmarshalling; this time can now be spent receiving packets. If you
* have lots of retransmissions because of network input buffer overflow,
* consider setting this property to true.
*
*
* @author Bela Ban
*/
public class UDP extends TP {
/* ------------------------------------------ Properties ------------------------------------------ */
/**
* Traffic class for sending unicast and multicast datagrams. Valid values
* are (check {@link DatagramSocket#setTrafficClass(int)} ); for details):
*
* - {@code IPTOS_LOWCOST (0x02)}, decimal 2
* - {@code IPTOS_RELIABILITY (0x04)}<, decimal 4/li>
*
- {@code IPTOS_THROUGHPUT (0x08)}, decimal 8
* - {@code IPTOS_LOWDELAY (0x10)}, decimal 16
*
*/
@Property(description="Traffic class for sending unicast and multicast datagrams")
protected int tos; // valid values: 0, 2, 4, 8, 16
protected static final String UCAST_NAME="ucast-receiver";
protected static final String MCAST_NAME="mcast-receiver";
@Property(name="mcast_addr", description="The multicast address used for sending and receiving packets",
defaultValueIPv4="239.8.8.8", defaultValueIPv6="ff0e::8:8:8",
systemProperty=Global.UDP_MCAST_ADDR,writable=false)
protected InetAddress mcast_group_addr;
@Property(description="The multicast port used for sending and receiving packets. Default is 7600",
systemProperty=Global.UDP_MCAST_PORT, writable=false)
protected int mcast_port=7600;
@Property(description="Multicast toggle. If false multiple unicast datagrams are sent instead of one multicast. " +
"Default is true", writable=false)
protected boolean ip_mcast=true;
@Property(description="The time-to-live (TTL) for multicast datagram packets. Default is 8",systemProperty=Global.UDP_IP_TTL)
protected int ip_ttl=8;
@Property(description="Send buffer size of the multicast datagram socket",type=AttributeType.BYTES)
protected int mcast_send_buf_size=Global.MAX_DATAGRAM_PACKET_SIZE + MSG_OVERHEAD;
@Property(description="Receive buffer size of the multicast datagram socket",type=AttributeType.BYTES)
protected int mcast_recv_buf_size=5_000_000;
@Property(description="Send buffer size of the unicast datagram socket",type=AttributeType.BYTES)
protected int ucast_send_buf_size=200_000;
@Property(description="Receive buffer size of the unicast datagram socket",type=AttributeType.BYTES)
protected int ucast_recv_buf_size=5_000_000;
@Property(description="If true, disables IP_MULTICAST_LOOP on the MulticastSocket (for sending and receiving of " +
"multicast packets). IP multicast packets send on a host P will therefore not be received by anyone on P. Use with caution.")
protected boolean disable_loopback=false;
@Property(description="Suppresses warnings on Mac OS (for now) about not enough buffer space when sending " +
"a datagram packet",type=AttributeType.TIME)
protected long suppress_time_out_of_buffer_space=60000;
protected int unicast_receiver_threads=1;
protected int multicast_receiver_threads=1;
/* --------------------------------------------- Fields ------------------------------------------------ */
/** The multicast address (mcast address and port) this member uses */
protected IpAddress mcast_addr;
/**
* Socket used for
*
* - sending unicast and multicast packets and
*
- receiving unicast packets
*
* The address of this socket will be our local address (local_addr)
*/
protected MulticastSocket sock;
/** IP multicast socket for receiving multicast packets */
protected MulticastSocket mcast_sock;
/** Runnable to receive multicast packets */
protected PacketReceiver[] mcast_receivers;
/** Runnable to receive unicast packets */
protected PacketReceiver[] ucast_receivers;
protected SuppressLog suppress_log_out_of_buffer_space;
protected static final boolean is_android, is_mac;
static {
is_android=Util.checkForAndroid();
is_mac=Util.checkForMac();
}
public boolean supportsMulticasting() {return ip_mcast;}
public T setMulticasting(boolean fl) {this.ip_mcast=fl; return (T)this;}
public T setMulticastAddress(InetAddress a) {this.mcast_group_addr=a; return (T)this;}
public InetAddress getMulticastAddress() {return mcast_group_addr;}
public int getMulticastPort() {return mcast_port;}
public T setMulticastPort(int mcast_port) {this.mcast_port=mcast_port; return (T)this;}
public int getTos() {return tos;}
public UDP setTos(int t) {this.tos=t; return this;}
public InetAddress getMcastGroupAddr() {return mcast_group_addr;}
public UDP setMcastGroupAddr(InetAddress m) {this.mcast_group_addr=m; return this;}
public boolean ipMcast() {return ip_mcast;}
public UDP ipMcast(boolean i) {this.ip_mcast=i; return this;}
public int getIpTTL() {return ip_ttl;}
public UDP setIpTTL(int i) {this.ip_ttl=i; return this;}
public int getMcastSendBufSize() {return mcast_send_buf_size;}
public UDP setMcastSendBufSize(int m) {this.mcast_send_buf_size=m; return this;}
public int getMcastRecvBufSize() {return mcast_recv_buf_size;}
public UDP setMcastRecvBufSize(int m) {this.mcast_recv_buf_size=m; return this;}
public int getUcastSendBufSize() {return ucast_send_buf_size;}
public UDP setUcastSendBufSize(int u) {this.ucast_send_buf_size=u; return this;}
public int getUcastRecvBufSize() {return ucast_recv_buf_size;}
public UDP setUcastRecvBufSize(int u) {this.ucast_recv_buf_size=u; return this;}
public boolean disableLoopback() {return disable_loopback;}
public UDP disableLoopback(boolean d) {this.disable_loopback=d; return this;}
public long getSuppressTimeOutOfBufferSpace() {return suppress_time_out_of_buffer_space;}
public UDP setSuppressTimeOutOfBufferSpace(long s) {this.suppress_time_out_of_buffer_space=s; return this;}
/**
* Set the ttl for multicast socket
* @param ttl the time to live for the socket.
*/
public T setMulticastTTL(int ttl) {
this.ip_ttl=ttl;
setTimeToLive(ttl, sock);
return (T)this;
}
public int getMulticastTTL() {
return ip_ttl;
}
@ManagedAttribute(description="Number of messages dropped when sending because of insufficient buffer space"
,type=AttributeType.SCALAR)
public int getDroppedMessages() {
return suppress_log_out_of_buffer_space != null? suppress_log_out_of_buffer_space.getCache().size() : 0;
}
@ManagedOperation(description="Clears the cache for dropped messages")
public T clearDroppedMessagesCache() {
if(suppress_log_out_of_buffer_space != null)
suppress_log_out_of_buffer_space.getCache().clear();
return (T)this;
}
@Property(description="Number of unicast receiver threads, all reading from the same DatagramSocket. " +
"If de-serialization is slow, increasing the number of receiver threads might yield better performance.")
public T setUcastReceiverThreads(int num) {
if(unicast_receiver_threads != num) {
unicast_receiver_threads=num;
if(ucast_receivers != null) {
stopUcastReceiverThreads();
ucast_receivers=createReceivers(unicast_receiver_threads, sock, UCAST_NAME);
startUcastReceiverThreads();
}
}
return (T)this;
}
@Property(description="Number of unicast receiver threads, all reading from the same DatagramSocket. " +
"If de-serialization is slow, increasing the number of receiver threads might yield better performance.")
public int getUcastReceiverThreads() {
return unicast_receiver_threads;
}
@Property(description="Number of multicast receiver threads, all reading from the same MulticastSocket. " +
"If de-serialization is slow, increasing the number of receiver threads might yield better performance.")
public T setMcastReceiverThreads(int num) {
if(multicast_receiver_threads != num) {
multicast_receiver_threads=num;
if(mcast_receivers != null) {
stopMcastReceiverThreads();
mcast_receivers=createReceivers(multicast_receiver_threads, mcast_sock, MCAST_NAME);
startMcastReceiverThreads();
}
}
return (T)this;
}
@Property(description="Number of multicast receiver threads, all reading from the same MulticastSocket. " +
"If de-serialization is slow, increasing the number of receiver threads might yield better performance.")
public int getMcastReceiverThreads() {
return multicast_receiver_threads;
}
public String getInfo() {
return String.format("group_addr=%s:%d\n", mcast_group_addr.getHostName(), mcast_port);
}
@Override
public void sendToAll(byte[] data, int offset, int length) throws Exception {
if(ip_mcast && mcast_addr != null) {
if(local_transport != null) {
try {
local_transport.sendToAll(data, offset, length);
}
catch(Exception ex) {
log.warn("failed sending group message via local transport, sending it via regular transport", ex);
}
}
_send(mcast_addr.getIpAddress(), mcast_addr.getPort(), data, offset, length);
}
else
super.sendToAll(data, offset, length);
}
public void sendUnicast(PhysicalAddress dest, byte[] data, int offset, int length) throws Exception {
_send(((IpAddress)dest).getIpAddress(), ((IpAddress)dest).getPort(), data, offset, length);
}
protected void _send(InetAddress dest, int port, byte[] data, int offset, int length) throws Exception {
DatagramPacket packet=new DatagramPacket(data, offset, length, dest, port);
// using the datagram socket to send multicasts or unicasts (https://issues.redhat.com/browse/JGRP-1765)
if(sock != null) {
try {
sock.send(packet);
}
catch(IOException ex) {
if(suppress_log_out_of_buffer_space != null)
suppress_log_out_of_buffer_space.log(SuppressLog.Level.warn, dest, suppress_time_out_of_buffer_space,
local_addr, dest == null? "cluster" : dest, ex);
else
throw ex;
}
}
}
/* ------------------------------------------------------------------------------- */
/*------------------------------ Protocol interface ------------------------------ */
@Override
public Object down(Event evt) {
Object retval=super.down(evt);
if(evt.getType() == Event.VIEW_CHANGE) {
if(suppress_log_out_of_buffer_space != null)
suppress_log_out_of_buffer_space.removeExpired(suppress_time_out_of_buffer_space);
if(local_transport != null) {
try {
// if we have local members, we send the multicast through the local transport, and do *not* need
// to receive a copy on the local host
sock.setLoopbackMode(true);
mcast_sock.setLoopbackMode(true);
}
catch(SocketException e) {
log.error("failed enabling loopback-mode to", e);
}
}
}
return retval;
}
public void init() throws Exception {
super.init();
if(bundler.getMaxSize() > Global.MAX_DATAGRAM_PACKET_SIZE)
throw new IllegalArgumentException("bundler.max_size (" + bundler.getMaxSize() + ") cannot exceed the max " +
"datagram packet size of " + Global.MAX_DATAGRAM_PACKET_SIZE);
if(is_mac && suppress_time_out_of_buffer_space > 0)
suppress_log_out_of_buffer_space=new SuppressLog<>(log, "FailureSendingToPhysAddr", "SuppressMsg");
}
/** Creates the unicast and multicast sockets and starts the unicast and multicast receiver threads */
public void start() throws Exception {
try {
createSockets();
super.start();
}
catch(Exception ex) {
destroySockets();
throw ex;
}
ucast_receivers=createReceivers(unicast_receiver_threads, sock, UCAST_NAME);
if(ip_mcast)
mcast_receivers=createReceivers(multicast_receiver_threads, mcast_sock, MCAST_NAME);
}
public void stop() {
super.stop();
log.debug("%s: closing sockets and stopping threads", local_addr);
destroySockets();
stopThreads();
}
protected void handleConnect() throws Exception {
startThreads();
}
protected void setCorrectSocketBufferSize(MulticastSocket s, int buf_size, int new_size, boolean send, boolean mcast)
throws SocketException {
String so=String.format("%s%s", mcast? "mcast ": "", send? "send":"receive");
log.warn("%s: setting %s socket buffer size (%s) to %s (size of the max datagram packet)",
local_addr, so, Util.printBytes(buf_size), Util.printBytes(new_size));
if(send)
s.setSendBufferSize(new_size);
else
s.setReceiveBufferSize(new_size);
}
/*--------------------------- End of Protocol interface -------------------------- */
/* ------------------------------ Private Methods -------------------------------- */
protected static Method findMethod(Class> clazz, String method_name, Class> ... parameters) {
try {
Method method=clazz.getDeclaredMethod(method_name, parameters);
method.setAccessible(true);
return method;
}
catch(Throwable t) {
return null;
}
}
/** Creates the UDP sender and receiver sockets */
protected void createSockets() throws Exception {
if(bind_addr == null)
throw new IllegalArgumentException("bind_addr cannot be null");
Util.checkIfValidAddress(bind_addr, getName());
if(log.isDebugEnabled()) log.debug("sockets will use interface " + bind_addr.getHostAddress());
// Create socket for receiving unicast UDP packets and sending of IP multicast packets. The bind address
// and port of this socket will be our local physical address (local_addr)
// 1: sock is bound to bind_addr:bind_port, which means it will *receive* packets only on bind_addr:bind_port
// 2: sock's setInterface() method is used to determine the interface to *send* multicasts (unicasts use the
// interface determined by consulting the routing table)
if(bind_port > 0)
sock=createMulticastSocketWithBindPort();
else
sock=createMulticastSocket("jgroups.udp.sock", 0);
setTimeToLive(ip_ttl, sock);
if(tos > 0) {
try {
sock.setTrafficClass(tos);
}
catch(SocketException e) {
log.warn(Util.getMessage("TrafficClass"), tos, e);
}
}
// 3. Create socket for receiving IP multicast packets
if(ip_mcast) {
// https://issues.redhat.com/browse/JGRP-777 - this doesn't work on MacOS, and we don't have
// cross talking on Windows anyway, so we just do it for Linux. (How about Solaris ?)
// If possible, the MulticastSocket(SocketAddress) ctor is used which binds to mcast_addr:mcast_port.
// This acts like a filter, dropping multicasts to different multicast addresses
if(Util.can_bind_to_mcast_addr)
mcast_sock=Util.createMulticastSocket(getSocketFactory(), "jgroups.udp.mcast_sock", mcast_group_addr, mcast_port, log);
else
mcast_sock=getSocketFactory().createMulticastSocket("jgroups.udp.mcast_sock", mcast_port);
if(disable_loopback) {
mcast_sock.setLoopbackMode(true);
sock.setLoopbackMode(true);
}
mcast_addr=new IpAddress(mcast_group_addr, mcast_port);
// check that we're not using the same mcast address and port as the diagnostics socket
if(diag_handler.isEnabled() && diag_handler.getMcastAddress().equals(mcast_group_addr)
&& diag_handler.getPort() == mcast_port)
throw new IllegalArgumentException("diagnostics_addr:diagnostics_port and mcast_addr:mcast_port " +
"have to be different");
if(tos > 0) {
try {
mcast_sock.setTrafficClass(tos);
}
catch(SocketException e) {
log.warn(Util.getMessage("TrafficClass"), tos, e);
}
}
if(receive_on_all_interfaces || (receive_interfaces != null && !receive_interfaces.isEmpty())) {
List interfaces;
if(receive_interfaces != null)
interfaces=receive_interfaces;
else
interfaces=Util.getAllAvailableInterfaces();
joinGroupOnInterfaces(interfaces, mcast_sock, mcast_addr.getIpAddress());
}
else {
if(bind_addr != null)
setNetworkInterface(bind_addr, mcast_sock); // not strictly needed for receiving, only for sending of mcasts
mcast_sock.joinGroup(new InetSocketAddress(mcast_group_addr, mcast_port),
bind_addr == null? null : NetworkInterface.getByInetAddress(bind_addr));
}
}
setBufferSizes();
log.debug("socket information:\n%s", dumpSocketInfo());
}
protected void destroySockets() {
closeMulticastSocket();
closeUnicastSocket();
}
protected PacketReceiver[] createReceivers(int num, DatagramSocket sock, String name) {
PacketReceiver[] receivers=new PacketReceiver[num];
for(int i=0; i < num; i++)
receivers[i]=new PacketReceiver(sock, name);
return receivers;
}
protected IpAddress createLocalAddress() {
if(sock == null || sock.isClosed())
return null;
if(external_addr != null) {
if(external_port > 0)
return new IpAddress(external_addr, external_port);
return new IpAddress(external_addr, sock.getLocalPort());
}
return new IpAddress(sock.getLocalAddress(), sock.getLocalPort());
}
protected T setTimeToLive(int ttl, MulticastSocket s) {
try {
if(s != null)
s.setTimeToLive(ttl);
}
catch(Throwable ex) { // just in case Windows throws an exception (DualStack impl, not implemented)
log.error("failed setting ip_ttl to %d: %s", ttl, ex);
}
return (T)this;
}
protected T setNetworkInterface(InetAddress addr, MulticastSocket s) {
NetworkInterface intf=null;
try {
if(s != null && addr != null) {
intf=NetworkInterface.getByInetAddress(addr);
s.setNetworkInterface(intf);
if (log.isDebugEnabled()) {
log.debug(String.format("multicast_socket on %s", intf.getName()));
}
}
}
catch(Throwable ex) {
log.error("failed setting interface to %s (%s): %s", intf, addr, ex);
}
return (T)this;
}
protected PhysicalAddress getPhysicalAddress() {
return createLocalAddress();
}
/**
* Joins a multicast address on all interfaces
* @param interfaces List. The interfaces to join mcast_addr:mcast_port
* @param s The MulticastSocket to join on
* @param mcast_addr The multicast address to join
*/
protected void joinGroupOnInterfaces(List interfaces, MulticastSocket s, InetAddress mcast_addr) {
SocketAddress tmp_mcast_addr=new InetSocketAddress(mcast_addr, mcast_port);
for(NetworkInterface intf: interfaces) {
//[ JGRP-680] - receive_on_all_interfaces requires every NIC to be configured
try {
s.joinGroup(tmp_mcast_addr, intf);
log.debug("joined %s on %s", tmp_mcast_addr, intf.getName());
}
catch(IOException e) {
log.warn(Util.getMessage("InterfaceJoinFailed"), tmp_mcast_addr, intf.getName());
}
}
}
/**
* Creates a DatagramSocket when bind_port > 0. Attempts to allocate the socket with port == bind_port, and
* increments until it finds a valid port, or until port_range has been exceeded
* @return DatagramSocket The newly created socket
* @throws Exception
*/
protected MulticastSocket createMulticastSocketWithBindPort() throws Exception {
MulticastSocket tmp=null;
Exception saved_exception=null;
// 27-6-2003 bgooren, find available port in range (start_port, start_port+port_range)
int rcv_port=bind_port, max_port=bind_port + port_range;
while(rcv_port <= max_port) {
try {
return createMulticastSocket("jgroups.udp.sock", rcv_port);
}
catch(SocketException | SecurityException bind_ex) { // Cannot listen on this port
rcv_port++;
saved_exception=bind_ex;
}
}
// Cannot listen at all, throw an Exception
if(rcv_port >= max_port + 1) // +1 due to the increment above
throw new Exception(String.format("failed to open a port in range %d-%d (last exception: %s)",
bind_port, max_port, saved_exception));
return tmp;
}
protected MulticastSocket createMulticastSocket(String service_name, int port) throws Exception {
// Creates an *unbound* multicast socket (because SocketAddress is null)
MulticastSocket retval=getSocketFactory().createMulticastSocket(service_name, null); // causes *no* binding !
if(bind_addr != null)
setNetworkInterface(bind_addr, retval);
retval.setReuseAddress(false); // so we get a conflict if binding to the same port and increment the port
retval.bind(new InetSocketAddress(bind_addr, port));
return retval;
}
protected String dumpSocketInfo() throws Exception {
StringBuilder sb=new StringBuilder(128);
Formatter formatter=new Formatter(sb);
formatter.format("mcast_addr=%s, bind_addr=%s, ttl=%d", mcast_addr, bind_addr, ip_ttl);
if(sock != null)
formatter.format("\nsock: bound to %s:%d, receive buffer size=%d, send buffer size=%d",
sock.getLocalAddress().getHostAddress(), sock.getLocalPort(),
sock.getReceiveBufferSize(), sock.getSendBufferSize());
if(mcast_sock != null)
formatter.format("\nmcast_sock: bound to %s:%d, send buffer size=%d, receive buffer size=%d",
mcast_sock.getLocalAddress(), mcast_sock.getLocalPort(),
mcast_sock.getSendBufferSize(), mcast_sock.getReceiveBufferSize());
NetworkInterface nic=bind_addr != null? NetworkInterface.getByInetAddress(bind_addr) : null;
String nic_name=nic != null? nic.getName() : "n/a";
if(bind_port > 0)
formatter.format("\n%s: using network interface '%s' with port range '%s-%s'", bind_addr, nic_name, bind_port, (bind_port + port_range));
else
formatter.format("\n%s: using network interface '%s' to any (ephemeral) port", bind_addr, nic_name);
return sb.toString();
}
void setBufferSizes() throws SocketException {
if(sock != null) {
setBufferSize(sock, ucast_send_buf_size, ucast_recv_buf_size);
if(ucast_send_buf_size <= 0)
ucast_send_buf_size=getBufferSize(sock, true);
if(ucast_recv_buf_size <= 0)
ucast_recv_buf_size=getBufferSize(sock, false);
}
if(mcast_sock != null) {
setBufferSize(mcast_sock, mcast_send_buf_size, mcast_recv_buf_size);
if(mcast_send_buf_size <= 0)
mcast_send_buf_size=getBufferSize(mcast_sock, true);
if(mcast_recv_buf_size <= 0)
mcast_recv_buf_size=getBufferSize(mcast_sock, false);
}
int max_size=Global.MAX_DATAGRAM_PACKET_SIZE + MSG_OVERHEAD;
if(sock != null) {
if(sock.getSendBufferSize() < max_size)
setCorrectSocketBufferSize(sock, sock.getSendBufferSize(), max_size, true, false);
if(sock.getReceiveBufferSize() < max_size)
setCorrectSocketBufferSize(sock, sock.getReceiveBufferSize(), max_size, false, false);
}
if(mcast_sock != null) {
if(mcast_sock.getSendBufferSize() < max_size)
setCorrectSocketBufferSize(mcast_sock, mcast_sock.getSendBufferSize(), max_size, true, true);
if(mcast_sock.getReceiveBufferSize() < max_size)
setCorrectSocketBufferSize(mcast_sock, mcast_sock.getReceiveBufferSize(), max_size, false, true);
}
}
protected void setBufferSize(DatagramSocket sock, int send_buf_size, int recv_buf_size) {
if(send_buf_size > 0) {
try {
sock.setSendBufferSize(send_buf_size);
int actual_size=sock.getSendBufferSize();
if(actual_size < send_buf_size && log.isWarnEnabled()) {
log.warn(Util.getMessage("IncorrectBufferSize"), "send", sock.getClass().getSimpleName(),
Util.printBytes(send_buf_size), Util.printBytes(actual_size));
}
}
catch(Throwable ex) {
log.warn(Util.getMessage("BufferSizeFailed"), "send", send_buf_size, sock, ex);
}
}
if(recv_buf_size > 0) {
try {
sock.setReceiveBufferSize(recv_buf_size);
int actual_size=sock.getReceiveBufferSize();
if(actual_size < recv_buf_size && log.isWarnEnabled()) {
log.warn(Util.getMessage("IncorrectBufferSize"), "receive", sock.getClass().getSimpleName(),
Util.printBytes(recv_buf_size), Util.printBytes(actual_size));
}
}
catch(Throwable ex){
log.warn(Util.getMessage("BufferSizeFailed"), "receive", recv_buf_size, sock, ex);
}
}
}
protected static int getBufferSize(DatagramSocket s, boolean send) {
try {
return send? s.getSendBufferSize() : s.getReceiveBufferSize();
}
catch(SocketException e) {
return 0;
}
}
void closeMulticastSocket() {
if(mcast_sock != null) {
try {
if(mcast_addr != null) {
SocketAddress addr=new InetSocketAddress(mcast_addr.getIpAddress(), mcast_addr.getPort());
mcast_sock.leaveGroup(addr, bind_addr == null? null : NetworkInterface.getByInetAddress(bind_addr));
}
getSocketFactory().close(mcast_sock); // this will cause the mcast receiver thread to break out of its loop
mcast_sock=null;
if(log.isDebugEnabled()) log.debug("%s: multicast socket closed", local_addr);
}
catch(IOException ignored) {
}
mcast_addr=null;
}
}
protected void closeUnicastSocket() {
getSocketFactory().close(sock);
}
protected void startThreads() throws Exception {
startUcastReceiverThreads();
startMcastReceiverThreads();
}
protected void startUcastReceiverThreads() {
if(ucast_receivers != null)
for(PacketReceiver r: ucast_receivers)
r.start();
}
protected void startMcastReceiverThreads() {
if(mcast_receivers != null)
for(PacketReceiver r: mcast_receivers)
r.start();
}
protected void stopThreads() {
stopMcastReceiverThreads();
stopUcastReceiverThreads();
}
protected void stopUcastReceiverThreads() {Util.close(ucast_receivers);}
protected void stopMcastReceiverThreads() {Util.close(mcast_receivers);}
protected void handleConfigEvent(Map map) throws SocketException {
boolean set_buffers=false;
if(map == null) return;
if(map.containsKey("send_buf_size")) {
mcast_send_buf_size=(Integer)map.get("send_buf_size");
ucast_send_buf_size=mcast_send_buf_size;
set_buffers=true;
}
if(map.containsKey("recv_buf_size")) {
mcast_recv_buf_size=(Integer)map.get("recv_buf_size");
ucast_recv_buf_size=mcast_recv_buf_size;
set_buffers=true;
}
if(set_buffers)
setBufferSizes();
}
/* ----------------------------- End of Private Methods ---------------------------------------- */
/* ----------------------------- Inner Classes ---------------------------------------- */
public class PacketReceiver implements Runnable, Closeable {
private Thread thread;
private final DatagramSocket receiver_socket;
private final String name;
public PacketReceiver(DatagramSocket socket, String name) {
this.receiver_socket=socket;
this.name=name;
}
public synchronized void start() {
if(thread == null || !thread.isAlive()) {
thread=getThreadFactory().newThread(this, name);
thread.start();
}
}
public void close() throws IOException {stop();}
public synchronized void stop() {
Thread tmp=thread;
thread=null;
if(tmp != null && tmp.isAlive()) {
tmp.interrupt();
try {
tmp.join(Global.THREAD_SHUTDOWN_WAIT_TIME);
}
catch(InterruptedException e) {
Thread.currentThread().interrupt(); // set interrupt flag again
}
}
}
public void run() {
final byte[] receive_buf=new byte[66000]; // to be on the safe side (IPv6 == 65575 bytes, IPv4 = 65535)
final DatagramPacket packet=new DatagramPacket(receive_buf, receive_buf.length);
while(Thread.currentThread().equals(thread)) {
try {
// solves Android ISSUE #24748 - DatagramPacket truncated UDP in ICS
if(is_android)
packet.setLength(receive_buf.length);
receiver_socket.receive(packet);
int len=packet.getLength();
if(len > receive_buf.length && log.isErrorEnabled())
log.error(Util.getMessage("SizeOfTheReceivedPacket"), len, receive_buf.length, receive_buf.length);
receive(new IpAddress(packet.getAddress(), packet.getPort()),
receive_buf, packet.getOffset(), len);
}
catch(SocketException sock_ex) {
if(receiver_socket.isClosed()) {
log.debug("%s: receiver socket is closed, exception=%s", local_addr, sock_ex.getMessage());
break;
}
log.error(Util.getMessage("FailedReceivingPacket"), sock_ex);
}
catch(Throwable ex) {
log.error(Util.getMessage("FailedReceivingPacket"), ex);
}
}
if(log.isDebugEnabled()) log.debug(name + " thread terminated");
}
public String toString() {
return receiver_socket != null? receiver_socket.getLocalSocketAddress().toString() : "null";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy