Skip to content
This repository

Classes to represent exit policy and servers. #77

Merged
merged 1 commit into from almost 2 years ago

2 participants

Nick Martindell Will
Nick Martindell
DaemonF commented May 24, 2012

Added Classes to represent a server's publicly avaliable details (eg. exit policy), its privately tracked performance stats and to decide
which server to use to connect to a given host and port.

Nick Martindell Added Classes to represent a server's publicly avaliable details (eg.
exit policy), its privately tracked performance stats and to decide
which server to use to connect to a given host and port.
628262e
Will willscott merged commit 8855642 into from May 24, 2012
Will willscott closed this May 24, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

May 24, 2012
Nick Martindell Added Classes to represent a server's publicly avaliable details (eg.
exit policy), its privately tracked performance stats and to decide
which server to use to connect to a given host and port.
628262e
This page is out of date. Refresh to see the latest.
53  oneswarm_f2f/src/edu/washington/cs/oneswarm/f2f/servicesharing/ServerExtendedInfo.java
... ...
@@ -0,0 +1,53 @@
  1
+package edu.washington.cs.oneswarm.f2f.servicesharing;
  2
+
  3
+import java.util.Date;
  4
+import java.util.Queue;
  5
+
  6
+public class ServerExtendedInfo extends ServerPublicInfo {
  7
+    // Measured in kilobytes (rounded)
  8
+    private Queue<Integer> bandwidthHistory; // Last 10 reported bandwidths
  9
+    private int avgBandwidth;
  10
+    private Queue<Integer> latencyHistory; // Last 10 reported latencies
  11
+    private int avgLatency;
  12
+
  13
+    private static final int HISTORY_LENGTH = 10;
  14
+
  15
+    public ServerExtendedInfo(String nickname, long id, int advertBandwidth, String[] exitPolicy,
  16
+            Date lastOutage, String version) {
  17
+        super(nickname, id, advertBandwidth, exitPolicy, lastOutage, version);
  18
+    }
  19
+
  20
+    public int compareTo(ServerPublicInfo other) {
  21
+        if (other instanceof ServerExtendedInfo) {
  22
+            return this.avgBandwidth - ((ServerExtendedInfo) other).avgBandwidth;
  23
+        }
  24
+        return super.compareTo(other);
  25
+    }
  26
+
  27
+    public void recordBandwidth(int kbps) {
  28
+        bandwidthHistory.add(kbps);
  29
+        avgBandwidth = averageIntQueue(bandwidthHistory);
  30
+    }
  31
+
  32
+    public void recordLatency(int ms) {
  33
+        latencyHistory.add(ms);
  34
+        avgLatency = averageIntQueue(latencyHistory);
  35
+    }
  36
+
  37
+    public int getAvgBandwidth() {
  38
+        return avgBandwidth;
  39
+    }
  40
+
  41
+    public int getAvgLatency() {
  42
+        return avgLatency;
  43
+    }
  44
+
  45
+    private int averageIntQueue(Queue<Integer> q) {
  46
+        while (q.size() > HISTORY_LENGTH)
  47
+            q.remove();
  48
+        int sum = 0;
  49
+        for (int i = 0; i < q.size(); i++)
  50
+            sum += q.remove();
  51
+        return sum / q.size();
  52
+    }
  53
+}
213  oneswarm_f2f/src/edu/washington/cs/oneswarm/f2f/servicesharing/ServerPublicInfo.java
... ...
@@ -0,0 +1,213 @@
  1
+package edu.washington.cs.oneswarm.f2f.servicesharing;
  2
+
  3
+import java.util.Date;
  4
+import java.util.LinkedList;
  5
+import java.util.List;
  6
+
  7
