package net.hyperic.sigar;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.File;
import java.io.FileReader;

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

public class NetPortMap {

    private static final String SERVICE_FILE;

    private static Map udpServices = null;
    private static Map tcpServices = null;

    static {
        if (SigarLoader.IS_WIN32) {
            SERVICE_FILE = "C:\\windows\\system32\\drivers\\etc\\services";
        }
        else {
            SERVICE_FILE = "/etc/services";
        }
    }

    private static void parseServices(String type, Map services) {
        File file = new File(SERVICE_FILE);
        if (!file.exists()) {
            return;
        }

        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = reader.readLine()) != null) {
                String name, protocol;
                Long port;

                line = line.trim();
                if ((line.length() == 0) || (line.charAt(0) == '#')) {
                    continue;
                }

                StringTokenizer st = new StringTokenizer(line, " \t/#");
                if (st.countTokens() < 3) {
                    continue;
                }
                name = st.nextToken().trim();
                String pnum = st.nextToken().trim();
                protocol = st.nextToken().trim();
                if (!type.equals(protocol)) {
                    continue;
                }
                services.put(Long.valueOf(pnum), name);
            }
        } catch (IOException e) {
            return;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) { }
            }
        }
    }

    public static String getServiceName(String protocol, long port) {
        if (protocol.equals("tcp")) {
            return getTcpServiceName(port);
        }
        else if (protocol.equals("udp")) {
            return getUdpServiceName(port);
        }
        else {
            return String.valueOf(port);
        }
    }

    public static String getTcpServiceName(long port) {
        if (tcpServices == null) {
            tcpServices = new HashMap();
            parseServices("tcp", tcpServices);
        }
        return (String)tcpServices.get(new Long(port));
    }

    public static String getUdpServiceName(long port) {
        if (udpServices == null) {
            udpServices = new HashMap();
            parseServices("udp", udpServices);
        }
        return (String)udpServices.get(new Long(port));
    }

    /**
     * Map listening tcp ports to connected remote addresses.
     * key == Listening tcp port on the local machine.
     * value == List of connected remote addresses.
     */
    public static Map getTcpConnections(Sigar sigar)
        throws SigarException {

        int flags =
            NetFlags.CONN_SERVER | NetFlags.CONN_TCP;

        Map map = new HashMap();

        NetConnection[] connections =
            sigar.getNetConnectionList(flags);

        //first pass, get listening port numbers
        for (int i=0; i<connections.length; i++) {
            NetConnection conn = connections[i];
            Long port = new Long(conn.getLocalPort());
            List addresses = (List)map.get(port);

            if (addresses == null) {
                addresses = new ArrayList();
                map.put(port, addresses);
            }
        }

        //second pass, get addresses connected to listening ports
        flags = NetFlags.CONN_CLIENT | NetFlags.CONN_TCP;
        connections = sigar.getNetConnectionList(flags);

        for (int i=0; i<connections.length; i++) {
            NetConnection conn = connections[i];
            Long port = new Long(conn.getLocalPort());
            List addresses = (List)map.get(port);

            if (addresses == null) {
                continue;
            }

            addresses.add(conn.getRemoteAddress());
        }

        return map;
    }

    public static void main(String[] args) throws Exception {
        Sigar sigar = new Sigar();
        Map ports = getTcpConnections(sigar);

        for (Iterator it = ports.entrySet().iterator();
             it.hasNext();)
        {
            Map.Entry entry = (Map.Entry)it.next();
            Long port = (Long)entry.getKey();
            List addresses = (List)entry.getValue();
            System.out.println(port + "=" + addresses);
        }
    }
}

@@ -658,24 +658,231 @@
    %7D%0A    %7D%0A%0A
+    public static class IpEntry %7B%0A        int count;%0A%0A        IpEntry() %7B%0A            this.count = 0;%0A        %7D%0A%0A        public String toString() %7B%0A            return %22count:%22 + this.count;%0A        %7D%0A    %7D%0A%0A
     private 
@@ -3691,36 +3691,35 @@
 ));%0A            
-List
+Map
  addresses = (Li
@@ -3708,36 +3708,35 @@
 ap addresses = (
-List
+Map
 )map.get(port);%0A
@@ -3805,25 +3805,23 @@
 s = new 
-ArrayList
+HashMap
 ();%0A    
@@ -4055,32 +4055,69 @@
 tionList(flags);
+%0A        IpEntry key = new IpEntry();
 %0A%0A        for (i
@@ -4261,36 +4261,35 @@
 ));%0A            
-List
+Map
  addresses = (Li
@@ -4286,20 +4286,19 @@
 sses = (
-List
+Map
 )map.get
@@ -4400,22 +4400,20 @@
     
-addresses.add(
+String ip = 
 conn
@@ -4431,17 +4431,227 @@
 ddress()
-)
+;%0A            IpEntry entry = (IpEntry)addresses.get(ip);%0A            if (entry == null) %7B%0A                entry = new IpEntry();%0A                addresses.put(ip, entry);%0A            %7D%0A            entry.count++
 ;%0A      
@@ -5030,20 +5030,19 @@
         
-List
+Map
  address
@@ -5047,20 +5047,19 @@
 sses = (
-List
+Map
 )entry.g

use Map rather than List to keep track of addresses