forked from I2P_Developers/i2p.i2p
2004-11-05 jrandom
* Bugfixes and unit tests for the SAM bridge to handle quoted message
parameters, verify proper operation after multiple session lifetimes,
as well as some synchronization problems.
* New properties method on the DataHelper class.
* Address a race on fast disconnecting clients
This commit is contained in:
@@ -46,7 +46,7 @@ public class SAMBridge implements Runnable {
|
||||
* app designated destination name to the base64 of the I2P formatted
|
||||
* destination keys (Destination+PrivateKey+SigningPrivateKey)
|
||||
*/
|
||||
private Map nameToPrivKeys = Collections.synchronizedMap(new HashMap(8));
|
||||
private Map nameToPrivKeys;
|
||||
|
||||
private boolean acceptConnections = true;
|
||||
|
||||
@@ -65,6 +65,7 @@ public class SAMBridge implements Runnable {
|
||||
*/
|
||||
public SAMBridge(String listenHost, int listenPort, Properties i2cpProps, String persistFile) {
|
||||
persistFilename = persistFile;
|
||||
nameToPrivKeys = new HashMap(8);
|
||||
loadKeys();
|
||||
try {
|
||||
if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
|
||||
@@ -93,16 +94,18 @@ public class SAMBridge implements Runnable {
|
||||
* @return null if the name does not exist, or if it is improperly formatted
|
||||
*/
|
||||
public Destination getDestination(String name) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(val);
|
||||
return d;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error retrieving the destination from " + name, dfe);
|
||||
nameToPrivKeys.remove(name);
|
||||
return null;
|
||||
synchronized (nameToPrivKeys) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(val);
|
||||
return d;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error retrieving the destination from " + name, dfe);
|
||||
nameToPrivKeys.remove(name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,9 +117,11 @@ public class SAMBridge implements Runnable {
|
||||
* @return null if the name does not exist, else the stream
|
||||
*/
|
||||
public String getKeystream(String name) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
return val;
|
||||
synchronized (nameToPrivKeys) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +129,9 @@ public class SAMBridge implements Runnable {
|
||||
*
|
||||
*/
|
||||
public void addKeystream(String name, String stream) {
|
||||
nameToPrivKeys.put(name, stream);
|
||||
synchronized (nameToPrivKeys) {
|
||||
nameToPrivKeys.put(name, stream);
|
||||
}
|
||||
storeKeys();
|
||||
}
|
||||
|
||||
@@ -132,49 +139,52 @@ public class SAMBridge implements Runnable {
|
||||
* Load up the keys from the persistFilename
|
||||
*
|
||||
*/
|
||||
private synchronized void loadKeys() {
|
||||
Map keys = new HashMap(16);
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(persistFilename);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
int eq = line.indexOf('=');
|
||||
String name = line.substring(0, eq);
|
||||
String privKeys = line.substring(eq+1);
|
||||
keys.put(name, privKeys);
|
||||
private void loadKeys() {
|
||||
synchronized (nameToPrivKeys) {
|
||||
nameToPrivKeys.clear();
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(persistFilename);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
int eq = line.indexOf('=');
|
||||
String name = line.substring(0, eq);
|
||||
String privKeys = line.substring(eq+1);
|
||||
nameToPrivKeys.put(name, privKeys);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Key file does not exist at " + persistFilename);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to read the keys from " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Key file does not exist at " + persistFilename);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to read the keys from " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
nameToPrivKeys = Collections.synchronizedMap(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current keys to disk in the location specified on creation
|
||||
*
|
||||
*/
|
||||
private synchronized void storeKeys() {
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(persistFilename);
|
||||
for (Iterator iter = nameToPrivKeys.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String privKeys = (String)nameToPrivKeys.get(name);
|
||||
out.write(name.getBytes());
|
||||
out.write('=');
|
||||
out.write(privKeys.getBytes());
|
||||
out.write('\n');
|
||||
private void storeKeys() {
|
||||
synchronized (nameToPrivKeys) {
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(persistFilename);
|
||||
for (Iterator iter = nameToPrivKeys.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String privKeys = (String)nameToPrivKeys.get(name);
|
||||
out.write(name.getBytes());
|
||||
out.write('=');
|
||||
out.write(privKeys.getBytes());
|
||||
out.write('\n');
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out the SAM keys to " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out the SAM keys to " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,9 +111,10 @@ public class SAMUtils {
|
||||
*/
|
||||
public static Properties parseParams(StringTokenizer tok) throws SAMException {
|
||||
int pos, nprops = 0, ntoks = tok.countTokens();
|
||||
String token, param, value;
|
||||
String token, param;
|
||||
Properties props = new Properties();
|
||||
|
||||
StringBuffer value = new StringBuffer();
|
||||
for (int i = 0; i < ntoks; ++i) {
|
||||
token = tok.nextToken();
|
||||
|
||||
@@ -123,9 +124,16 @@ public class SAMUtils {
|
||||
throw new SAMException("Bad formatting for param [" + token + "]");
|
||||
}
|
||||
param = token.substring(0, pos);
|
||||
value = token.substring(pos + 1);
|
||||
value.append(token.substring(pos+1));
|
||||
if (value.charAt(0) == '"') {
|
||||
while ( (i < ntoks) && (value.lastIndexOf("\"") <= 0) ) {
|
||||
value.append(' ').append(tok.nextToken());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
props.setProperty(param, value);
|
||||
props.setProperty(param, value.toString());
|
||||
value.setLength(0);
|
||||
nprops += 1;
|
||||
}
|
||||
|
||||
@@ -157,4 +165,19 @@ public class SAMUtils {
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
try {
|
||||
test("a=b c=d e=\"f g h\"");
|
||||
test("a=\"b c d\" e=\"f g h\" i=\"j\"");
|
||||
test("a=\"b c d\" e=f i=\"j\"");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
private static void test(String props) throws Exception {
|
||||
StringTokenizer tok = new StringTokenizer(props);
|
||||
Properties p = parseParams(tok);
|
||||
System.out.println(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
|
||||
msg = buf.toString("ISO-8859-1").trim();
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("New message received: " + msg);
|
||||
_log.debug("New message received: [" + msg + "]");
|
||||
}
|
||||
buf.reset();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user