+public class ServerPublicInfo implements Comparable<ServerPublicInfo> {
  8
+    private String nickname;
  9
+    private long id;
  10
+    private int advertizedBandwith;
  11
+    private PolicyTree exitPolicy;
  12
+    private Date onlineSince;
  13
+    private String version;
  14
+
  15
+    public ServerPublicInfo(String nickname, long id, int advertBandwidth, String[] exitPolicy,
  16
+            Date lastOutage, String version) {
  17
+        this.nickname = nickname;
  18
+        this.id = id;
  19
+        this.advertizedBandwith = advertBandwidth;
  20
+        this.exitPolicy = new PolicyTree(exitPolicy);
  21
+        this.onlineSince = lastOutage;
  22
+        this.version = version;
  23
+    }
  24
+
  25
+    /**
  26
+     * Sets the exit policy of the server using Tor's notation.
  27
+     * 
  28
+     * The format is: (reject|accept) (domain|ip)[:port] with one policy per
  29
+     * line of the string.
  30
+     * 
  31
+     * EX: reject 66.146.193.31:* accept *:80
  32
+     * 
  33
+     * @param policy
  34
+     *            Tor style exit policy array
  35
+     */
  36
+    public void setExitPolicy(String[] policy) {
  37
+        exitPolicy = new PolicyTree(policy);
  38
+    }
  39
+
  40
+    public boolean allowsConnectionTo(String url, int port) {
  41
+        return exitPolicy.getPolicy(url, port);
  42
+    }
  43
+
  44
+    public int compareTo(ServerPublicInfo other) {
  45
+        return this.advertizedBandwith - other.advertizedBandwith;
  46
+    }
  47
+
  48
+    public String getNickname() {
  49
+        return nickname;
  50
+    }
  51
+
  52
+    public long getId() {
  53
+        return id;
  54
+    }
  55
+
  56
+    public int getAdvertizedBandwith() {
  57
+        return advertizedBandwith;
  58
+    }
  59
+
  60
+    public Date getOnlineSinceDate() {
  61
+        return onlineSince;
  62
+    }
  63
+
  64
+    public String getVersion() {
  65
+        return version;
  66
+    }
  67
+
  68
+    private enum PolicyValue {
  69
+        ACCEPT, REJECT
  70
+    }
  71
+
  72
+    private enum NodeType {
  73
+        DOMAIN, PORT
  74
+    }
  75
+
  76
+    private class PolicyTree {
  77
+        private PolicyNode root;
  78
+
  79
+        public PolicyTree(String[] policy) {
  80
+            root = new PolicyNode("");
  81
+            addPolicies(policy);
  82
+        }
  83
+
  84
+        public void addPolicies(String[] policyStrings) {
  85
+            for (int i = 0; i < policyStrings.length; i++)
  86
+                addPolicy(policyStrings[i]);
  87
+        }
  88
+
  89
+        public void addPolicy(String policyString) {
  90
+            policyString = policyString.toLowerCase();
  91
+            PolicyValue policy;
  92
+            int port;
  93
+
  94
+            String[] policyParts = policyString.split("[ :]");
  95
+
  96
+            switch (policyParts.length) {
  97
+            case 2:
  98
+                port = -1;
  99
+                break;
  100
+            case 3:
  101
+                port = policyParts[2].equals("*") ? -1 : Integer.parseInt(policyParts[2]);
  102
+                if (port < -1 || port > 65535)
  103
+                    throw new IllegalArgumentException("Improper Format - Port out of range.");
  104
+                break;
  105
+            default:
  106
+                throw new IllegalArgumentException(
  107
+                        "Improper Format - Should be (reject|accept) (domain|ip)[:port]");
  108
+            }
  109
+
  110
+            if (policyParts[0].equalsIgnoreCase("accept"))
  111
+                policy = PolicyValue.ACCEPT;
  112
+            else if (policyParts[0].equalsIgnoreCase("reject"))
  113
+                policy = PolicyValue.REJECT;
  114
+            else
  115
+                throw new IllegalArgumentException(
  116
+                        "Improper Format - First word is not (accept|reject)");
  117
+
  118
+            String[] urlParts = policyParts[1].split("\\.");
  119
+            root = addPolicy(urlParts, urlParts.length - 1, port, policy, root);
  120
+        }
  121
+
  122
+        private PolicyNode addPolicy(String[] url, int index, int port, PolicyValue policy,
  123
+                PolicyNode root) {
  124
+            if (index < 0) {
  125
+                root.children.add(new PolicyNode(port, policy));
  126
+            } else {
  127
+                PolicyNode child = root.lastInstanceOfUrlPart(url[index]);
  128
+                if (child == null)
  129
+                    child = root.add(new PolicyNode(url[index]));
  130
+                child = addPolicy(url, index - 1, port, policy, child);
  131
+            }
  132
+            return root;
  133
+        }
  134
+
  135
+        // Must be a specific url or ip, and a specific port
  136
+        public boolean getPolicy(String url, int port) {
  137
+            url = url.toLowerCase();
  138
+            String[] urlParts = url.split("\\.");
  139
+            PolicyValue policy = getPolicy(urlParts, urlParts.length - 1, port, root);
  140
+            if (PolicyValue.ACCEPT == policy)
  141
+                return true;
  142
+            return false;
  143
+        }
  144
+
  145
+        private PolicyValue getPolicy(String[] domain, int index, int port, PolicyNode root) {
  146
+            for (PolicyNode child : root.children) {
  147
+                if (index >= 0 && (child.domain.equals("*") || domain[index].equals(child.domain))) {
  148
+                    PolicyValue temp = getPolicy(domain, index - 1, port, child);
  149
+                    if (temp != null)
  150
+                        return temp;
  151
+                } else if (port == child.port || child.port == -1)
  152
+                    return child.policy;
  153
+            }
  154
+            return null;
  155
+        }
  156
+    }
  157
+
  158
+    class PolicyNode {
  159
+        /*
  160
+         * Either domainPart or port will be filled for each node. "*" is wild
  161
+         * card for domainPart, "" is unused field -1 means wild card for port,
  162
+         * -2 is unused field
  163
+         */
  164
+        String domain;
  165
+        int port;
  166
+        List<PolicyNode> children;
  167
+        PolicyValue policy;
  168
+        NodeType type;
  169
+
  170
+        // Constructs a domainPart node
  171
+        public PolicyNode(String domainPart) {
  172
+            this(domainPart, -2, null, NodeType.DOMAIN);
  173
+        }
  174
+
  175
+        // Constructs a port node
  176
+        public PolicyNode(int port, PolicyValue policy) {
  177
+            this("", port, policy, NodeType.PORT);
  178
+        }
  179
+
  180
+        private PolicyNode(String domainPart, int port, PolicyValue policy, NodeType type) {
  181
+            this.domain = domainPart;
  182
+            this.port = port;
  183
+            this.policy = policy;
  184
+            this.type = type;
  185
+            this.children = new LinkedList<PolicyNode>();
  186
+        }
  187
+
  188
+        public PolicyNode lastInstanceOfUrlPart(String urlPart) {
  189
+            if (!children.isEmpty() && children.get(children.size() - 1).domain.equals(urlPart))
  190
+                return children.get(children.size() - 1);
  191
+            return null;
  192
+        }
  193
+
  194
+        public PolicyNode lastInstanceOfPort(int port) {
  195
+            if (!children.isEmpty() && children.get(children.size() - 1).port == port)
  196
+                return children.get(children.size() - 1);
  197
+            return null;
  198
+        }
  199
+
  200
+        public PolicyNode add(PolicyNode node) {
  201
+            children.add(node);
  202
+            return node;
  203
+        }
  204
+
  205
+        public String toString() {
  206
+            String temp = "";
  207
+            temp += domain.isEmpty() ? "--" : domain;
  208
+            temp += ":";
  209
+            temp += port == -1 ? "*" : port == -2 ? "--" : port;
  210
+            return temp;
  211
+        }
  212
+    }
  213
+}
25  oneswarm_f2f/src/edu/washington/cs/oneswarm/f2f/servicesharing/UrlToServer.java
... ...
@@ -0,0 +1,25 @@
  1
