/** * 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.helios.apmrouter.byteman.sockets.ServerConnection; import org.helios.apmrouter.util.SimpleLogger; import java.io.FileDescriptor; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.SocketAddress; import java.util.Iterator; import static org.helios.apmrouter.util.SimpleLogger.log; /** * <p>Title: LoggingSocketTracker</p> * <p>Description: A super simple {@link ISocketTracker} that logs all socket events.</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.byteman.sockets.impl.LoggingSocketTracker</code></p> */ public class LoggingSocketTracker extends EmptySocketTracker implements LoggingSocketTrackerMBean { /* * TODO: * Logging level * Tracked socket counts */ /** * Called when EOF is set on a socket * @param is the input stream * @param socket the socket * @param eof the eof value */ @Override public void onSetEOF(InputStream is, Object socket, boolean eof) { log(loggingLevel, "EOF [", eof, "]"); } /** * Called when bytes are skipped on the input stream of a socket * @param is The input stream * @param skipped the actual number of bytes to skip * @param socket the socket * @param skip the number of bytes to skip */ @Override public void onSkip(InputStream is, long skipped, Object socket, long skip) { log(loggingLevel, "Skipped [", skipped, "]"); } /** * Called when a write completes to a socket * @param os The output stream * @param socket The socket * @param b the data that was written * @param off the start offset in the data * @param len the number of bytes that were written */ @Override public void onSocketWrite(OutputStream os, Object socket, byte b[], int off, int len) { log(loggingLevel, "Socket Write [", len, "]"); //log(loggingLevel, "Socket Write Conent: [", new String(b), "]"); } /** * Called when data is read from a socket * @param is the input stream * @param actualBytesRead the actual number of bytes read, -1 is returned when the end of the stream is reached * @param socket the socket * @param buffer the buffer into which the data is read */ @Override public void onRead(InputStream is, int actualBytesRead, Object socket, byte[] buffer) { log(loggingLevel, "Socket Read [", actualBytesRead, "]"); } /** * Called when data is read from a socket * @param is the input stream * @param actualBytesRead the actual number of bytes read, -1 is returned when the end of the stream is reached * @param socket the socket * @param buffer the buffer into which the data is read * @param off the start offset of the data * @param length the maximum number of bytes read */ @Override public void onRead(InputStream is, int actualBytesRead, Object socket, byte[] buffer, int off, int length) { log(loggingLevel, "Socket Read [", actualBytesRead, "]"); } /** * Called when a byte is read from a socket * @param is the input stream * @param value the value read * @param socket the socket */ @Override public void onRead(InputStream is, int value, Object socket) { log(loggingLevel, "Socket Read [1]"); } /** * Called on a socket impl connect. This is the only <i>actual</i> connect execution. The overloads are redirected here. * @param socketImpl the socket impl that connected * @param address the socket address that the socket impl connected to * @param timeout the timeout used for connect */ @Override public void onConnect(ISocketImpl socketImpl, SocketAddress address, int timeout) { log(loggingLevel, "Connected (sa) [", socketImpl.getClass().getSimpleName() , ":", address, ":", timeout, "]"); } /** * Called on a socket impl connect * @param socketImpl the socket impl that connected * @param address the inet address that the socket impl connected to * @param timeout the timeout used for connect */ @Override public void onConnect(ISocketImpl socketImpl, InetAddress address, int timeout) { log(loggingLevel, "Connected (ia) [", address, ":", timeout, "]"); } /** * Called on a socket impl connect * @param socketImpl the socket impl that connected * @param host the host name that the socket impl connected to * @param port the port that the socket impl connected to */ @Override public void onConnect(ISocketImpl socketImpl, String host, int port) { log(loggingLevel, "Connected (ha) [", host, ":", port, "]"); } /** * Called when a socket impl binds to a socket * @param socketImpl the socket impl that was bound * @param host the host of the bound socket * @param port the port of the bound socket */ @Override public void onBind(ISocketImpl socketImpl, InetAddress host, int port) { log(loggingLevel, "Bind [", host, ":", port, "]"); ServerSocket ss = socketImpl.getServerSocket(); log(loggingLevel, "ServerSock: [", ss, "]"); } /** * Called when a socket impl has its backlog queue set * @param socketImpl the socket impl that had its backlog queue set * @param backlog the connection backlog */ @Override public void onListen(ISocketImpl socketImpl, int backlog) { log(loggingLevel, "Listen [", backlog, "]"); } /** * Called when a server socket impl accepts a new connection * @param socketImpl the socket impl that was accepted * @param acceptedSocketImpl the accepted client socket impl */ @Override public void onAccept(ISocketImpl socketImpl, ISocketImpl acceptedSocketImpl) { //serverSideSockets.add(acceptedSocketImpl); ServerConnection.registerInstance(acceptedSocketImpl); StringBuilder b = new StringBuilder("Accepted Socket [").append(System.identityHashCode(acceptedSocketImpl)).append("]"); b.append("\n\tAccepted:").append(acceptedSocketImpl); b.append("\n\tRemote Address:").append(acceptedSocketImpl.getInetAddress().getHostAddress()).append(":").append(acceptedSocketImpl.getPort()); b.append("\n\tLocal Address:").append(socketImpl.getInetAddress().getHostAddress()).append(":").append(socketImpl.getLocalPort()); // b.append("\n\tLocal Address:").append(acceptedSocketImpl.getSocket().getLocalSocketAddress()); // b.append("\n\tRemote Address:").append(acceptedSocketImpl.getSocket().getRemoteSocketAddress()); log(loggingLevel, b); } /** * Called when the input stream is requested from a socket impl * @param socketImpl the socket impl * @param inputStream the returned input stream */ @Override public void onGetInputStream(ISocketImpl socketImpl, InputStream inputStream) { StringBuilder b = new StringBuilder("InputStream Accessed [").append(System.identityHashCode(socketImpl)).append("]"); b.append("\n\tLocal Address:").append(socketImpl.getSocket().getLocalSocketAddress()); b.append("\n\tRemote Address:").append(socketImpl.getSocket().getRemoteSocketAddress()); log(loggingLevel, b); } /** * Called when the output stream is requested from a socket impl * @param socketImpl the socket impl * @param outputStream the returned output stream */ @Override public void onGetOutputStream(ISocketImpl socketImpl, OutputStream outputStream) { StringBuilder b = new StringBuilder("OutputStream Accessed [").append(System.identityHashCode(socketImpl)).append("]"); b.append("\n\tLocal Address:").append(socketImpl.getSocket().getLocalSocketAddress()); b.append("\n\tRemote Address:").append(socketImpl.getSocket().getRemoteSocketAddress()); log(loggingLevel, b); } /** * Called when the available bytes is requested from a socket impl * @param socketImpl the socket impl * @param available the available bytes returned */ @Override public void onAvailable(ISocketImpl socketImpl, int available) { log(loggingLevel, "Available [", available, "]"); } /** * Called when a socket impl is closed * @param socketImpl the socket impl */ @Override public void onClose(ISocketImpl socketImpl) { StringBuilder b = new StringBuilder("Closing ["); b.append(socketImpl.getClass().getSimpleName()).append("]"); if(socketImpl.getServerSocket()!=null) { b.append(": ServerSocket"); b.append("\n\tBound Address:").append(socketImpl.getServerSocket().getLocalSocketAddress()); } else { if(serverSideSockets.remove(socketImpl)) { b.append(": ServerSide Socket [" + System.identityHashCode(socketImpl) + "]"); } else { b.append(": ClientSocket [" + System.identityHashCode(socketImpl) + "]"); } b.append("\n\tLocal Address:").append(socketImpl.getSocket().getLocalSocketAddress()); b.append("\n\tRemote Address:").append(socketImpl.getSocket().getRemoteSocketAddress()); } log(loggingLevel, b); } /** * Called when input is shutdown on a socket impl * @param socketImpl the socket impl */ @Override public void onShutdownInput(ISocketImpl socketImpl) { log(loggingLevel, "ShutdownInput [", socketImpl, "]"); } /** * Called when output is shutdown on a socket impl * @param socketImpl the socket impl */ @Override public void onShutdownOutput(ISocketImpl socketImpl) { log(loggingLevel, "ShutdownOutput [", socketImpl, "]"); } /** * Called when urgent data is sent through a socket impl * @param socketImpl the socket impl * @param data the data that was sent */ @Override public void onSendUrgentData(ISocketImpl socketImpl, int data) { log(loggingLevel, "SendUrgentData [", data, "]"); } /** * Called when the client socket is set on a socket impl * @param socketImpl the socket impl * @param socket the set socket */ @Override public void onSetSocket(ISocketImpl socketImpl, Object socket) { log(loggingLevel, "SetSocket [", socket, "]"); } /** * Called when the server socket is set on a socket impl * @param socketImpl the socket impl * @param serverSocket The set server socket */ @Override public void onSetServerSocket(ISocketImpl socketImpl, Object serverSocket) { log(loggingLevel, "SetServerSocket [", serverSocket, "]"); } /** * Called when a socket impl is reset * @param socketImpl the socket impl */ @Override public void onReset(ISocketImpl socketImpl) { log(loggingLevel, "Reset [", socketImpl, "]"); } /** * Called when performance preferences are set on a socket impl * @param socketImpl the socket impl * @param connectionTime An <tt>int</tt> expressing the relative importance of a short connection time * @param latency An <tt>int</tt> expressing the relative importance of low latency * @param bandwidth An <tt>int</tt> expressing the relative importance of highbandwidth */ @Override public void onSetPerformancePreferences(ISocketImpl socketImpl, int connectionTime, int latency, int bandwidth) { log(loggingLevel, "SetPerformancePreferences [", connectionTime, ":", latency, ":", bandwidth, "]"); } /** * {@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() { if(serverSideSockets.isEmpty()) return; final long start = System.currentTimeMillis(); //SimpleLogger.log(loggingLevel, "[", getClass().getSimpleName(), "] Harvesting..."); final int startSize = serverSideSockets.size(); Iterator<ISocketImpl> socketIter = serverSideSockets.iterator(); int socketsClosed = 0; for(; socketIter.hasNext();) { ISocketImpl isocket = socketIter.next(); FileDescriptor fd = isocket.getFileDescriptor(); boolean fdValid = fd!=null && fd.valid(); if(fd!=null) { SimpleLogger.log(loggingLevel, "FD: [", fd, "]:" , fd.valid()); try { fd.sync(); } catch (Exception ex) {} } if(!fdValid || !testSocketStreams(isocket.getSocket())) { socketIter.remove(); socketsClosed++; try { isocket.close(); } catch (Exception ex) {} } } final int endSize = serverSideSockets.size(); final long elapsed = System.currentTimeMillis()-start; SimpleLogger.log(loggingLevel, "[", getClass().getSimpleName(), "] Harvester closed [", socketsClosed, "] accepted sockets. \n\tStartCount:", startSize, " \n\tEndCount:", endSize, "\n\tElapsed:", elapsed, " ms."); } /** * {@inheritDoc} * @see org.helios.apmrouter.byteman.sockets.impl.EmptySocketTracker#hasJMXInterface() */ @Override public boolean hasJMXInterface() { return true; } }