use of net.i2p.util.OrderedProperties in project i2p.i2p by i2p.
the class I2PSimpleSession method connect.
/**
* Connect to the router and establish a session. This call blocks until
* a session is granted.
*
* NOT threadsafe, do not call from multiple threads.
*
* @throws I2PSessionException if there is a configuration error or the router is
* not reachable
*/
@Override
public void connect() throws I2PSessionException {
changeState(State.OPENING);
boolean success = false;
try {
// protect w/ closeSocket()
synchronized (_stateLock) {
// If we are in the router JVM, connect using the interal queue
if (_context.isRouterContext()) {
// _socket and _writer remain null
InternalClientManager mgr = _context.internalClientManager();
if (mgr == null)
throw new I2PSessionException("Router is not ready for connections");
// the following may throw an I2PSessionException
_queue = mgr.connect();
_reader = new QueuedI2CPMessageReader(_queue, this);
_reader.startReading();
} else {
if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL))) {
try {
I2PSSLSocketFactory fact = new I2PSSLSocketFactory(_context, false, "certificates/i2cp");
_socket = fact.createSocket(_hostname, _portNum);
} catch (GeneralSecurityException gse) {
IOException ioe = new IOException("SSL Fail");
ioe.initCause(gse);
throw ioe;
}
} else {
_socket = new Socket(_hostname, _portNum);
}
_socket.setKeepAlive(true);
OutputStream out = _socket.getOutputStream();
out.write(I2PClient.PROTOCOL_BYTE);
out.flush();
_writer = new ClientWriterRunner(out, this);
_writer.startWriting();
InputStream in = new BufferedInputStream(_socket.getInputStream(), BUF_SIZE);
_reader = new I2CPMessageReader(in, this);
_reader.startReading();
}
}
// must be out of synch block for writer to get unblocked
if (!_context.isRouterContext()) {
Properties opts = getOptions();
// support the AuthMessage
if ((!opts.containsKey(PROP_USER)) && (!opts.containsKey(PROP_PW))) {
// auto-add auth if not set in the options
String configUser = _context.getProperty(PROP_USER);
String configPW = _context.getProperty(PROP_PW);
if (configUser != null && configPW != null) {
opts.setProperty(PROP_USER, configUser);
opts.setProperty(PROP_PW, configPW);
}
}
if (opts.containsKey(PROP_USER) && opts.containsKey(PROP_PW)) {
Properties auth = new OrderedProperties();
auth.setProperty(PROP_USER, opts.getProperty(PROP_USER));
auth.setProperty(PROP_PW, opts.getProperty(PROP_PW));
sendMessage_unchecked(new GetDateMessage(CoreVersion.VERSION, auth));
} else {
// we must now send a GetDate even in SimpleSession, or we won't know
// what version we are talking with and cannot use HostLookup
sendMessage_unchecked(new GetDateMessage(CoreVersion.VERSION));
}
waitForDate();
}
// we do not receive payload messages, so we do not need an AvailabilityNotifier
// ... or an Idle timer, or a VerifyUsage
success = true;
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix() + " simple session connected");
} catch (InterruptedException ie) {
throw new I2PSessionException("Interrupted", ie);
} catch (UnknownHostException uhe) {
throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe);
} catch (IOException ioe) {
// Generate the best error message as this will be logged
String msg;
if (_context.isRouterContext())
msg = "Failed internal router binding";
else if (SystemVersion.isAndroid() && Boolean.parseBoolean(getOptions().getProperty(PROP_DOMAIN_SOCKET)))
msg = "Failed to bind to the router";
else
msg = "Cannot connect to the router on " + _hostname + ':' + _portNum;
throw new I2PSessionException(getPrefix() + msg, ioe);
} finally {
changeState(success ? State.OPEN : State.CLOSED);
}
}
use of net.i2p.util.OrderedProperties in project i2p.i2p by i2p.
the class Daemon method update.
/**
* @param knownNames only non-null if router book is a text file
* @param publishedNS only non-null if we have a published address book
* @since 0.9.33 split out from above
*/
private static void update(NamingService router, Set<String> knownNames, NamingService publishedNS, AddressBook addressbook, Iterator<Map.Entry<String, HostTxtEntry>> iter, Log log) {
long start = System.currentTimeMillis();
int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
int deleted = 0;
while (iter.hasNext()) {
Map.Entry<String, HostTxtEntry> entry = iter.next();
total++;
// may be null for 'remove' entries
String key = entry.getKey();
boolean isKnown;
// NOT set for text file NamingService
Destination oldDest;
if (knownNames != null) {
oldDest = null;
isKnown = key != null ? knownNames.contains(key) : null;
} else {
oldDest = key != null ? router.lookup(key) : null;
isKnown = oldDest != null;
}
try {
HostTxtEntry he = entry.getValue();
Properties hprops = he.getProps();
boolean mustValidate = MUST_VALIDATE || hprops != null;
String action = hprops != null ? hprops.getProperty(HostTxtEntry.PROP_ACTION) : null;
if (key == null && !he.hasValidRemoveSig()) {
if (log != null) {
log.append("Bad signature of action " + action + " for key " + hprops.getProperty(HostTxtEntry.PROP_NAME) + ". From: " + addressbook.getLocation());
}
invalid++;
} else if (key != null && mustValidate && !he.hasValidSig()) {
if (log != null) {
log.append("Bad signature of action " + action + " for key " + key + ". From: " + addressbook.getLocation());
}
invalid++;
} else if (action != null || !isKnown) {
if (key != null && AddressBook.isValidKey(key)) {
Destination dest = new Destination(he.getDest());
Properties props = new OrderedProperties();
props.setProperty("s", addressbook.getLocation());
boolean allowExistingKeyInPublished = false;
if (mustValidate) {
// sig checked above
props.setProperty("v", "true");
}
if (hprops != null) {
// merge in all the received properties
for (Map.Entry<Object, Object> e : hprops.entrySet()) {
// Add prefix to indicate received property
props.setProperty(RCVD_PROP_PREFIX + e.getKey(), (String) e.getValue());
}
}
if (action != null) {
// Must handle isKnown in each case.
if (action.equals(HostTxtEntry.ACTION_ADDDEST)) {
// Add an alternate destination (new crypto) for existing hostname
// Requires new NamingService support if the key exists
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(dest)) {
// we knew it before, with the same dest
old++;
continue;
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
// TODO Requires NamingService support
// if (isTextFile), do we replace or not? check sigType.isAvailable()
boolean success = router.addDestination(key, dest, props);
if (log != null) {
if (success)
log.append("Additional address for " + key + " added to address book. From: " + addressbook.getLocation());
else
log.append("Failed to add additional address for " + key + " From: " + addressbook.getLocation());
}
// ditto
if (publishedNS != null) {
// FIXME this fails, no support in SFNS
success = publishedNS.addDestination(key, dest, props);
if (log != null && !success)
log.append("Add to published address book " + publishedNS.getName() + " failed for " + key);
}
nnew++;
continue;
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, he.getDest(), addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_ADDNAME)) {
// Add an alias for an existing hostname, same dest
if (isKnown) {
// could be same or different dest
old++;
continue;
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
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.contains(dest)) {
// checks out, so we'll add the new one
} else {
// mismatch, disallow
logMismatch(log, action, key, pod, he.getDest(), addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_ADDSUBDOMAIN)) {
// add a subdomain with verification
if (isKnown) {
old++;
continue;
}
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (polddest != null && poldname != null) {
// check for valid subdomain
if (!AddressBook.isValidKey(poldname) || key.indexOf('.' + poldname) <= 0) {
if (log != null)
log.append("Action: " + action + " failed because" + " old name " + poldname + " is invalid" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} 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);
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(dest)) {
// we already have the new dest
old++;
continue;
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
if (log != null) {
if (pod2.size() == 1)
log.append("Changing destination for " + key + ". From: " + addressbook.getLocation());
else
log.append("Replacing " + pod2.size() + " destinations for " + key + ". From: " + addressbook.getLocation());
}
allowExistingKeyInPublished = true;
props.setProperty("m", Long.toString(I2PAppContext.getGlobalContext().clock().now()));
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) {
// is this what we want?
if (isKnown) {
old++;
continue;
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
List<Destination> pod = router.lookupAll(poldname);
if (pod == null) {
// we didn't have the old name
} else if (pod.contains(dest)) {
// checks out, so we'll delete it
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname, dest);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " to be replaced with " + key + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " to be replaced with " + key + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, dest);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else {
// mismatch, disallow
logMismatch(log, action, key, pod, he.getDest(), addressbook);
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_REMOVE) || action.equals(HostTxtEntry.ACTION_REMOVEALL)) {
// w/o name=dest handled below
if (log != null)
log.append("Action: " + action + " with name=dest invalid" + ". From: " + addressbook.getLocation());
invalid++;
continue;
} else if (action.equals(HostTxtEntry.ACTION_UPDATE)) {
if (isKnown) {
allowExistingKeyInPublished = true;
props.setProperty("m", Long.toString(I2PAppContext.getGlobalContext().clock().now()));
}
} else {
if (log != null)
log.append("Action: " + action + " unrecognized" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
}
// action != null
boolean success = router.put(key, dest, props);
if (log != null) {
if (success)
log.append("New address " + key + " added to address book. From: " + addressbook.getLocation());
else
log.append("Save to naming service " + router + " failed for new key " + key);
}
// now update the published addressbook
if (publishedNS != null) {
if (allowExistingKeyInPublished)
success = publishedNS.put(key, dest, props);
else
success = publishedNS.putIfAbsent(key, dest, props);
if (log != null && !success) {
log.append("Save to published address book " + publishedNS.getName() + " failed for new key " + key);
}
}
if (knownNames != null) {
// keep track for later dup check
knownNames.add(key);
}
nnew++;
} else if (key == null) {
// isKnown is false
if (action != null) {
// Process commands. hprops is non-null.
if (action.equals(HostTxtEntry.ACTION_REMOVE)) {
// delete this entry
String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (polddest != null && poldname != null) {
Destination pod = new Destination(polddest);
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, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else if (pod2 != null) {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
} else {
old++;
}
} else {
logMissing(log, action, "delete", addressbook);
invalid++;
}
} else if (action.equals(HostTxtEntry.ACTION_REMOVEALL)) {
// delete all entries with this destination
String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
// oldname is optional, but nice because not all books support reverse lookup
if (polddest != null) {
Destination pod = new Destination(polddest);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (poldname != null) {
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else if (pod2 != null) {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
} else {
old++;
}
}
// reverse lookup, delete all
List<String> revs = router.reverseLookupAll(pod);
if (revs != null) {
for (String rev : revs) {
if (knownNames != null)
knownNames.remove(rev);
boolean success = router.remove(rev, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + rev + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + rev + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(rev, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + rev);
}
}
}
} else {
logMissing(log, action, "delete", addressbook);
invalid++;
}
} else {
if (log != null)
log.append("Action: " + action + " w/o name=dest unrecognized" + ". From: " + addressbook.getLocation());
invalid++;
}
continue;
} else {
if (log != null)
log.append("No action in command line" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
} else if (log != null) {
log.append("Bad hostname " + key + ". From: " + addressbook.getLocation());
invalid++;
}
/**
**
* } else if (false && DEBUG && log != null) {
* // lookup the conflict if we haven't yet (O(n**2) for text file)
* if (isTextFile)
* oldDest = router.lookup(key);
* if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
* log.append("Conflict for " + key + ". From: "
* + addressbook.getLocation()
* + ". Destination in remote address book is "
* + entry.getValue());
* conflict++;
* } else {
* old++;
* }
***
*/
} else {
old++;
}
} catch (DataFormatException dfe) {
if (log != null)
log.append("Invalid b64 for " + key + " From: " + addressbook.getLocation());
invalid++;
}
}
// entries
if (DEBUG && log != null && total > 0) {
log.append("Merge of " + addressbook.getLocation() + " into " + router + " took " + (System.currentTimeMillis() - start) + " ms with " + total + " total, " + nnew + " new, " + old + " old, " + deleted + " deleted, " + invalid + " invalid, " + conflict + " conflicts");
}
}
use of net.i2p.util.OrderedProperties in project i2p.i2p by i2p.
the class Config method reloadConfiguration.
/**
*/
public static synchronized void reloadConfiguration() {
// DEBUG level logging won't work here since we haven't loaded the config yet...
properties = new Properties();
InputStream iv = null;
try {
iv = Config.class.getResourceAsStream("/susimail.properties");
properties.load(iv);
} catch (IOException e) {
Debug.debug(Debug.ERROR, "Could not open WEB-INF/classes/susimail.properties (possibly in jar), reason: " + e);
} finally {
if (iv != null)
try {
iv.close();
} catch (IOException ioe) {
}
}
try {
File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
if (cfg.exists()) {
config = new OrderedProperties();
DataHelper.loadProps(config, cfg);
}
} catch (IOException e) {
Debug.debug(Debug.ERROR, "Could not open susimail.config, reason: " + e);
}
}
use of net.i2p.util.OrderedProperties in project i2p.i2p by i2p.
the class Config method saveConfiguration.
/**
* Saves the properties. A property not in newProps will be removed but
* will not override the default in the resource.
*
* @param newProps non-null WITHOUT the prefix
* @since 0.9.13
*/
public static synchronized void saveConfiguration(Properties newProps) throws IOException {
Properties toSave = new OrderedProperties();
for (Map.Entry<Object, Object> e : newProps.entrySet()) {
Object k = e.getKey();
if (configPrefix != null)
k = configPrefix + k;
toSave.put(k, e.getValue());
}
config = toSave;
File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config");
DataHelper.storeProps(toSave, cfg);
}
use of net.i2p.util.OrderedProperties in project i2p.i2p by i2p.
the class DataHelper method readProperties.
/**
* Read a mapping from the stream, as defined by the I2P data structure spec,
* and store it into a Properties object.
*
* A mapping is a set of key / value pairs. It starts with a 2 byte Integer (ala readLong(rawStream, 2))
* defining how many bytes make up the mapping. After that comes that many bytes making
* up a set of UTF-8 encoded characters. The characters are organized as key=value;.
* The key is a String (ala readString(rawStream)) unique as a key within the current
* mapping that does not include the UTF-8 characters '=' or ';'. After the key
* comes the literal UTF-8 character '='. After that comes a String (ala readString(rawStream))
* for the value. Finally after that comes the literal UTF-8 character ';'. This key=value;
* is repeated until there are no more bytes (not characters!) left as defined by the
* first two byte integer.
*
* As of 0.9.18, throws DataFormatException on duplicate key
*
* @param rawStream stream to read the mapping from
* @throws DataFormatException if the format is invalid
* @throws IOException if there is a problem reading the data
* @return an OrderedProperties
*/
public static Properties readProperties(InputStream rawStream) throws DataFormatException, IOException {
Properties props = new OrderedProperties();
readProperties(rawStream, props);
return props;
}
Aggregations