+package edu.washington.cs.oneswarm.f2f.servicesharing;
  2
+
  3
+import java.util.Collections;
  4
+import java.util.List;
  5
+
  6
+public class UrlToServer {
  7
+    List<ServerPublicInfo> servers;
  8
+
  9
+    public UrlToServer(ServerPublicInfo[] servers) {
  10
+        for (ServerPublicInfo server : servers)
  11
+            addServer(server);
  12
+    }
  13
+
  14
+    public void addServer(ServerPublicInfo server) {
  15
+        servers.add(server);
  16
+        Collections.sort(servers);
  17
+    }
  18
+
  19
+    public ServerPublicInfo pickServer(String url, int port) {
  20
+        for (ServerPublicInfo server : servers)
  21
+            if (server.allowsConnectionTo(url, port))
  22
+                return server;
  23
+        return null;
  24
+    }
  25
+}
84  oneswarm_f2f/test/edu/washington/cs/oneswarm/f2f/servicesharing/ProxyPolicyTest.java
... ...
@@ -0,0 +1,84 @@
  1
+package edu.washington.cs.oneswarm.f2f.servicesharing;
  2
+
  3
+import static org.junit.Assert.*;
  4
+
  5
+import java.util.Date;
  6
+import java.util.logging.Logger;
  7
