/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.apmrouter.byteman.sockets.impl;
import org.cliffc.high_scale_lib.Counter;
import org.cliffc.high_scale_lib.NonBlockingHashMap;
import org.cliffc.high_scale_lib.NonBlockingHashSet;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
/**
* <p>Title: ConnectionTracker</p>
* <p>Description: Lightweight {@link ISocketTracker} that tracks simple TCP connectivity between the instrumented host and its clients and other hosts it connects to</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.byteman.sockets.impl.ConnectionTracker</code></p>
*/
public class ConnectionTracker extends EmptySocketTracker implements Runnable {
/** The number of connections bound to a listening server socket */
protected final NonBlockingHashMap<SocketAddress, NonBlockingHashMap<SocketAddress, Counter>> serverListenerConnections = new NonBlockingHashMap<SocketAddress, NonBlockingHashMap<SocketAddress, Counter>>();
/** A hashset of server side sockets */
protected final NonBlockingHashSet<ISocketImpl> serverSideSockets = new NonBlockingHashSet<ISocketImpl>();
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.EmptySocketTracker#onConnect(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl, java.net.SocketAddress, int)
*/
@Override
public void onConnect(ISocketImpl socketImpl, SocketAddress address, int timeout) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.ISocketTracker#onConnect(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl, java.net.InetAddress, int)
*/
@Override
public void onConnect(ISocketImpl socketImpl, InetAddress address, int timeout) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.ISocketTracker#onConnect(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl, java.lang.String, int)
*/
@Override
public void onConnect(ISocketImpl socketImpl, String host, int port) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.ISocketTracker#onBind(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl, java.net.InetAddress, int)
*/
@Override
public void onBind(ISocketImpl socketImpl, InetAddress host, int port) {
serverListenerConnections.put(socketImpl.getServerSocket().getLocalSocketAddress(), new NonBlockingHashMap<SocketAddress, Counter>());
}
/**
* <p>Increments the count of connections from the remote host of the passed accepted socket to the passed server socket.</p>
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.EmptySocketTracker#onAccept(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl, org.helios.apmrouter.byteman.sockets.impl.ISocketImpl)
*/
@Override
public void onAccept(ISocketImpl socketImpl, ISocketImpl acceptedSocketImpl) {
serverSideSockets.add(acceptedSocketImpl);
SocketAddress sa = acceptedSocketImpl.getSocket().getRemoteSocketAddress();
NonBlockingHashMap<SocketAddress, Counter> clientSockMap = serverListenerConnections.get(socketImpl.getServerSocket().getLocalSocketAddress());
Counter counter = new Counter();
Counter tmpCounter = clientSockMap.get(sa);
if(tmpCounter!=null) {
counter = tmpCounter;
}
counter.increment();
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.ISocketTracker#onClose(org.helios.apmrouter.byteman.sockets.impl.ISocketImpl)
*/
@Override
public void onClose(ISocketImpl socketImpl) {
if(socketImpl.getServerSocket()!=null) {
onClose(socketImpl.getServerSocket());
} else {
Socket sock = socketImpl.getSocket();
SocketAddress remoteSocketAddress = sock.getRemoteSocketAddress();
SocketAddress localSocketAddress = sock.getLocalSocketAddress();
if(serverSideSockets.remove(socketImpl)) {
// the closed socket is a server side (accepted) socket
// decrement the connection count for the server socket
try {
serverListenerConnections.get(localSocketAddress).get(remoteSocketAddress).decrement();
} catch (NullPointerException npe) {
System.err.println("Failed to decrement for remote disconnect on [" + localSocketAddress + "]");
}
} else {
// the closed socket is a client socket
}
}
}
/**
* Called when a remote client socket closes
* @param socket the closed remote socket
*/
protected void onCloseRemote(Socket socket) {
// SocketAddress sa = socket.
// NonBlockingHashMap<SocketAddress, Counter> clientSockMap = serverListenerConnections.get(socketImpl.getServerSocket().getLocalSocketAddress());
// Counter counter = new Counter();
// Counter tmpCounter = clientSockMap.get(sa);
// if(tmpCounter!=null) {
// counter = tmpCounter;
// }
// counter.increment();
}
/**
* Called when a local client socket closes
* @param socket the closed local socket
*/
protected void onCloseLocal(Socket socket) {
}
/**
* Called when a formerly bound and listening server socket closes
* @param serverSocket the closed server socket
*/
protected void onClose(ServerSocket serverSocket) {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.ISocketTracker#requiresHarvester()
*/
@Override
public boolean requiresHarvester() {
return true;
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.EmptySocketTracker#harvest()
*/
@Override
protected void harvest() {
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.byteman.sockets.impl.EmptySocketTracker#hasJMXInterface()
*/
@Override
public boolean hasJMXInterface() {
return true;
}
}