/* This file is part of GNUnet. (C) 2012, 2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gnunet.gns; import org.gnunet.gns.messages.ClientLookupMessage; import org.gnunet.gns.messages.ClientLookupResultMessage; import org.gnunet.requests.FixedMessageRequest; import org.gnunet.requests.MatchingRequestContainer; import org.gnunet.requests.RequestIdentifier; import org.gnunet.util.*; import org.gnunet.util.crypto.EcdsaPrivateKey; import org.gnunet.util.crypto.EcdsaPublicKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * API to the GNUnet name system. */ public class Gns { private static final Logger logger = LoggerFactory .getLogger(Gns.class); /** * Defaults, look in cache, then in DHT. */ public static final int LOOKUP_OPTION_DEFAULT = 0; /** * Never look in the DHT, keep request to local cache. */ public static final int LOOKUP_OPTION_NO_DHT = 1; /** * For the rightmost label, only look in the cache (it * is our master zone), for the others, the DHT is OK. */ public static final int LOOKUP_OPTION_LOCAL_MASTER = 2; /** * All pending and active lookup requests. */ private MatchingRequestContainer> lookupRequests; /** * Request ID for lookup requests. */ private long nextUID = 1; /** * Client connected to the GNS service. */ private Client client; private RelativeTime reconnectBackoff = RelativeTime.STD_BACKOFF; public class GNSMessageReceiver extends RunaboutMessageReceiver { public void visit(ClientLookupResultMessage m) { RequestIdentifier> r = lookupRequests.getRequestIdentifier(m.id); if (null == r) { logger.warn("no matching getRequestIdentifier for lookup result"); return; } r.getRequest().getContext().process(m.records); } @Override public void handleError() { logger.warn("Error receiving from GNS service, reconnecting."); Scheduler.addDelayed(reconnectBackoff, new Scheduler.Task() { @Override public void run(Scheduler.RunContext ctx) { client.reconnect(); // re-send active requests lookupRequests.restart(); } }); reconnectBackoff = reconnectBackoff.backoff(); } } /** * Connect to the GNS service * * @param cfg configuration to use */ public Gns(Configuration cfg) { client = new Client("gns", cfg); lookupRequests = new MatchingRequestContainer>(client); client.installReceiver(new GNSMessageReceiver()); } /** * Perform an asynchronous lookup operation on the GNS. * * @param name the name to look up * @param zone zone to look in * @param type the GNS record type to look for * @param lookupOption a Gns.LOOKUP_OPTION_* value * @param shortenZoneKey the private key of the shorten zone (can be NULL); * specify to enable automatic shortening (given a PSEU * record, if a given pseudonym is not yet used in the * shorten zone, we automatically add the respective zone * under that name) * @param proc function to call on result * @return handle to the queued getRequestIdentifier */ public Cancelable lookup(String name, EcdsaPublicKey zone, long type, int lookupOption, EcdsaPrivateKey shortenZoneKey, LookupResultProcessor proc) { ClientLookupMessage m = new ClientLookupMessage(); if (null != shortenZoneKey) { m.haveKey = 1; m.shortenKey = shortenZoneKey; } else { m.haveKey = 0; m.shortenKey = EcdsaPrivateKey.zeroKey(); } m.id = nextUID++; m.name = name; m.onlyCached = lookupOption; m.type = type; m.zone = zone; return lookupRequests.addRequest(m.id, new FixedMessageRequest(m, proc)); } /** * Disconnect from the GNS service. */ public void disconnect() { client.disconnect(); client = null; } }