+
  8
+import org.junit.*;
  9
+
  10
+import edu.washington.cs.oneswarm.test.integration.ServiceSharingClientTest;
  11
+import edu.washington.cs.oneswarm.test.util.OneSwarmTestBase;
  12
+import edu.washington.cs.oneswarm.test.util.TestUtils;
  13
+
  14
+/**
  15
+ * Tests ServerPublicInfo, verifying that it correctly represents the policy of
  16
+ * the server it represents.
  17
+ * 
  18
+ * @author Nick
  19
+ * 
  20
+ */
  21
+public class ProxyPolicyTest extends OneSwarmTestBase {
  22
+
  23
+    private static Logger logger = Logger.getLogger(ServiceSharingClientTest.class.getName());
  24
+
  25
+    @Test
  26
+    public void testServerPublicInfo() throws Exception {
  27
+        /*
  28
+         * Verify that the exit policy passed to the ServerPublicInfo is
  29
+         * correctly represented in subsequent calls to 'allowsConnection(String
  30
+         * url, int port)'
  31
+         * 
  32
+         * Test plan: -Create a ServerPublicInfo with a complex exit policy
  33
+         * -Verify that the results match the set of manually predetermined
  34
+         * results for each case
  35
+         */
  36
+
  37
+        try {
  38
+            String[] policy = new String[] { "reject yahoo.com", "accept *:80",
  39
+                    "reject *.google.com:40", "accept google.com:40", "reject *.2.*.*:40",
  40
+                    "accept 4.*.2.2:40", "reject *:*" };
  41
+
  42
+            ServerPublicInfo server = new ServerPublicInfo("Servo The Magnificent", 123456789, 275,
  43
+                    policy, new Date(), "Version string 2.0");
  44
+
  45
+            // Sample Url's to test
  46
+            String[] urls = new String[] { "google.com", "yahoo.com", "maps.google.com", "4.2.2.2",
  47
+                    "4.5.2.2" };
  48
+
  49
+            // Sample ports to test
  50
+            int[] ports = new int[] { 80, 40 };
  51
+
  52
+            // First index is url, second index is port
  53
+            boolean[][] expected = new boolean[][] { { true, true }, { false, false },
  54
+                    { true, false }, { true, false }, { true, true } };
  55
+
  56
+            if (expected.length != urls.length || expected[0].length != ports.length)
  57
+                throw new Exception(
  58
+                        "Invalid test: Dimmensions of 'expected' does not match the number of urls or ports.");
  59
+
  60
+            for (int x = 0; x < urls.length; x++) {
  61
+                for (int y = 0; y < ports.length; y++) {
  62
+                    if (expected[x][y] != server.allowsConnectionTo(urls[x], ports[y])) {
  63
+                        throw new Exception("Reported result (" + expected[x][y]
  64
+                                + ") differs from expeceted result (" + !expected[x][y] + ") for "
  65
+                                + urls[x] + ":" + ports[y]);
  66
+                    }
  67
+                }
  68
+            }
  69
+
  70
+        } catch (Exception e) {
  71
+            e.printStackTrace();
  72
+            logger.severe(e.toString());
  73
+            fail();
  74
+        } finally {
  75
+            logger.info("End testServerPublicInfo()");
  76
+        }
  77
+    }
  78
+
  79
+    /** Boilerplate code for running as executable. */
  80
+    public static void main(String[] args) throws Exception {
  81
+        TestUtils.swtCompatibleTestRunner(ProxyPolicyTest.class);
  82
+    }
  83
+
  84
+}
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.