Addressbook: Use new NamingService API methods in action handling

- Refactor HostTxtEntry to consolidate properties writing
- More HostTxtEntry tests
- Start of 'remove' entry handling
Blockfile: Cleanup unused code
- Add Iterable interface to SkipList
This commit is contained in:
zzz
2016-04-21 14:37:38 +00:00
parent 34e390909e
commit 4f262f6140
6 changed files with 159 additions and 197 deletions

View File

@ -254,10 +254,10 @@ public class Daemon {
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
Destination pod = router.lookup(poldname);
List<Destination> pod = router.lookupAll(poldname);
if (pod == null) {
// we didn't have the old one, so we'll add the new one
} else if (pod.equals(dest)) {
} else if (pod.contains(dest)) {
// checks out, so we'll add the new one
} else {
// mismatch, disallow
@ -297,10 +297,10 @@ public class Daemon {
continue;
}
Destination pod = new Destination(polddest);
Destination pod2 = router.lookup(poldname);
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 == null) {
// we didn't have the old name
} else if (pod.equals(pod2)) {
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
if (log != null)
@ -330,6 +330,8 @@ public class Daemon {
}
} else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) {
// change destination on an existing entry
// This removes all previous destinations under that hostname,
// is this what we want?
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
@ -369,20 +371,22 @@ public class Daemon {
}
} else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) {
// Delete old name, replace with new
// This removes all previous destinations under that hostname,
// is this what we want?
if (isKnown) {
old++;
continue;
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
Destination pod = router.lookup(poldname);
List<Destination> pod = router.lookupAll(poldname);
if (pod == null) {
// we didn't have the old name
} else if (pod.equals(dest)) {
} else if (pod.contains(dest)) {
// checks out, so we'll delete it
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname);
boolean success = router.remove(poldname, dest);
if (success)
deleted++;
if (log != null) {
@ -399,7 +403,7 @@ public class Daemon {
if (published != null) {
if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname);
success = publishedNS.remove(poldname, dest);
if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
}
@ -431,11 +435,11 @@ public class Daemon {
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (polddest != null && poldname != null) {
Destination pod = new Destination(polddest);
Destination pod2 = router.lookup(poldname);
if (pod.equals(pod2)) {
if (knownNames != null)
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null && pod2.size() == 1)
knownNames.remove(poldname);
boolean success = router.remove(poldname);
boolean success = router.remove(poldname, pod);
if (success)
deleted++;
if (log != null) {
@ -452,7 +456,7 @@ public class Daemon {
if (published != null) {
if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname);
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
}
@ -485,11 +489,11 @@ public class Daemon {
Destination pod = new Destination(polddest);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (poldname != null) {
Destination pod2 = router.lookup(poldname);
if (pod.equals(pod2)) {
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname);
boolean success = router.remove(poldname, pod);
if (success)
deleted++;
if (log != null) {
@ -506,7 +510,7 @@ public class Daemon {
if (published != null) {
if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname);
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
}
@ -530,12 +534,12 @@ public class Daemon {
break;
rev2 = rev;
// forward check in case hash collision or something
Destination fwd = router.lookup(rev);
if (!pod.equals(fwd))
List<Destination> fwd = router.lookupAll(rev);
if (!fwd.contains(pod))
break; // can't go around again, fail
if (knownNames != null)
knownNames.remove(rev);
boolean success = router.remove(rev);
boolean success = router.remove(rev, pod);
if (success)
deleted++;
if (log != null) {
@ -552,7 +556,7 @@ public class Daemon {
if (published != null) {
if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(rev);
success = publishedNS.remove(rev, pod);
if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + rev);
}

View File

@ -2,6 +2,8 @@ package net.i2p.addressbook;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import net.i2p.crypto.DSAEngine;
@ -17,8 +19,10 @@ import net.i2p.util.OrderedProperties;
import java.io.File;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import net.i2p.data.Base32;
import net.i2p.data.PrivateKeyFile;
import net.i2p.data.SigningPrivateKey;
import net.i2p.util.RandomSource;
/**
@ -97,7 +101,7 @@ class HostTxtEntry {
* @param line part after the #!
* @throws IllegalArgumentException on dup key and other errors
*/
private OrderedProperties parseProps(String line) throws IllegalArgumentException {
private static OrderedProperties parseProps(String line) throws IllegalArgumentException {
line = line.trim();
OrderedProperties rv = new OrderedProperties();
String[] entries = DataHelper.split(line, "#");
@ -115,28 +119,59 @@ class HostTxtEntry {
return rv;
}
/**
* Write as a standard line name=dest[#!k1=v1#k2=v2...]
* Includes newline.
*/
public void write(BufferedWriter out) throws IOException {
out.write(name);
out.write(KV_SEPARATOR);
out.write(dest);
if (props != null && props.size() > 0) {
writeProps(out, false, false);
out.newLine();
}
/**
* Write as a "remove" line #!olddest=dest#oldname=name#k1=v1#k2=v2...]
* Includes newline.
* Must have been constructed with non-null properties.
*/
public void writeRemove(BufferedWriter out) throws IOException {
if (props == null)
throw new IllegalStateException();
props.setProperty(PROP_OLDNAME, name);
props.setProperty(PROP_OLDDEST, dest);
writeProps(out, false, false);
out.newLine();
props.remove(PROP_OLDNAME);
props.remove(PROP_OLDDEST);
}
/**
* Write the props part (if any) only, without newline
*/
private void writeProps(Writer out, boolean omitSig, boolean omitOldSig) throws IOException {
if (props == null)
return;
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
String k = (String) e.getKey();
if (omitSig && k.equals(PROP_SIG))
continue;
if (omitOldSig && k.equals(PROP_OLDSIG))
continue;
if (started) {
out.write(PROP_SEPARATOR);
} else {
started = true;
out.write(PROPS_SEPARATOR);
}
String k = (String) e.getKey();
String v = (String) e.getValue();
out.write(k);
out.write(KV_SEPARATOR);
out.write(v);
}
}
out.newLine();
}
/**
* Verify with the dest public key using the "sig" property
@ -146,34 +181,19 @@ class HostTxtEntry {
return false;
if (!isValidated) {
isValidated = true;
StringBuilder buf = new StringBuilder(1024);
String sig = null;
StringWriter buf = new StringWriter(1024);
String sig = props.getProperty(PROP_SIG);
if (sig == null)
return false;
buf.append(name);
buf.append(KV_SEPARATOR);
buf.append(dest);
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
String k = (String) e.getKey();
String v = (String) e.getValue();
if (k.equals(PROP_SIG)) {
if (sig != null)
try {
writeProps(buf, true, false);
} catch (IOException ioe) {
// won't happen
return false;
sig = v;
// remove from the written data
continue;
}
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
}
if (sig == null)
return false;
byte[] sdata = Base64.decode(sig);
if (sdata == null)
return false;
@ -207,43 +227,20 @@ class HostTxtEntry {
boolean rv = false;
// don't cache result
if (true) {
StringBuilder buf = new StringBuilder(1024);
String sig = null;
String olddest = null;
StringWriter buf = new StringWriter(1024);
String sig = props.getProperty(PROP_OLDSIG);
String olddest = props.getProperty(PROP_OLDDEST);
if (sig == null || olddest == null)
return false;
buf.append(name);
buf.append(KV_SEPARATOR);
buf.append(dest);
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
String k = (String) e.getKey();
String v = (String) e.getValue();
if (k.equals(PROP_SIG)) {
continue;
}
if (k.equals(PROP_OLDSIG)) {
if (sig != null)
try {
writeProps(buf, true, true);
} catch (IOException ioe) {
// won't happen
return false;
sig = v;
// remove from the written data
continue;
}
if (k.equals(PROP_OLDDEST)) {
if (olddest != null)
return false;
olddest = v;
}
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
}
if (sig == null || olddest == null)
return false;
byte[] sdata = Base64.decode(sig);
if (sdata == null)
return false;
@ -309,25 +306,16 @@ class HostTxtEntry {
private void signIt(SigningPrivateKey spk, String sigprop) {
if (props == null)
throw new IllegalStateException();
StringBuilder buf = new StringBuilder(1024);
if (props.containsKey(sigprop))
throw new IllegalStateException();
StringWriter buf = new StringWriter(1024);
buf.append(name);
buf.append(KV_SEPARATOR);
buf.append(dest);
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
String k = (String) e.getKey();
String v = (String) e.getValue();
if (k.equals(sigprop))
throw new IllegalStateException();
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
try {
writeProps(buf, false, false);
} catch (IOException ioe) {
throw new IllegalStateException(ioe);
}
Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk);
if (s == null)
@ -336,34 +324,54 @@ class HostTxtEntry {
}
public static void main(String[] args) throws Exception {
int astart = 0;
if (args.length > 0 && args[0].equals("-i"))
astart++;
OrderedProperties props = new OrderedProperties();
for (int i = astart; i < args.length; i++) {
int eq = args[i].indexOf("=");
props.setProperty(args[i].substring(0, eq), args[i].substring(eq + 1));
}
props.setProperty("zzzz", "zzzzzzzzzzzzzzz");
// outer
File f = new File("tmp-eepPriv.dat");
PrivateKeyFile pkf = new PrivateKeyFile(f);
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
f.delete();
PrivateKeyFile pkf2;
if (astart != 0) {
// inner
File f2 = new File("tmp-eepPriv2.dat");
PrivateKeyFile pkf = new PrivateKeyFile(f);
PrivateKeyFile pkf2 = new PrivateKeyFile(f2);
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
pkf2 = new PrivateKeyFile(f2);
pkf2.createIfAbsent(SigType.DSA_SHA1);
OrderedProperties props = new OrderedProperties();
props.setProperty("c", "ccccccccccc");
props.setProperty("a", "aaaa");
f2.delete();
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
HostTxtEntry he = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), props);
} else {
pkf2 = null;
}
byte[] rand = new byte[5];
RandomSource.getInstance().nextBytes(rand);
String host = Base32.encode(rand) + ".i2p";
HostTxtEntry he = new HostTxtEntry(host, pkf.getDestination().toBase64(), props);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
out.write("Before signing:\n");
he.write(out);
out.flush();
//out.write("Before signing:\n");
//he.write(out);
//out.flush();
SigningPrivateKey priv = pkf.getSigningPrivKey();
if (astart != 0) {
SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
he.signInner(priv2);
out.write("After signing inner:\n");
he.write(out);
//out.write("After signing inner:\n");
//he.write(out);
}
he.sign(priv);
out.write("After signing:\n");
//out.write("After signing:\n");
he.write(out);
out.flush();
System.out.println("Orig has valid inner sig? " + he.hasValidInnerSig());
System.out.println("Orig has valid sig? " + he.hasValidSig());
if (astart > 0 && !he.hasValidInnerSig())
throw new IllegalStateException("Inner fail 1");
if (!he.hasValidSig())
throw new IllegalStateException("Outer fail 1");
// now create 2nd, read in
StringWriter sw = new StringWriter(1024);
BufferedWriter buf = new BufferedWriter(sw);
@ -371,10 +379,12 @@ class HostTxtEntry {
buf.flush();
String line = sw.toString();
line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
HostTxtEntry he2 = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), line);
System.out.println("Dupl. has valid inner sig? " + he2.hasValidInnerSig());
System.out.println("Dupl. has valid sig? " + he2.hasValidSig());
f.delete();
f2.delete();
HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line);
if (astart > 0 && !he2.hasValidInnerSig())
throw new IllegalStateException("Inner fail 2");
if (!he2.hasValidSig())
throw new IllegalStateException("Outer fail 2");
//out.write("Test passed\n");
//out.flush();
}
}

View File

@ -217,7 +217,10 @@ class HostTxtParser {
for (HostTxtEntry e : map.values()) {
System.out.println("Host: " + e.getName() +
"\nDest: " + e.getDest() +
"\nValid? " + e.hasValidSig());
"\nAction: " + (e.getProps() != null ? e.getProps().getProperty("action") : "(none)") +
"\nValid Inner? " + e.hasValidInnerSig() +
"\nValid? " + e.hasValidSig() +
'\n');
}
}

View File

@ -206,6 +206,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V
return new IBSkipIterator<K, V>(first, 0);
}
/****
@Override
public SkipIterator<K, V> min() {
return iterator();
@ -218,6 +219,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V
SkipSpan<K, V> ss = stack.getEnd();
return new IBSkipIterator<K, V>(ss, ss.nKeys - 1);
}
****/
@Override
public SkipIterator<K, V> find(K key) {

View File

@ -1,59 +0,0 @@
/*
Copyright (c) 2006, Matthew Estes
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Metanotion Software nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.io.data;
import net.metanotion.io.Serializer;
public class LongBytes implements Serializer<Long> {
public byte[] getBytes(Long o) {
byte[] b = new byte[8];
long v = o.longValue();
b[0] = (byte)(0xff & (v >> 56));
b[1] = (byte)(0xff & (v >> 48));
b[2] = (byte)(0xff & (v >> 40));
b[3] = (byte)(0xff & (v >> 32));
b[4] = (byte)(0xff & (v >> 24));
b[5] = (byte)(0xff & (v >> 16));
b[6] = (byte)(0xff & (v >> 8));
b[7] = (byte)(0xff & v);
return b;
}
public Long construct(byte[] b) {
long v =(((long)(b[0] & 0xff) << 56) |
((long)(b[1] & 0xff) << 48) |
((long)(b[2] & 0xff) << 40) |
((long)(b[3] & 0xff) << 32) |
((long)(b[4] & 0xff) << 24) |
((long)(b[5] & 0xff) << 16) |
((long)(b[6] & 0xff) << 8) |
(b[7] & 0xff));
return Long.valueOf(v);
}
}

View File

@ -35,7 +35,7 @@ import net.i2p.util.RandomSource;
//import net.metanotion.io.block.BlockFile;
public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
public class SkipList<K extends Comparable<? super K>, V> implements Flushable, Iterable<V> {
/** the probability of each next higher level */
protected static final int P = 2;
private static final int MIN_SLOTS = 4;
@ -151,6 +151,7 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
* dumps all the data
* @deprecated goes to System.out
*/
@Deprecated
public void print() {
System.out.println("List size " + size);
System.out.println(first.print());
@ -163,12 +164,14 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); }
/****
public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); }
public SkipIterator<K, V> max() {
SkipSpan<K, V> ss = stack.getEnd();
return new SkipIterator<K, V>(ss, ss.nKeys - 1);
}
****/
/** @return an iterator where nextKey() is the first one greater than or equal to 'key' */
public SkipIterator<K, V> find(K key) {
@ -178,7 +181,6 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
return new SkipIterator<K, V>(ss, search[0]);
}
// Levels adjusted to guarantee O(log n) search
// This is expensive proportional to the number of spans.
public void balance() {