From nextgens at freenetproject.org Thu Mar 1 01:11:40 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Thu, 1 Mar 2007 01:11:40 +0000 (UTC) Subject: [freenet-cvs] r11937 - trunk/freenet/src/freenet/client/async Message-ID: <20070301011140.C02609BFBA@emu.freenetproject.org> Author: nextgens Date: 2007-03-01 01:11:39 +0000 (Thu, 01 Mar 2007) New Revision: 11937 Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java Log: constant should be before Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java =================================================================== --- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-02-28 22:51:25 UTC (rev 11936) +++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:11:39 UTC (rev 11937) @@ -264,9 +264,9 @@ short fuzz = -1, iteration = 0; synchronized (this) { - if(choosenPriorityScheduler.equals(PRIORITY_SOFT)) + if(PRIORITY_SOFT.equals(choosenPriorityScheduler)) fuzz = -1; - else if(choosenPriorityScheduler.equals(PRIORITY_HARD)) + else if(PRIORITY_HARD.equals(choosenPriorityScheduler)) fuzz = 0; } // we loop to ensure we try every possibilities ( n + 1) From nextgens at freenetproject.org Thu Mar 1 01:13:49 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Thu, 1 Mar 2007 01:13:49 +0000 (UTC) Subject: [freenet-cvs] r11938 - trunk/freenet/src/freenet/client/async Message-ID: <20070301011349.4915B9BCF9@emu.freenetproject.org> Author: nextgens Date: 2007-03-01 01:13:48 +0000 (Thu, 01 Mar 2007) New Revision: 11938 Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java Log: clarify a log message, refactor a bit Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java =================================================================== --- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:11:39 UTC (rev 11937) +++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:13:48 UTC (rev 11938) @@ -259,10 +259,10 @@ return Math.max(0, retryCount-MIN_RETRY_COUNT); } - private int removeFirstAccordingToPriorities(int priority){ + private int removeFirstAccordingToPriorities(){ SortedVectorByNumber result = null; - short fuzz = -1, iteration = 0; + short fuzz = -1, iteration = 0, priority; synchronized (this) { if(PRIORITY_SOFT.equals(choosenPriorityScheduler)) fuzz = -1; @@ -292,11 +292,10 @@ public SendableRequest removeFirst() { // Priorities start at 0 if(logMINOR) Logger.minor(this, "removeFirst()"); - int choosenPriorityClass = Integer.MAX_VALUE; - choosenPriorityClass = removeFirstAccordingToPriorities(choosenPriorityClass); + int choosenPriorityClass = removeFirstAccordingToPriorities(); if(choosenPriorityClass == -1) { if(logMINOR) - Logger.minor(this, "No priority with requests"); + Logger.minor(this, "Nothing to do"); return null; } SortedVectorByNumber s = priorities[choosenPriorityClass]; From nextgens at freenetproject.org Thu Mar 1 01:18:37 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Thu, 1 Mar 2007 01:18:37 +0000 (UTC) Subject: [freenet-cvs] r11939 - trunk/freenet/src/freenet/client/async Message-ID: <20070301011837.E4E589BCF9@emu.freenetproject.org> Author: nextgens Date: 2007-03-01 01:18:36 +0000 (Thu, 01 Mar 2007) New Revision: 11939 Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java Log: change the logging level of a few things Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java =================================================================== --- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:13:48 UTC (rev 11938) +++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:18:36 UTC (rev 11939) @@ -322,11 +322,11 @@ } else if(req.getPriorityClass() != choosenPriorityClass) { // Reinsert it : shouldn't happen if we are calling reregisterAll, // maybe we should ask people to report that error if seen - if(logMINOR) Logger.minor(this, "In wrong priority class: "+req+" (req.prio="+req.getPriorityClass()+" but chosen="+choosenPriorityClass+ ')'); + Logger.normal(this, "In wrong priority class: "+req+" (req.prio="+req.getPriorityClass()+" but chosen="+choosenPriorityClass+ ')'); innerRegister(req); continue; } - if(logMINOR) Logger.minor(this, "removeFirst() returning "+req+" ("+rga.getNumber()+", prio "+ + if(logMINOR) Logger.debug(this, "removeFirst() returning "+req+" ("+rga.getNumber()+", prio "+ req.getPriorityClass()+", retries "+req.getRetryCount()+", client "+req.getClient()+", client-req "+req.getClientRequest()+ ')'); ClientRequester cr = req.getClientRequest(); if(req.canRemove()) { From nextgens at freenetproject.org Thu Mar 1 01:20:17 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Thu, 1 Mar 2007 01:20:17 +0000 (UTC) Subject: [freenet-cvs] r11940 - trunk/freenet/src/freenet/client/async Message-ID: <20070301012017.B35829BCF9@emu.freenetproject.org> Author: nextgens Date: 2007-03-01 01:20:15 +0000 (Thu, 01 Mar 2007) New Revision: 11940 Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java Log: doh Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java =================================================================== --- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:18:36 UTC (rev 11939) +++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java 2007-03-01 01:20:15 UTC (rev 11940) @@ -91,7 +91,7 @@ private static final int MIN_RETRY_COUNT = 3; private String choosenPriorityScheduler; - private final int[] tweakedPrioritySelector = { + private final short[] tweakedPrioritySelector = { RequestStarter.MAXIMUM_PRIORITY_CLASS, RequestStarter.MAXIMUM_PRIORITY_CLASS, RequestStarter.MAXIMUM_PRIORITY_CLASS, @@ -127,7 +127,7 @@ RequestStarter.MINIMUM_PRIORITY_CLASS }; - private final int[] prioritySelector = { + private final short[] prioritySelector = { RequestStarter.MAXIMUM_PRIORITY_CLASS, RequestStarter.INTERACTIVE_PRIORITY_CLASS, RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS, From zothar at freenetproject.org Thu Mar 1 13:15:40 2007 From: zothar at freenetproject.org (zothar at freenetproject.org) Date: Thu, 1 Mar 2007 13:15:40 +0000 (UTC) Subject: [freenet-cvs] r11941 - trunk/freenet/src/freenet/io/comm Message-ID: <20070301131540.8AEC09BB7E@emu.freenetproject.org> Author: zothar Date: 2007-03-01 13:15:39 +0000 (Thu, 01 Mar 2007) New Revision: 11941 Modified: trunk/freenet/src/freenet/io/comm/UdpSocketManager.java Log: UdpSocketManager: Increase the threshold before error log level on some messages and reduce the log level of other messages to minor. Fix an if(logMINOR) there as well. Modified: trunk/freenet/src/freenet/io/comm/UdpSocketManager.java =================================================================== --- trunk/freenet/src/freenet/io/comm/UdpSocketManager.java 2007-03-01 01:20:15 UTC (rev 11940) +++ trunk/freenet/src/freenet/io/comm/UdpSocketManager.java 2007-03-01 13:15:39 UTC (rev 11941) @@ -231,10 +231,10 @@ Peer peer = new Peer(packet.getAddress(), packet.getPort()); long endTime = System.currentTimeMillis(); if(endTime - startTime > 50) { - if(endTime-startTime > 500) + if(endTime-startTime > 3000) Logger.error(this, "packet creation took "+(endTime-startTime)+"ms"); else - Logger.normal(this, "packet creation took "+(endTime-startTime)+"ms"); + if(logMINOR) Logger.minor(this, "packet creation took "+(endTime-startTime)+"ms"); } byte[] data = packet.getData(); int offset = packet.getOffset(); @@ -246,10 +246,10 @@ lowLevelFilter.process(data, offset, length, peer); endTime = System.currentTimeMillis(); if(endTime - startTime > 50) { - if(endTime-startTime > 500) + if(endTime-startTime > 3000) Logger.error(this, "processing packet took "+(endTime-startTime)+"ms"); else - Logger.normal(this, "processing packet took "+(endTime-startTime)+"ms"); + if(logMINOR) Logger.minor(this, "processing packet took "+(endTime-startTime)+"ms"); } if(logMINOR) Logger.minor(this, "Successfully handled packet length " + length); @@ -324,10 +324,10 @@ } long tEnd = System.currentTimeMillis(); if(tEnd - tStart > 50) { - if(tEnd - tStart > 500) + if(tEnd - tStart > 3000) Logger.error(this, "removeTimedOutFilters took "+(tEnd-tStart)+"ms"); else - Logger.normal(this, "removeTimedOutFilters took "+(tEnd-tStart)+"ms"); + if(logMINOR) Logger.minor(this, "removeTimedOutFilters took "+(tEnd-tStart)+"ms"); } } @@ -349,7 +349,7 @@ Logger.debug(this, "" + (System.currentTimeMillis() % 60000) + ' ' + _sock.getLocalPort() + " <- " + m.getSource() + " : " + m); } else { - Logger.minor(this, "" + (System.currentTimeMillis() % 60000) + ' ' + _sock.getLocalPort() + " <- " + if(logMINOR) Logger.minor(this, "" + (System.currentTimeMillis() % 60000) + ' ' + _sock.getLocalPort() + " <- " + m.getSource() + " : " + m); } } @@ -433,10 +433,10 @@ } long tEnd = System.currentTimeMillis(); if(tEnd - tStart > 50) { - if(tEnd - tStart > 500) + if(tEnd - tStart > 3000) Logger.error(this, "checkFilters took "+(tEnd-tStart)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for matched: "+matched); else - Logger.normal(this, "checkFilters took "+(tEnd-tStart)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for matched: "+matched); + if(logMINOR) Logger.minor(this, "checkFilters took "+(tEnd-tStart)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for matched: "+matched); } } @@ -513,10 +513,10 @@ } long tEnd = System.currentTimeMillis(); if(tEnd - now > 50) { - if(tEnd - now > 500) + if(tEnd - now > 3000) Logger.error(this, "waitFor _unclaimed iteration took "+(tEnd-now)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for ret of "+ret); else - Logger.normal(this, "waitFor _unclaimed iteration took "+(tEnd-now)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for ret of "+ret); + if(logMINOR) Logger.minor(this, "waitFor _unclaimed iteration took "+(tEnd-now)+"ms with unclaimedFIFOSize of "+_unclaimed.size()+" for ret of "+ret); } // Unlock to wait on filter // Waiting on the filter won't release the outer lock From nextgens at freenetproject.org Sat Mar 3 16:44:40 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 16:44:40 +0000 (UTC) Subject: [freenet-cvs] r11943 - trunk/freenet/src/freenet/config Message-ID: <20070303164440.62C919BC2F@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 16:44:39 +0000 (Sat, 03 Mar 2007) New Revision: 11943 Modified: trunk/freenet/src/freenet/config/LongOption.java Log: Throw an InvalidConfigValueException if LongOption.setValue can't parse the long ... it prevents the node from starting at all if the config. file has been badly hand-edited and won't lead to loosing other parts of it (like plugins and bookmarks). it might help issue #1025 : because of such an error, the stun plugin wasn't loaded anymore! Modified: trunk/freenet/src/freenet/config/LongOption.java =================================================================== --- trunk/freenet/src/freenet/config/LongOption.java 2007-03-03 14:44:36 UTC (rev 11942) +++ trunk/freenet/src/freenet/config/LongOption.java 2007-03-03 16:44:39 UTC (rev 11943) @@ -47,7 +47,12 @@ } public void setValue(String val) throws InvalidConfigValueException { - long x = Fields.parseLong(val); + long x; + try{ + x = Fields.parseLong(val); + }catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } cb.set(x); cachedStringValue = val; currentValue = x; @@ -62,7 +67,12 @@ } public void setInitialValue(String val) throws InvalidConfigValueException { - long x = Fields.parseLong(val); + long x; + try{ + x = Fields.parseLong(val); + }catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } cachedStringValue = val; currentValue = x; } From nextgens at freenetproject.org Sat Mar 3 16:58:47 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 16:58:47 +0000 (UTC) Subject: [freenet-cvs] r11944 - trunk/freenet/src/freenet/config Message-ID: <20070303165847.D079B9BB29@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 16:58:31 +0000 (Sat, 03 Mar 2007) New Revision: 11944 Modified: trunk/freenet/src/freenet/config/IntOption.java trunk/freenet/src/freenet/config/ShortOption.java Log: Do the same for IntOption adn ShortOption Modified: trunk/freenet/src/freenet/config/IntOption.java =================================================================== --- trunk/freenet/src/freenet/config/IntOption.java 2007-03-03 16:44:39 UTC (rev 11943) +++ trunk/freenet/src/freenet/config/IntOption.java 2007-03-03 16:58:31 UTC (rev 11944) @@ -47,14 +47,24 @@ } public void setValue(String val) throws InvalidConfigValueException { - int x = Fields.parseInt(val); + int x; + try{ + x = Fields.parseInt(val); + } catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } cb.set(x); cachedStringValue = val; currentValue = x; } - public void setInitialValue(String val) { - int x = Fields.parseInt(val); + public void setInitialValue(String val) throws InvalidConfigValueException { + int x; + try{ + x = Fields.parseInt(val); + } catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } cachedStringValue = val; currentValue = x; } Modified: trunk/freenet/src/freenet/config/ShortOption.java =================================================================== --- trunk/freenet/src/freenet/config/ShortOption.java 2007-03-03 16:44:39 UTC (rev 11943) +++ trunk/freenet/src/freenet/config/ShortOption.java 2007-03-03 16:58:31 UTC (rev 11944) @@ -26,7 +26,12 @@ } public void setValue(String val) throws InvalidConfigValueException { - short x = Fields.parseShort(val); + short x; + try{ + x= Fields.parseShort(val); + } catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } cb.set(x); currentValue = x; } @@ -36,7 +41,12 @@ } public void setInitialValue(String val) throws InvalidConfigValueException { - short x = Fields.parseShort(val); + short x; + try{ + x = Fields.parseShort(val); + } catch (NumberFormatException e) { + throw new InvalidConfigValueException("The value specified can't be parsed : "+val); + } currentValue = x; } From nextgens at freenetproject.org Sat Mar 3 19:07:10 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 19:07:10 +0000 (UTC) Subject: [freenet-cvs] r11945 - in trunk/freenet/src/freenet: clients/http node Message-ID: <20070303190710.8CB259BB49@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 19:07:09 +0000 (Sat, 03 Mar 2007) New Revision: 11945 Modified: trunk/freenet/src/freenet/clients/http/ConfigToadlet.java trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java trunk/freenet/src/freenet/clients/http/FProxyToadlet.java trunk/freenet/src/freenet/clients/http/LocalFileInsertToadlet.java trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java trunk/freenet/src/freenet/clients/http/NinjaSpider.java trunk/freenet/src/freenet/clients/http/PluginToadlet.java trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java trunk/freenet/src/freenet/node/Node.java Log: Spare some StringBuffer instances on toadlets, remove some dead/obsolete code Modified: trunk/freenet/src/freenet/clients/http/ConfigToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/ConfigToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/ConfigToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -165,9 +165,7 @@ formNode.addChild("input", new String[] { "type", "value" }, new String[] { "submit", "Apply" }); formNode.addChild("input", new String[] { "type", "value" }, new String[] { "reset", "Reset" }); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); } public String supportedMethods() { Modified: trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -607,9 +607,7 @@ // ignore } - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); } private String sortString(boolean isReversed, String type) { @@ -738,9 +736,7 @@ this.writeReply(ctx, 200, "text/html", "OK", resultString); return; } - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); return; } else if (request.isPartSet("doAction") && request.getPartAsString("action",25).equals("update_notes")) { //int hashcode = Integer.decode(request.getParam("node")).intValue(); Modified: trunk/freenet/src/freenet/clients/http/FProxyToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/FProxyToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -325,9 +325,7 @@ errorContent.addChild("br"); errorContent.addChild("a", new String[] { "href", "title" }, new String[] { "/", "Node homepage" }, "Homepage"); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 400, "text/html", "Invalid key", pageBuffer.toString()); + this.writeReply(ctx, 400, "text/html", "Invalid key", pageNode.generate()); return; } String requestedMimeType = httprequest.getParam("type", null); @@ -407,9 +405,7 @@ optionForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "download", "Download in background and store in downloads directory" }); optionList.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/", "FProxy home page" }, "Abort and return to the FProxy home page"); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); } else { HTMLNode pageNode = ctx.getPageMaker().getPageNode(FetchException.getShortMessage(e.mode)); HTMLNode contentNode = ctx.getPageMaker().getContentNode(pageNode); @@ -426,10 +422,8 @@ infoboxContent.addChild("br"); infoboxContent.addChild("a", new String[] { "href", "title" }, new String[] { "/", "Node homepage" }, "Homepage"); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); this.writeReply(ctx, 500 /* close enough - FIXME probably should depend on status code */, - "text/html", FetchException.getShortMessage(e.mode), pageBuffer.toString()); + "text/html", FetchException.getShortMessage(e.mode), pageNode.generate()); } } catch (SocketException e) { // Probably irrelevant Modified: trunk/freenet/src/freenet/clients/http/LocalFileInsertToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/LocalFileInsertToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/LocalFileInsertToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -48,8 +48,6 @@ } currentPath = new File(path).getCanonicalFile(); - - StringBuffer pageBuffer = new StringBuffer(16384); PageMaker pageMaker = toadletContext.getPageMaker(); HTMLNode pageNode = pageMaker.getPageNode("Listing of " + currentPath.getAbsolutePath()); @@ -134,8 +132,7 @@ ulNode.addChild("li", "Check that the specified path is readable by the user running the node."); } - pageNode.generate(pageBuffer); - writeReply(toadletContext, 200, "text/html; charset=utf-8", "OK", pageBuffer.toString()); + writeReply(toadletContext, 200, "text/html; charset=utf-8", "OK", pageNode.generate()); } /** Modified: trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -16,7 +16,6 @@ import freenet.node.Node; import freenet.node.NodeClientCore; import freenet.node.PeerNode; -import freenet.node.Version; import freenet.support.Base64; import freenet.support.HTMLNode; import freenet.support.Logger; @@ -66,9 +65,7 @@ } if(peernode_name == null) { contentNode.addChild(createPeerInfobox("infobox-error", "Peer not found", "The peer with the hash code \u201c" + input_hashcode_string + "\u201d could not be found.")); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); return; } HashMap peers = new HashMap(); @@ -78,9 +75,7 @@ this.writeReply(ctx, 200, "text/html", "OK", resultString); return; } - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); return; } MultiValueTable headers = new MultiValueTable(); @@ -139,11 +134,7 @@ fs.put("composedTime", now); fs.put("sentTime", now); Message n2ntm; - if(Version.buildNumber() < 1000) { // FIXME/TODO: This test shouldn't be needed eventually - n2ntm = DMT.createNodeToNodeTextMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT, node.getMyName(), pn.getName(), message); - } else { - n2ntm = DMT.createNodeToNodeMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT, fs.toString().getBytes("UTF-8")); - } + n2ntm = DMT.createNodeToNodeMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT, fs.toString().getBytes("UTF-8")); if(!pn.isConnected()) { sendStatusShort = "Queued"; sendStatusLong = "Queued: Peer not connected, so message queued for when it connects"; @@ -179,10 +170,8 @@ HTMLNode list = peerTableInfobox.addChild("ul"); list.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/", "Back to node homepage" }, "Homepage"); list.addChild("li").addChild("a", new String[] { "href", "title" }, new String[] { "/darknet/", "Back to darknet connections" }, "Darknet connections"); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - this.writeReply(ctx, 200, "text/html", "OK", pageBuffer.toString()); - return; + this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); + return; } MultiValueTable headers = new MultiValueTable(); headers.put("Location", "/darknet/"); @@ -192,9 +181,7 @@ public static String createN2NTMSendForm(HTMLNode pageNode, HTMLNode contentNode, ToadletContext ctx, HashMap peers) throws ToadletContextClosedException, IOException { if(contentNode == null) { contentNode.addChild(createPeerInfobox("infobox-error", "Internal error", "Internal error: N2NTMToadlet.createN2NTMSendForm() not passed a valid contentNode.")); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - return pageBuffer.toString(); + return pageNode.generate(); } HTMLNode infobox = contentNode.addChild("div", new String[] { "class", "id" }, new String[] { "infobox", "n2nbox" }); infobox.addChild("div", "class", "infobox-header", "Send Node to Node Text Message"); Modified: trunk/freenet/src/freenet/clients/http/NinjaSpider.java =================================================================== --- trunk/freenet/src/freenet/clients/http/NinjaSpider.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/NinjaSpider.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -577,9 +577,7 @@ } } MultiValueTable responseHeaders = new MultiValueTable(); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - byte[] responseBytes = pageBuffer.toString().getBytes(); + byte[] responseBytes = pageNode.generate().getBytes(); context.sendReplyHeaders(200, "OK", responseHeaders, "text/html; charset=utf-8", responseBytes.length); context.writeData(responseBytes); } else if ("add".equals(action)) { @@ -616,9 +614,7 @@ HTMLNode infobox = contentNode.addChild("div", "class", "infobox infobox-alert"); infobox.addChild("div", "class", "infobox-header", title); infobox.addChild("div", "class", "infobox-content", message); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - byte[] responseBytes = pageBuffer.toString().getBytes("utf-8"); + byte[] responseBytes = pageNode.generate().getBytes("utf-8"); context.sendReplyHeaders(200, "OK", new MultiValueTable(), "text/html; charset=utf-8", responseBytes.length); context.writeData(responseBytes); } Modified: trunk/freenet/src/freenet/clients/http/PluginToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/PluginToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/PluginToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -192,7 +192,7 @@ * The toadlet context * @return A StringBuffer containing the HTML page */ - private StringBuffer listPlugins(ToadletContext context) { + private String listPlugins(ToadletContext context) { Plugin[] plugins = pluginManager.getPlugins(); PageMaker pageMaker = context.getPageMaker(); HTMLNode pageNode = pageMaker.getPageNode("List of Plugins"); @@ -228,9 +228,7 @@ contentNode.addChild(createAddPluginBox(context)); - StringBuffer pageBuffer = new StringBuffer(); - pageNode.generate(pageBuffer); - return pageBuffer; + return pageNode.generate(); } /** Modified: trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/clients/http/WelcomeToadlet.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -89,7 +89,6 @@ writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); Logger.normal(this, "Node is updating/restarting"); node.getNodeUpdater().arm(); - return; }else if (request.getPartAsString(GenericReadFilterCallback.magicHTTPEscapeString, MAX_URL_LENGTH).length()>0){ if(noPassword) { redirectToRoot(ctx); @@ -101,7 +100,6 @@ url = request.getPartAsString(GenericReadFilterCallback.magicHTTPEscapeString, MAX_URL_LENGTH); headers.put("Location", url==null ? "/" : url); ctx.sendReplyHeaders(302, "Found", headers, null, 0); - return; }else if (request.getPartAsString("update", 32).length() > 0) { HTMLNode pageNode = ctx.getPageMaker().getPageNode("Node Update"); HTMLNode contentNode = ctx.getPageMaker().getContentNode(pageNode); @@ -112,7 +110,6 @@ updateForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "cancel", "Cancel" }); updateForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "submit", "updateconfirm", "Update" }); writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); - return; }else if(request.isPartSet("getThreadDump")) { if(noPassword) { redirectToRoot(ctx); @@ -130,7 +127,6 @@ ctx.getPageMaker().getContentNode(infobox).addChild("#", "It's not possible to make the node generate a thread dump if you aren't using the wrapper!"); } this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); - return; }else if(request.isPartSet("getJEStatsDump")) { if(noPassword) { redirectToRoot(ctx); @@ -146,7 +142,6 @@ ctx.getPageMaker().getContentNode(infobox).addChild("#", "Runtime database statistics have been written to the wrapper logfile"); this.writeReply(ctx, 200, "text/html", "OK", pageNode.generate()); - return; }else if (request.isPartSet("addbookmark")) { if(noPassword) { redirectToRoot(ctx); @@ -385,7 +380,6 @@ infoboxContent.addChild("#", "Thank you for using Freenet."); writeReply(ctx, 200, "text/html; charset=utf-8", "OK", pageNode.generate()); this.node.exit("Shutdown from fproxy"); - return; }else if(request.isPartSet("restartconfirm")){ if(noPassword) { redirectToRoot(ctx); @@ -400,7 +394,6 @@ writeReply(ctx, 200, "text/html; charset=utf-8", "OK", pageNode.generate()); Logger.normal(this, "Node is restarting"); node.getNodeStarter().restart(); - return; }else { redirectToRoot(ctx); } @@ -447,9 +440,7 @@ this.writeReply(ctx, 200, "text/plain", "OK", sw.toString()); return; - } - - if (request.getParam("newbookmark").length() > 0) { + }else if (request.getParam("newbookmark").length() > 0) { HTMLNode pageNode = ctx.getPageMaker().getPageNode("Add a Bookmark"); HTMLNode contentNode = ctx.getPageMaker().getContentNode(pageNode); HTMLNode infobox = contentNode.addChild(ctx.getPageMaker().getInfobox("Confirm Bookmark Addition")); @@ -467,7 +458,6 @@ HTMLNode warnbox = contentNode.addChild(ctx.getPageMaker().getInfobox("infobox-warning", "External link")); HTMLNode externalLinkForm = ctx.addFormChild(ctx.getPageMaker().getContentNode(warnbox), "/", "confirmExternalLinkForm"); - // FIXME: has request.getParam(GenericReadFilterCallback.magicHTTPEscapeString) been sanityzed ? final String target = request.getParam(GenericReadFilterCallback.magicHTTPEscapeString); externalLinkForm.addChild("#", "Please confirm that you want to go to " + target + ". WARNING: You are leaving FREENET! Clicking on this link WILL seriously jeopardize your anonymity!. It is strongly recommended not to do so!"); externalLinkForm.addChild("br"); Modified: trunk/freenet/src/freenet/node/Node.java =================================================================== --- trunk/freenet/src/freenet/node/Node.java 2007-03-03 16:58:31 UTC (rev 11944) +++ trunk/freenet/src/freenet/node/Node.java 2007-03-03 19:07:09 UTC (rev 11945) @@ -888,8 +888,7 @@ aggressiveGCModificator = val; } }); - if(lastVersion <= 954) - nodeConfig.fixOldDefault("aggressiveGC", "250"); + aggressiveGCModificator = nodeConfig.getInt("aggressiveGC"); //Memory Checking thread @@ -1316,7 +1315,6 @@ }); - if(lastVersion <= 1007) nodeConfig.fixOldDefault("databaseMaxMemory", "0"); // FIXME remove; 1007 had a bug which reset this to 0 databaseMaxMemory = nodeConfig.getLong("databaseMaxMemory"); envMutableConfig.setCacheSize(databaseMaxMemory); @@ -3601,7 +3599,7 @@ } // FIXME put this somewhere else - private final Object statsSync = new Object(); + private volatile Object statsSync = new Object(); /** The total number of bytes of real data i.e. payload sent by the node */ private long totalPayloadSent; From nextgens at freenetproject.org Sat Mar 3 19:14:04 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 19:14:04 +0000 (UTC) Subject: [freenet-cvs] r11946 - trunk/freenet/src/freenet/client Message-ID: <20070303191404.490179BCF9@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 19:14:03 +0000 (Sat, 03 Mar 2007) New Revision: 11946 Modified: trunk/freenet/src/freenet/client/RealArchiveStoreItem.java Log: Doh! we want to free it : finalizing will come afterwards. Modified: trunk/freenet/src/freenet/client/RealArchiveStoreItem.java =================================================================== --- trunk/freenet/src/freenet/client/RealArchiveStoreItem.java 2007-03-03 19:07:09 UTC (rev 11945) +++ trunk/freenet/src/freenet/client/RealArchiveStoreItem.java 2007-03-03 19:14:03 UTC (rev 11946) @@ -59,7 +59,7 @@ } void innerClose() { - underBucket.finalize(); + underBucket.free(); } Bucket getDataOrThrow() throws ArchiveFailureException { From nextgens at freenetproject.org Sat Mar 3 19:19:42 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 19:19:42 +0000 (UTC) Subject: [freenet-cvs] r11947 - trunk/freenet/src/freenet/config Message-ID: <20070303191942.DFFDD9BB49@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 19:19:41 +0000 (Sat, 03 Mar 2007) New Revision: 11947 Modified: trunk/freenet/src/freenet/config/StringArrOption.java Log: Doh!!! fix a silly bug in StringArrOption. Modified: trunk/freenet/src/freenet/config/StringArrOption.java =================================================================== --- trunk/freenet/src/freenet/config/StringArrOption.java 2007-03-03 19:14:03 UTC (rev 11946) +++ trunk/freenet/src/freenet/config/StringArrOption.java 2007-03-03 19:19:41 UTC (rev 11947) @@ -1,5 +1,7 @@ package freenet.config; +import java.util.Arrays; + import freenet.support.URLDecoder; import freenet.support.URLEncodedFormatException; import freenet.support.URLEncoder; @@ -100,7 +102,7 @@ public boolean isDefault() { getValueString(); - return currentValue == null ? false : currentValue.equals(defaultValue); + return currentValue == null ? false : Arrays.equals(currentValue, defaultValue); } public void setDefault() { From nextgens at freenetproject.org Sat Mar 3 23:42:32 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sat, 3 Mar 2007 23:42:32 +0000 (UTC) Subject: [freenet-cvs] r11950 - trunk/freenet/src/freenet/node Message-ID: <20070303234232.BAE1B9C251@emu.freenetproject.org> Author: nextgens Date: 2007-03-03 23:42:31 +0000 (Sat, 03 Mar 2007) New Revision: 11950 Modified: trunk/freenet/src/freenet/node/Node.java trunk/freenet/src/freenet/node/TextModeClientInterface.java Log: Get rid of a duplicate method Modified: trunk/freenet/src/freenet/node/Node.java =================================================================== --- trunk/freenet/src/freenet/node/Node.java 2007-03-03 23:34:26 UTC (rev 11949) +++ trunk/freenet/src/freenet/node/Node.java 2007-03-03 23:42:31 UTC (rev 11950) @@ -3614,10 +3614,6 @@ return totalPayloadSent; } } - - public String getName() { - return myName; - } public void setName(String key) throws InvalidConfigValueException { config.get("node").getOption("name").setValue(key); Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java =================================================================== --- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2007-03-03 23:34:26 UTC (rev 11949) +++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2007-03-03 23:42:31 UTC (rev 11950) @@ -672,7 +672,7 @@ addPeer(content); } else if(uline.startsWith("NAME:")) { - outsb.append("Node name currently: ").append(n.getName()); + outsb.append("Node name currently: ").append(n.getMyName()); String key = line.substring("NAME:".length()); while((key.length() > 0) && (key.charAt(0) == ' ')) key = key.substring(1); From nextgens at freenetproject.org Sun Mar 4 00:09:49 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sun, 4 Mar 2007 00:09:49 +0000 (UTC) Subject: [freenet-cvs] r11952 - trunk/freenet/src/freenet/clients/http Message-ID: <20070304000950.1093D9C254@emu.freenetproject.org> Author: nextgens Date: 2007-03-04 00:09:42 +0000 (Sun, 04 Mar 2007) New Revision: 11952 Modified: trunk/freenet/src/freenet/clients/http/PageMaker.java Log: That constructor has to be public otherwise we can't access it from plugins. Modified: trunk/freenet/src/freenet/clients/http/PageMaker.java =================================================================== --- trunk/freenet/src/freenet/clients/http/PageMaker.java 2007-03-03 23:42:55 UTC (rev 11951) +++ trunk/freenet/src/freenet/clients/http/PageMaker.java 2007-03-04 00:09:42 UTC (rev 11952) @@ -32,7 +32,7 @@ /** Cache for themes read from the JAR file. */ private List jarThemesCache = null; - PageMaker(String t) { + public PageMaker(String t) { setTheme(t); } From nextgens at freenetproject.org Sun Mar 4 15:15:38 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sun, 4 Mar 2007 15:15:38 +0000 (UTC) Subject: [freenet-cvs] r11953 - trunk/freenet/src/freenet/clients/http Message-ID: <20070304151538.BE30F9BC5F@emu.freenetproject.org> Author: nextgens Date: 2007-03-04 15:15:38 +0000 (Sun, 04 Mar 2007) New Revision: 11953 Modified: trunk/freenet/src/freenet/clients/http/PluginToadlet.java trunk/freenet/src/freenet/clients/http/PproxyToadlet.java Log: Load plugins' web interface as a popup insteed of replacing fproxy Modified: trunk/freenet/src/freenet/clients/http/PluginToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/PluginToadlet.java 2007-03-04 00:09:42 UTC (rev 11952) +++ trunk/freenet/src/freenet/clients/http/PluginToadlet.java 2007-03-04 15:15:38 UTC (rev 11953) @@ -212,7 +212,7 @@ tableRow.addChild("td", plugin.getPluginName()); tableRow.addChild("td", internalName); if (plugin instanceof HttpPlugin) { - tableRow.addChild("td").addChild("form", new String[] { "action", "method" }, new String[] { internalName, "get" }).addChild("input", new String[] { "type", "value" }, new String[] { "submit", "Visit" }); + tableRow.addChild("td").addChild("form", new String[] { "action", "method", "target" }, new String[] { internalName, "get", "_new" }).addChild("input", new String[] { "type", "value" }, new String[] { "submit", "Visit" }); } else { tableRow.addChild("td"); } Modified: trunk/freenet/src/freenet/clients/http/PproxyToadlet.java =================================================================== --- trunk/freenet/src/freenet/clients/http/PproxyToadlet.java 2007-03-04 00:09:42 UTC (rev 11952) +++ trunk/freenet/src/freenet/clients/http/PproxyToadlet.java 2007-03-04 15:15:38 UTC (rev 11953) @@ -190,7 +190,7 @@ pluginRow.addChild("td", new Date(pi.getStarted()).toString()); HTMLNode actionCell = pluginRow.addChild("td"); if (pi.isPproxyPlugin()) { - HTMLNode visitForm = actionCell.addChild("form", new String[] { "method", "action" }, new String[] { "get", pi.getPluginClassName() }); + HTMLNode visitForm = actionCell.addChild("form", new String[] { "method", "action", "target" }, new String[] { "get", pi.getPluginClassName(), "_new" }); visitForm.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "formPassword", core.formPassword }); visitForm.addChild("input", new String[] { "type", "value" }, new String[] { "submit", "Visit" }); } From nextgens at freenetproject.org Sun Mar 4 15:23:02 2007 From: nextgens at freenetproject.org (nextgens at freenetproject.org) Date: Sun, 4 Mar 2007 15:23:02 +0000 (UTC) Subject: [freenet-cvs] r11954 - in trunk/plugins: . MDNSDiscovery MDNSDiscovery/com MDNSDiscovery/com/strangeberry MDNSDiscovery/com/strangeberry/jmdns MDNSDiscovery/com/strangeberry/jmdns/tools MDNSDiscovery/javax MDNSDiscovery/javax/jmdns Message-ID: <20070304152302.3A6F49BC5F@emu.freenetproject.org> Author: nextgens Date: 2007-03-04 15:23:01 +0000 (Sun, 04 Mar 2007) New Revision: 11954 Added: trunk/plugins/MDNSDiscovery/ trunk/plugins/MDNSDiscovery/MDNSDiscovery.java trunk/plugins/MDNSDiscovery/com/ trunk/plugins/MDNSDiscovery/com/strangeberry/ trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/ trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/ trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Browser.java trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Main.java trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Responder.java trunk/plugins/MDNSDiscovery/gpl.txt trunk/plugins/MDNSDiscovery/javax/ trunk/plugins/MDNSDiscovery/javax/jmdns/ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSCache.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSConstants.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSEntry.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSIncoming.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSListener.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSOutgoing.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSQuestion.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSRecord.java trunk/plugins/MDNSDiscovery/javax/jmdns/DNSState.java trunk/plugins/MDNSDiscovery/javax/jmdns/HostInfo.java trunk/plugins/MDNSDiscovery/javax/jmdns/JmDNS.java trunk/plugins/MDNSDiscovery/javax/jmdns/ServiceEvent.java trunk/plugins/MDNSDiscovery/javax/jmdns/ServiceInfo.java trunk/plugins/MDNSDiscovery/javax/jmdns/ServiceListener.java trunk/plugins/MDNSDiscovery/javax/jmdns/ServiceTypeListener.java Log: plugins: new plugin called MDNSDiscovery ; it implements Zeroconf (called Bonjour/RendezVous by apple) support on a freenet node. That will allow FCP clients to discover "automagicaly" FCP servers and might have other applications (we will discuss that on @darknet-tools soon) it works fine using latest trunk (r11953) no backward compatibility is planned. Added: trunk/plugins/MDNSDiscovery/MDNSDiscovery.java =================================================================== --- trunk/plugins/MDNSDiscovery/MDNSDiscovery.java (rev 0) +++ trunk/plugins/MDNSDiscovery/MDNSDiscovery.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,178 @@ +/* This code is part of Freenet. It is distributed under the GNU General + * Public License, version 2 (or at your option any later version). See + * http://www.gnu.org/ for further details of the GPL. */ + +package plugins.MDNSDiscovery; + +import java.io.IOException; + +import plugins.MDNSDiscovery.javax.jmdns.JmDNS; +import plugins.MDNSDiscovery.javax.jmdns.ServiceEvent; +import plugins.MDNSDiscovery.javax.jmdns.ServiceInfo; +import plugins.MDNSDiscovery.javax.jmdns.ServiceListener; +import freenet.clients.http.PageMaker; +import freenet.config.Config; +import freenet.pluginmanager.*; +import freenet.support.HTMLNode; +import freenet.support.api.HTTPRequest; + +/** + * This plugin implements Zeroconf (called Bonjour/RendezVous by apple) support on a freenet node. + * + * @author Florent Daignière <nextgens at freenetproject.org> + * + * @see http://www.dns-sd.org/ServiceTypes.html + * @see http://www.multicastdns.org/ + * @see http://jmdns.sourceforge.net/ + * + * TODO: We shouldn't start a thread at all ... but they are issues on startup (the configuration framework isn't available yet) + * TODO: We shouldn't advertise services if they aren't reachable (ie: bound to localhost) + * TODO: We will need to manage the list on our own insteed of requesting it for each http request + * TODO: Plug into config. callbacks to reflect changes + */ +public class MDNSDiscovery implements FredPlugin, FredPluginHTTP{ + public static String freenetServiceType = "_freenet._udp.local."; + private boolean goon = true; + private JmDNS jmdns; + private ServiceInfo fproxyInfo, tcmiInfo, fcpInfo, nodeInfo; + private Config nodeConfig; + private PageMaker pageMaker; + + /** + * Called upon plugin unloading : we unregister advertised services + */ + public void terminate() { + jmdns.unregisterAllServices(); + goon = false; + } + + public void runPlugin(PluginRespirator pr) { + // wait until the node is initialised. + do{ + try{ + Thread.sleep(1000); + }catch (InterruptedException e) {} + }while(pr.getNode() == null || !pr.getNode().isHasStarted()); + + nodeConfig = pr.getNode().config; + pageMaker = new PageMaker("clean"); + + try{ + // Create the multicast listener + jmdns = new JmDNS(); + final String address = "server on " + jmdns.getLocalHost() + " (" + pr.getNode().getMyName(); + + // Advertise Fproxy + if(nodeConfig.get("fproxy").getBoolean("enabled")){ + fproxyInfo = new ServiceInfo("_http._tcp.local.", "Freenet 0.7 Fproxy " + address, + nodeConfig.get("fproxy").getInt("port"), 0, 0, "path=/"); + jmdns.registerService(fproxyInfo); + } + + // Advertise FCP + if(nodeConfig.get("fcp").getBoolean("enabled")){ + fcpInfo = new ServiceInfo("_fcp._tcp.local.", "Freenet 0.7 FCP " + address, + nodeConfig.get("fcp").getInt("port"), 0, 0, ""); + jmdns.registerService(fcpInfo); + } + + // Advertise TCMI + if(nodeConfig.get("console").getBoolean("enabled")){ + tcmiInfo = new ServiceInfo("_telnet._tcp.local.", "Freenet 0.7 TCMI " + address, + nodeConfig.get("console").getInt("port"), 0, 0, ""); + jmdns.registerService(tcmiInfo); + } + + // Advertise the node + nodeInfo = new ServiceInfo(MDNSDiscovery.freenetServiceType, "Freenet 0.7 Node " + address, + nodeConfig.get("node").getInt("listenPort"), 0, 0, ""); + jmdns.registerService(nodeInfo); + + // Watch out for other nodes + jmdns.addServiceListener(MDNSDiscovery.freenetServiceType, new NodeMDNSListener(this)); + + } catch (IOException e) { + e.printStackTrace(); + } + + while(goon){ + synchronized (this) { + try{ + wait(300000); + }catch (InterruptedException e) {} + } + } + } + + static class NodeMDNSListener implements ServiceListener { + final MDNSDiscovery plugin; + + public NodeMDNSListener(MDNSDiscovery plugin) { + this.plugin = plugin; + } + + public synchronized void serviceAdded(ServiceEvent event) { + System.out.println("Service added : " + event.getName()+"."+event.getType()); + synchronized (plugin) { + plugin.notify(); + } + } + + public synchronized void serviceRemoved(ServiceEvent event) { + System.out.println("Service removed : " + event.getName()+"."+event.getType()); + synchronized (plugin) { + plugin.notify(); + } + } + + public synchronized void serviceResolved(ServiceEvent event) { + System.out.println("Service resolved: " + event.getInfo()); + synchronized (plugin) { + plugin.notify(); + } + } + } + + public String handleHTTPGet(HTTPRequest request) throws PluginHTTPException { + HTMLNode pageNode = pageMaker.getPageNode("MDNSDiscovery plugin configuration page", false); + HTMLNode contentNode = pageMaker.getContentNode(pageNode); + + ServiceInfo[] foundNodes = jmdns.list(MDNSDiscovery.freenetServiceType); + if(foundNodes != null && foundNodes.length > 0){ + HTMLNode peerTableInfobox = contentNode.addChild("div", "class", "infobox infobox-normal"); + HTMLNode peerTableInfoboxHeader = peerTableInfobox.addChild("div", "class", "infobox-header"); + peerTableInfoboxHeader.addChild("#", "The following nodes have been found on the local subnet :"); + HTMLNode peerTableInfoboxContent = peerTableInfobox.addChild("div", "class", "infobox-content"); + + HTMLNode peerTable = peerTableInfoboxContent.addChild("table", "class", "darknet_connections"); + HTMLNode peerTableHeaderRow = peerTable.addChild("tr"); + peerTableHeaderRow.addChild("th").addChild("span", new String[] { "title", "style" }, new String[] { "The node's name.", "border-bottom: 1px dotted; cursor: help;" }, "Name"); + peerTableHeaderRow.addChild("th").addChild("span", new String[] { "title", "style" }, new String[] { "The node's network address as IP:Port", "border-bottom: 1px dotted; cursor: help;" }, "Address"); + peerTableHeaderRow.addChild("th").addChild("span", new String[] { "title", "style" }, new String[] { "A description of the service.", "border-bottom: 1px dotted; cursor: help;" }, "Description"); + + HTMLNode peerRow = peerTable.addChild("tr"); + + for(int i=0; i 0) && "-d".equals(argv[0])) { + System.arraycopy(argv, 1, argv, 0, --argc); + System.getProperties().put("jmdns.debug", "1"); + debug = true; + } + if ((argc > 1) && "-i".equals(argv[0])) { + intf = InetAddress.getByName(argv[1]); + System.arraycopy(argv, 2, argv, 0, argc -= 2); + } + if (intf == null) { + intf = InetAddress.getLocalHost(); + } + + JmDNS jmdns = new JmDNS(intf); + + if ((argc == 0) || ((argc >= 1) && "-browse".equals(argv[0]))) { + new Browser(jmdns); + for (int i = 2 ; i < argc ; i++) { + jmdns.registerServiceType(argv[i]); + } + } else if ((argc == 1) && "-bt".equals(argv[0])) { + jmdns.addServiceTypeListener(new SampleListener()); + } else if ((argc == 3) && "-bs".equals(argv[0])) { + jmdns.addServiceListener(argv[1] + "." + argv[2], new SampleListener()); + } else if ((argc > 4) && "-rs".equals(argv[0])) { + String type = argv[2] + "." + argv[3]; + String name = argv[1]; + Hashtable props = null; + for (int i = 5 ; i < argc ; i++) { + int j = argv[i].indexOf('='); + if (j < 0) { + throw new RuntimeException("not key=val: " + argv[i]); + } + if (props == null) { + props = new Hashtable(); + } + props.put(argv[i].substring(0, j), argv[i].substring(j+1)); + } + jmdns.registerService(new ServiceInfo(type, name, Integer.parseInt(argv[4]), 0, 0, props)); + + // This while loop keeps the main thread alive + while (true) { + try { + Thread.sleep(Integer.MAX_VALUE); + } catch (InterruptedException e) { + break; + } + } + } else if ((argc == 2) && "-f".equals(argv[0])) { + new Responder(jmdns, argv[1]); + } else if (!debug) { + System.out.println(); + System.out.println("jmdns:"); + System.out.println(" -d - output debugging info"); + System.out.println(" -i - specify the interface address"); + System.out.println(" -browse [...] - GUI browser (default)"); + System.out.println(" -bt - browse service types"); + System.out.println(" -bs - browse services by type"); + System.out.println(" -rs - register service"); + System.out.println(" -f - rendezvous responder"); + System.out.println(); + System.exit(1); + } + } +} Added: trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Responder.java =================================================================== --- trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Responder.java (rev 0) +++ trunk/plugins/MDNSDiscovery/com/strangeberry/jmdns/tools/Responder.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,79 @@ +// %Z%%M%, %I%, %G% +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package plugins.MDNSDiscovery.com.strangeberry.jmdns.tools; + +import java.io.*; +import plugins.MDNSDiscovery.javax.jmdns.*; + +/** + * A sample JmDNS responder that reads a set of rendezvous service + * definitions from a file and registers them with rendezvous. It uses + * the same file format as Apple's responder. Each record consists of + * 4 lines: name, type, text, port. Empty lines and lines starting with # + * between records are ignored. + * + * @author Arthur van Hoff + * @version %I%, %G% + */ +public class Responder +{ + /** + * Constructor. + */ + public Responder(JmDNS jmdns, String file) throws IOException + { + BufferedReader in = new BufferedReader(new FileReader(file)); + try { + while (true) { + String ln = in.readLine(); + while ((ln != null) && (ln.startsWith("#") || ln.trim().length() == 0)) { + ln = in.readLine(); + } + if (ln == null) { + break; + } + String name = ln; + String type = in.readLine(); + String text = in.readLine(); + int port = Integer.parseInt(in.readLine()); + + // make sure the type is fully qualified and in the local. domain + if (!type.endsWith(".")) { + type += "."; + } + if (!type.endsWith(".local.")) { + type += "local."; + } + + jmdns.registerService( + new ServiceInfo(type, name, port, text)); + } + } finally { + in.close(); + } + } + + /** + * Create a responder. + */ + public static void main(String argv[]) throws IOException + { + new Responder(new JmDNS(), (argv.length > 0) ? argv[0] : "services.txt"); + } +} + + Added: trunk/plugins/MDNSDiscovery/gpl.txt =================================================================== --- trunk/plugins/MDNSDiscovery/gpl.txt (rev 0) +++ trunk/plugins/MDNSDiscovery/gpl.txt 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSCache.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSCache.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSCache.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,257 @@ +//Copyright 2003-2005 Arthur van Hoff Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + +package plugins.MDNSDiscovery.javax.jmdns; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * A table of DNS entries. This is a hash table which + * can handle multiple entries with the same name. + *

+ * Storing multiple entries with the same name is implemented using a + * linked list of CacheNode's. + *

+ * The current implementation of the API of DNSCache does expose the + * cache nodes to clients. Clients must explicitly deal with the nodes + * when iterating over entries in the cache. Here's how to iterate over + * all entries in the cache: + *

+ * for (Iterator i=dnscache.iterator(); i.hasNext(); ) {
+ *    for (DNSCache.CacheNode n = (DNSCache.CacheNode) i.next(); n != null; n.next()) {
+ *       DNSEntry entry = n.getValue();
+ *       ...do something with entry...
+ *    }
+ * }
+ * 
+ *

+ * And here's how to iterate over all entries having a given name: + *

+ * for (DNSCache.CacheNode n = (DNSCache.CacheNode) dnscache.find(name); n != null; n.next()) {
+ *     DNSEntry entry = n.getValue();
+ *     ...do something with entry...
+ * }
+ * 
+ * + * @version %I%, %G% + * @author Arthur van Hoff, Werner Randelshofer, Rick Blair + */ +class DNSCache +{ + private static Logger logger = Logger.getLogger(DNSCache.class.toString()); + // Implementation note: + // We might completely hide the existence of CacheNode's in a future version + // of DNSCache. But this will require to implement two (inner) classes for + // the iterators that will be returned by method iterator() and + // method find(name). + // Since DNSCache is not a public class, it does not seem worth the effort + // to clean its API up that much. + + // [PJYF Oct 15 2004] This should implements Collections that would be amuch cleaner implementation + + /** + * The number of DNSEntry's in the cache. + */ + private int size; + + /** + * The hashtable used internally to store the entries of the cache. + * Keys are instances of String. The String contains an unqualified service + * name. + * Values are linked lists of CacheNode instances. + */ + private HashMap hashtable; + + /** + * Cache nodes are used to implement storage of multiple DNSEntry's of the + * same name in the cache. + */ + public static class CacheNode + { + private static Logger logger = Logger.getLogger(CacheNode.class.toString()); + private DNSEntry value; + private CacheNode next; + + public CacheNode(DNSEntry value) + { + this.value = value; + } + + public CacheNode next() + { + return next; + } + + public DNSEntry getValue() + { + return value; + } + } + + + /** + * Create a table with a given initial size. + */ + public DNSCache(final int size) + { + hashtable = new HashMap(size); + } + + /** + * Clears the cache. + */ + public synchronized void clear() + { + hashtable.clear(); + size = 0; + } + + /** + * Adds an entry to the table. + */ + public synchronized void add(final DNSEntry entry) + { + //logger.log("DNSCache.add("+entry.getName()+")"); + CacheNode newValue = new CacheNode(entry); + CacheNode node = (CacheNode) hashtable.get(entry.getName()); + if (node == null) + { + hashtable.put(entry.getName(), newValue); + } + else + { + newValue.next = node.next; + node.next = newValue; + } + size++; + } + + /** + * Remove a specific entry from the table. Returns true if the + * entry was found. + */ + public synchronized boolean remove(DNSEntry entry) + { + CacheNode node = (CacheNode) hashtable.get(entry.getName()); + if (node != null) + { + if (node.value == entry) + { + if (node.next == null) + { + hashtable.remove(entry.getName()); + } + else + { + hashtable.put(entry.getName(), node.next); + } + size--; + return true; + } + + CacheNode previous = node; + node = node.next; + while (node != null) + { + if (node.value == entry) + { + previous.next = node.next; + size--; + return true; + } + previous = node; + node = node.next; + } + ; + } + return false; + } + + /** + * Get a matching DNS entry from the table (using equals). + * Returns the entry that was found. + */ + public synchronized DNSEntry get(DNSEntry entry) + { + for (CacheNode node = find(entry.getName()); node != null; node = node.next) + { + if (node.value.equals(entry)) + { + return node.value; + } + } + return null; + } + + /** + * Get a matching DNS entry from the table. + */ + public synchronized DNSEntry get(String name, int type, int clazz) + { + for (CacheNode node = find(name); node != null; node = node.next) + { + if (node.value.type == type && node.value.clazz == clazz) + { + return node.value; + } + } + return null; + } + + /** + * Iterates over all cache nodes. + * The iterator returns instances of DNSCache.CacheNode. + * Each instance returned is the first node of a linked list. + * To retrieve all entries, one must iterate over this linked list. See + * code snippets in the header of the class. + */ + public Iterator iterator() + { + return Collections.unmodifiableCollection(hashtable.values()).iterator(); + } + + /** + * Iterate only over items with matching name. + * Returns an instance of DNSCache.CacheNode or null. + * If an instance is returned, it is the first node of a linked list. + * To retrieve all entries, one must iterate over this linked list. + */ + public synchronized CacheNode find(String name) + { + return (CacheNode) hashtable.get(name); + } + + /** + * List all entries for debugging. + */ + public synchronized void print() + { + for (Iterator i = iterator(); i.hasNext();) + { + for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) + { + System.out.println(n.value); + } + } + } + + public synchronized String toString() + { + StringBuffer aLog = new StringBuffer(); + aLog.append("\t---- cache ----"); + for (Iterator i = iterator(); i.hasNext();) + { + for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) + { + aLog.append("\n\t\t" + n.value); + } + } + return aLog.toString(); + } + +} Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSConstants.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSConstants.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSConstants.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,125 @@ +//Copyright 2003-2005 Arthur van Hoff, Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + +package plugins.MDNSDiscovery.javax.jmdns; + +/** + * DNS constants. + * + * @version %I%, %G% + * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer, Pierre Frisch, Rick Blair + */ +final class DNSConstants +{ + + // changed to final class - jeffs + final static String MDNS_GROUP = "224.0.0.251"; + final static String MDNS_GROUP_IPV6 = "FF02::FB"; + final static int MDNS_PORT = 5353; + final static int DNS_PORT = 53; + final static int DNS_TTL = 60 * 60; // default one hour TTL + // final static int DNS_TTL = 120 * 60; // two hour TTL (draft-cheshire-dnsext-multicastdns.txt ch 13) + + final static int MAX_MSG_TYPICAL = 1460; + final static int MAX_MSG_ABSOLUTE = 8972; + + final static int FLAGS_QR_MASK = 0x8000; // Query response mask + final static int FLAGS_QR_QUERY = 0x0000; // Query + final static int FLAGS_QR_RESPONSE = 0x8000; // Response + + final static int FLAGS_AA = 0x0400; // Authorative answer + final static int FLAGS_TC = 0x0200; // Truncated + final static int FLAGS_RD = 0x0100; // Recursion desired + final static int FLAGS_RA = 0x8000; // Recursion available + + final static int FLAGS_Z = 0x0040; // Zero + final static int FLAGS_AD = 0x0020; // Authentic data + final static int FLAGS_CD = 0x0010; // Checking disabled + + final static int CLASS_IN = 1; // Final Static Internet + final static int CLASS_CS = 2; // CSNET + final static int CLASS_CH = 3; // CHAOS + final static int CLASS_HS = 4; // Hesiod + final static int CLASS_NONE = 254; // Used in DNS UPDATE [RFC 2136] + final static int CLASS_ANY = 255; // Not a DNS class, but a DNS query class, meaning "all classes" + final static int CLASS_MASK = 0x7FFF; // Multicast DNS uses the bottom 15 bits to identify the record class... + final static int CLASS_UNIQUE = 0x8000; // ... and the top bit indicates that all other cached records are now invalid + + final static int TYPE_IGNORE = 0; // This is a hack to stop further processing + final static int TYPE_A = 1; // Address + final static int TYPE_NS = 2; // Name Server + final static int TYPE_MD = 3; // Mail Destination + final static int TYPE_MF = 4; // Mail Forwarder + final static int TYPE_CNAME = 5; // Canonical Name + final static int TYPE_SOA = 6; // Start of Authority + final static int TYPE_MB = 7; // Mailbox + final static int TYPE_MG = 8; // Mail Group + final static int TYPE_MR = 9; // Mail Rename + final static int TYPE_NULL = 10; // NULL RR + final static int TYPE_WKS = 11; // Well-known-service + final static int TYPE_PTR = 12; // Domain Name pofinal static inter + final static int TYPE_HINFO = 13; // Host information + final static int TYPE_MINFO = 14; // Mailbox information + final static int TYPE_MX = 15; // Mail exchanger + final static int TYPE_TXT = 16; // Arbitrary text string + final static int TYPE_RP = 17; // for Responsible Person [RFC1183] + final static int TYPE_AFSDB = 18; // for AFS Data Base location [RFC1183] + final static int TYPE_X25 = 19; // for X.25 PSDN address [RFC1183] + final static int TYPE_ISDN = 20; // for ISDN address [RFC1183] + final static int TYPE_RT = 21; // for Route Through [RFC1183] + final static int TYPE_NSAP = 22; // for NSAP address, NSAP style A record [RFC1706] + final static int TYPE_NSAP_PTR = 23; // + final static int TYPE_SIG = 24; // for security signature [RFC2931] + final static int TYPE_KEY = 25; // for security key [RFC2535] + final static int TYPE_PX = 26; // X.400 mail mapping information [RFC2163] + final static int TYPE_GPOS = 27; // Geographical Position [RFC1712] + final static int TYPE_AAAA = 28; // IP6 Address [Thomson] + final static int TYPE_LOC = 29; // Location Information [Vixie] + final static int TYPE_NXT = 30; // Next Domain - OBSOLETE [RFC2535, RFC3755] + final static int TYPE_EID = 31; // Endpoint Identifier [Patton] + final static int TYPE_NIMLOC = 32; // Nimrod Locator [Patton] + final static int TYPE_SRV = 33; // Server Selection [RFC2782] + final static int TYPE_ATMA = 34; // ATM Address [Dobrowski] + final static int TYPE_NAPTR = 35; // Naming Authority Pointer [RFC2168, RFC2915] + final static int TYPE_KX = 36; // Key Exchanger [RFC2230] + final static int TYPE_CERT = 37; // CERT [RFC2538] + final static int TYPE_A6 = 38; // A6 [RFC2874] + final static int TYPE_DNAME = 39; // DNAME [RFC2672] + final static int TYPE_SINK = 40; // SINK [Eastlake] + final static int TYPE_OPT = 41; // OPT [RFC2671] + final static int TYPE_APL = 42; // APL [RFC3123] + final static int TYPE_DS = 43; // Delegation Signer [RFC3658] + final static int TYPE_SSHFP = 44; // SSH Key Fingerprint [RFC-ietf-secsh-dns-05.txt] + final static int TYPE_RRSIG = 46; // RRSIG [RFC3755] + final static int TYPE_NSEC = 47; // NSEC [RFC3755] + final static int TYPE_DNSKEY = 48; // DNSKEY [RFC3755] + final static int TYPE_UINFO = 100; // [IANA-Reserved] + final static int TYPE_UID = 101; // [IANA-Reserved] + final static int TYPE_GID = 102; // [IANA-Reserved] + final static int TYPE_UNSPEC = 103; // [IANA-Reserved] + final static int TYPE_TKEY = 249; // Transaction Key [RFC2930] + final static int TYPE_TSIG = 250; // Transaction Signature [RFC2845] + final static int TYPE_IXFR = 251; // Incremental transfer [RFC1995] + final static int TYPE_AXFR = 252; // Transfer of an entire zone [RFC1035] + final static int TYPE_MAILA = 253; // Mailbox-related records (MB, MG or MR) [RFC1035] + final static int TYPE_MAILB = 254; // Mail agent RRs (Obsolete - see MX) [RFC1035] + final static int TYPE_ANY = 255; // Request for all records [RFC1035] + + //Time Intervals for various functions + + final static int SHARED_QUERY_TIME = 20; //milliseconds before send shared query + final static int QUERY_WAIT_INTERVAL = 225; //milliseconds between query loops. + final static int PROBE_WAIT_INTERVAL = 250; //milliseconds between probe loops. + final static int RESPONSE_MIN_WAIT_INTERVAL = 20; //minimal wait interval for response. + final static int RESPONSE_MAX_WAIT_INTERVAL = 115; //maximal wait interval for response + final static int PROBE_CONFLICT_INTERVAL = 1000; //milliseconds to wait after conflict. + final static int PROBE_THROTTLE_COUNT = 10; //After x tries go 1 time a sec. on probes. + final static int PROBE_THROTTLE_COUNT_INTERVAL = 5000; //We only increment the throttle count, if + // the previous increment is inside this interval. + final static int ANNOUNCE_WAIT_INTERVAL = 1000; //milliseconds between Announce loops. + final static int RECORD_REAPER_INTERVAL = 10000; //milliseconds between cache cleanups. + final static int KNOWN_ANSWER_TTL = 120; + final static int ANNOUNCED_RENEWAL_TTL_INTERVAL = DNS_TTL * 500; // 50% of the TTL in milliseconds +} Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSEntry.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSEntry.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSEntry.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,148 @@ +//Copyright 2003-2005 Arthur van Hoff, Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + +package plugins.MDNSDiscovery.javax.jmdns; + +import java.util.logging.Logger; + +/** + * DNS entry with a name, type, and class. This is the base + * class for questions and records. + * + * @version %I%, %G% + * @author Arthur van Hoff, Pierre Frisch, Rick Blair + */ +class DNSEntry +{ + private static Logger logger = Logger.getLogger(DNSEntry.class.toString()); + String key; + String name; + int type; + int clazz; + boolean unique; + + /** + * Create an entry. + */ + DNSEntry(String name, int type, int clazz) + { + this.key = name.toLowerCase(); + this.name = name; + this.type = type; + this.clazz = clazz & DNSConstants.CLASS_MASK; + this.unique = (clazz & DNSConstants.CLASS_UNIQUE) != 0; + } + + /** + * Check if two entries have exactly the same name, type, and class. + */ + public boolean equals(Object obj) + { + if (obj instanceof DNSEntry) + { + DNSEntry other = (DNSEntry) obj; + return name.equals(other.name) && type == other.type && clazz == other.clazz; + } + return false; + } + + public String getName() + { + return name; + } + + public int getType() + { + return type; + } + + /** + * Overriden, to return a value which is consistent with the value returned + * by equals(Object). + */ + public int hashCode() + { + return name.hashCode() + type + clazz; + } + + /** + * Get a string given a clazz. + */ + static String getClazz(int clazz) + { + switch (clazz & DNSConstants.CLASS_MASK) + { + case DNSConstants.CLASS_IN: + return "in"; + case DNSConstants.CLASS_CS: + return "cs"; + case DNSConstants.CLASS_CH: + return "ch"; + case DNSConstants.CLASS_HS: + return "hs"; + case DNSConstants.CLASS_NONE: + return "none"; + case DNSConstants.CLASS_ANY: + return "any"; + default: + return "?"; + } + } + + /** + * Get a string given a type. + */ + static String getType(int type) + { + switch (type) + { + case DNSConstants.TYPE_A: + return "a"; + case DNSConstants.TYPE_AAAA: + return "aaaa"; + case DNSConstants.TYPE_NS: + return "ns"; + case DNSConstants.TYPE_MD: + return "md"; + case DNSConstants.TYPE_MF: + return "mf"; + case DNSConstants.TYPE_CNAME: + return "cname"; + case DNSConstants.TYPE_SOA: + return "soa"; + case DNSConstants.TYPE_MB: + return "mb"; + case DNSConstants.TYPE_MG: + return "mg"; + case DNSConstants.TYPE_MR: + return "mr"; + case DNSConstants.TYPE_NULL: + return "null"; + case DNSConstants.TYPE_WKS: + return "wks"; + case DNSConstants.TYPE_PTR: + return "ptr"; + case DNSConstants.TYPE_HINFO: + return "hinfo"; + case DNSConstants.TYPE_MINFO: + return "minfo"; + case DNSConstants.TYPE_MX: + return "mx"; + case DNSConstants.TYPE_TXT: + return "txt"; + case DNSConstants.TYPE_SRV: + return "srv"; + case DNSConstants.TYPE_ANY: + return "any"; + default: + return "?"; + } + } + + public String toString(String hdr, String other) + { + return hdr + "[" + getType(type) + "," + getClazz(clazz) + (unique ? "-unique," : ",") + name + ((other != null) ? "," + other + "]" : "]"); + } +} Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSIncoming.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSIncoming.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSIncoming.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,466 @@ +///Copyright 2003-2005 Arthur van Hoff, Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + + +package plugins.MDNSDiscovery.javax.jmdns; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Parse an incoming DNS message into its components. + * + * @version %I%, %G% + * @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch + */ +final class DNSIncoming +{ + private static Logger logger = Logger.getLogger(DNSIncoming.class.toString()); + // Implementation note: This vector should be immutable. + // If a client of DNSIncoming changes the contents of this vector, + // we get undesired results. To fix this, we have to migrate to + // the Collections API of Java 1.2. i.e we replace Vector by List. + // final static Vector EMPTY = new Vector(); + + private DatagramPacket packet; + private int off; + private int len; + private byte data[]; + + int id; + private int flags; + private int numQuestions; + int numAnswers; + private int numAuthorities; + private int numAdditionals; + private long receivedTime; + + List questions; + List answers; + + /** + * Parse a message from a datagram packet. + */ + DNSIncoming(DatagramPacket packet) throws IOException + { + this.packet = packet; + this.data = packet.getData(); + this.len = packet.getLength(); + this.off = packet.getOffset(); + this.questions = Collections.EMPTY_LIST; + this.answers = Collections.EMPTY_LIST; + this.receivedTime = System.currentTimeMillis(); + + try + { + id = readUnsignedShort(); + flags = readUnsignedShort(); + numQuestions = readUnsignedShort(); + numAnswers = readUnsignedShort(); + numAuthorities = readUnsignedShort(); + numAdditionals = readUnsignedShort(); + + // parse questions + if (numQuestions > 0) + { + questions = Collections.synchronizedList(new ArrayList(numQuestions)); + for (int i = 0; i < numQuestions; i++) + { + DNSQuestion question = new DNSQuestion(readName(), readUnsignedShort(), readUnsignedShort()); + questions.add(question); + } + } + + // parse answers + int n = numAnswers + numAuthorities + numAdditionals; + if (n > 0) + { + answers = Collections.synchronizedList(new ArrayList(n)); + for (int i = 0; i < n; i++) + { + String domain = readName(); + int type = readUnsignedShort(); + int clazz = readUnsignedShort(); + int ttl = readInt(); + int len = readUnsignedShort(); + int end = off + len; + DNSRecord rec = null; + + switch (type) + { + case DNSConstants.TYPE_A: // IPv4 + case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested + rec = new DNSRecord.Address(domain, type, clazz, ttl, readBytes(off, len)); + break; + case DNSConstants.TYPE_CNAME: + case DNSConstants.TYPE_PTR: + rec = new DNSRecord.Pointer(domain, type, clazz, ttl, readName()); + break; + case DNSConstants.TYPE_TXT: + rec = new DNSRecord.Text(domain, type, clazz, ttl, readBytes(off, len)); + break; + case DNSConstants.TYPE_SRV: + rec = new DNSRecord.Service(domain, type, clazz, ttl, + readUnsignedShort(), readUnsignedShort(), readUnsignedShort(), readName()); + break; + case DNSConstants.TYPE_HINFO: + // Maybe we should do something with those + break; + default : + logger.finer("DNSIncoming() unknown type:" + type); + break; + } + + if (rec != null) + { + // Add a record, if we were able to create one. + answers.add(rec); + } + else + { + // Addjust the numbers for the skipped record + if (answers.size() < numAnswers) + { + numAnswers--; + } + else + { + if (answers.size() < numAnswers + numAuthorities) + { + numAuthorities--; + } + else + { + if (answers.size() < numAnswers + numAuthorities + numAdditionals) + { + numAdditionals--; + } + } + } + } + off = end; + } + } + } + catch (IOException e) + { + logger.log(Level.WARNING, "DNSIncoming() dump " + print(true) + "\n exception ", e); + throw e; + } + } + + /** + * Check if the message is a query. + */ + boolean isQuery() + { + return (flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY; + } + + /** + * Check if the message is truncated. + */ + boolean isTruncated() + { + return (flags & DNSConstants.FLAGS_TC) != 0; + } + + /** + * Check if the message is a response. + */ + boolean isResponse() + { + return (flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_RESPONSE; + } + + private int get(int off) throws IOException + { + if ((off < 0) || (off >= len)) + { + throw new IOException("parser error: offset=" + off); + } + return data[off] & 0xFF; + } + + private int readUnsignedShort() throws IOException + { + return (get(off++) << 8) + get(off++); + } + + private int readInt() throws IOException + { + return (readUnsignedShort() << 16) + readUnsignedShort(); + } + + private byte[] readBytes(int off, int len) throws IOException + { + byte bytes[] = new byte[len]; + System.arraycopy(data, off, bytes, 0, len); + return bytes; + } + + private void readUTF(StringBuffer buf, int off, int len) throws IOException + { + for (int end = off + len; off < end;) + { + int ch = get(off++); + switch (ch >> 4) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + // 0xxxxxxx + break; + case 12: + case 13: + // 110x xxxx 10xx xxxx + ch = ((ch & 0x1F) << 6) | (get(off++) & 0x3F); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + ch = ((ch & 0x0f) << 12) | ((get(off++) & 0x3F) << 6) | (get(off++) & 0x3F); + break; + default: + // 10xx xxxx, 1111 xxxx + ch = ((ch & 0x3F) << 4) | (get(off++) & 0x0f); + break; + } + buf.append((char) ch); + } + } + + private String readName() throws IOException + { + StringBuffer buf = new StringBuffer(); + int off = this.off; + int next = -1; + int first = off; + + while (true) + { + int len = get(off++); + if (len == 0) + { + break; + } + switch (len & 0xC0) + { + case 0x00: + //buf.append("[" + off + "]"); + readUTF(buf, off, len); + off += len; + buf.append('.'); + break; + case 0xC0: + //buf.append("<" + (off - 1) + ">"); + if (next < 0) + { + next = off + 1; + } + off = ((len & 0x3F) << 8) | get(off++); + if (off >= first) + { + throw new IOException("bad domain name: possible circular name detected"); + } + first = off; + break; + default: + throw new IOException("bad domain name: '" + buf + "' at " + off); + } + } + this.off = (next >= 0) ? next : off; + return buf.toString(); + } + + /** + * Debugging. + */ + String print(boolean dump) + { + StringBuffer buf = new StringBuffer(); + buf.append(toString() + "\n"); + for (Iterator iterator = questions.iterator(); iterator.hasNext();) + { + buf.append(" ques:" + iterator.next() + "\n"); + } + int count = 0; + for (Iterator iterator = answers.iterator(); iterator.hasNext(); count++) + { + if (count < numAnswers) + { + buf.append(" answ:"); + } + else + { + if (count < numAnswers + numAuthorities) + { + buf.append(" auth:"); + } + else + { + buf.append(" addi:"); + } + } + buf.append(iterator.next() + "\n"); + } + if (dump) + { + for (int off = 0, len = packet.getLength(); off < len; off += 32) + { + int n = Math.min(32, len - off); + if (off < 10) + { + buf.append(' '); + } + if (off < 100) + { + buf.append(' '); + } + buf.append(off); + buf.append(':'); + for (int i = 0; i < n; i++) + { + if ((i % 8) == 0) + { + buf.append(' '); + } + buf.append(Integer.toHexString((data[off + i] & 0xF0) >> 4)); + buf.append(Integer.toHexString((data[off + i] & 0x0F) >> 0)); + } + buf.append("\n"); + buf.append(" "); + for (int i = 0; i < n; i++) + { + if ((i % 8) == 0) + { + buf.append(' '); + } + buf.append(' '); + int ch = data[off + i] & 0xFF; + buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.'); + } + buf.append("\n"); + + // limit message size + if (off + 32 >= 256) + { + buf.append("....\n"); + break; + } + } + } + return buf.toString(); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + buf.append(isQuery() ? "dns[query," : "dns[response,"); + if (packet.getAddress() != null) + { + buf.append(packet.getAddress().getHostAddress()); + } + buf.append(':'); + buf.append(packet.getPort()); + buf.append(",len="); + buf.append(packet.getLength()); + buf.append(",id=0x"); + buf.append(Integer.toHexString(id)); + if (flags != 0) + { + buf.append(",flags=0x"); + buf.append(Integer.toHexString(flags)); + if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0) + { + buf.append(":r"); + } + if ((flags & DNSConstants.FLAGS_AA) != 0) + { + buf.append(":aa"); + } + if ((flags & DNSConstants.FLAGS_TC) != 0) + { + buf.append(":tc"); + } + } + if (numQuestions > 0) + { + buf.append(",questions="); + buf.append(numQuestions); + } + if (numAnswers > 0) + { + buf.append(",answers="); + buf.append(numAnswers); + } + if (numAuthorities > 0) + { + buf.append(",authorities="); + buf.append(numAuthorities); + } + if (numAdditionals > 0) + { + buf.append(",additionals="); + buf.append(numAdditionals); + } + buf.append("]"); + return buf.toString(); + } + + /** + * Appends answers to this Incoming. + * + * @throws IllegalArgumentException If not a query or if Truncated. + */ + void append(DNSIncoming that) + { + if (this.isQuery() && this.isTruncated() && that.isQuery()) + { + this.questions.addAll(that.questions); + this.numQuestions += that.numQuestions; + + if (Collections.EMPTY_LIST.equals(answers)) + { + answers = Collections.synchronizedList(new ArrayList()); + } + + if (that.numAnswers > 0) + { + this.answers.addAll(this.numAnswers, that.answers.subList(0, that.numAnswers)); + this.numAnswers += that.numAnswers; + } + if (that.numAuthorities > 0) + { + this.answers.addAll(this.numAnswers + this.numAuthorities, that.answers.subList(that.numAnswers, that.numAnswers + that.numAuthorities)); + this.numAuthorities += that.numAuthorities; + } + if (that.numAdditionals > 0) + { + this.answers.addAll(that.answers.subList(that.numAnswers + that.numAuthorities, that.numAnswers + that.numAuthorities + that.numAdditionals)); + this.numAdditionals += that.numAdditionals; + } + } + else + { + throw new IllegalArgumentException(); + } + } + + int elapseSinceArrival() + { + return (int) (System.currentTimeMillis() - receivedTime); + } +} Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSListener.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSListener.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSListener.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,24 @@ +//Copyright 2003-2005 Arthur van Hoff, Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + +package plugins.MDNSDiscovery.javax.jmdns; + +// REMIND: Listener should follow Java idiom for listener or have a different +// name. + +/** + * DNSListener. + * Listener for record updates. + * + * @author Werner Randelshofer, Rick Blair + * @version 1.0 May 22, 2004 Created. + */ +interface DNSListener +{ + /** + * Update a DNS record. + */ + void updateRecord(JmDNS jmdns, long now, DNSRecord record); +} Added: trunk/plugins/MDNSDiscovery/javax/jmdns/DNSOutgoing.java =================================================================== --- trunk/plugins/MDNSDiscovery/javax/jmdns/DNSOutgoing.java (rev 0) +++ trunk/plugins/MDNSDiscovery/javax/jmdns/DNSOutgoing.java 2007-03-04 15:23:01 UTC (rev 11954) @@ -0,0 +1,381 @@ +//Copyright 2003-2005 Arthur van Hoff, Rick Blair +//Licensed under Apache License version 2.0 +//Original license LGPL + + +package plugins.MDNSDiscovery.javax.jmdns; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An outgoing DNS message. + * + * @version %I%, %G% + * @author Arthur van Hoff, Rick Blair, Werner Randelshofer + */ +final class DNSOutgoing +{ + private static Logger logger = Logger.getLogger(DNSOutgoing.class.toString()); + int id; + int flags; + private boolean multicast; + private int numQuestions; + private int numAnswers; + private int numAuthorities; + private int numAdditionals; + private Hashtable names; + + byte data[]; + int off; + int len; + + /** + * Create an outgoing multicast query or response. + */ + DNSOutgoing(int flags) + { + this(flags, true); + } + + /** + * Create an outgoing query or response. + */ + DNSOutgoing(int flags, boolean multicast) + { + this.flags = flags; + this.multicast = multicast; + names = new Hashtable(); + data = new byte[DNSConstants.MAX_MSG_TYPICAL]; + off = 12; + } + + /** + * Add a question to the message. + */ + void addQuestion(DNSQuestion rec) throws IOException + { + if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0) + { + throw new IllegalStateException("Questions must be added before answers"); + } + numQuestions++; + writeQuestion(rec); + } + + /** + * Add an answer if it is not suppressed. + */ + void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException + { + if (numAuthorities > 0 || numAdditionals > 0) + { + throw new IllegalStateException("Answers must be added before authorities and additionals"); + } + if (!rec.suppressedBy(in)) + { + addAnswer(rec, 0); + } + } + + /** + * Add an additional answer to the record. Omit if there is no room. + */ + void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException + { + if ((off < DNSConstants.MAX_MSG_TYPICAL - 200) && !rec.suppressedBy(in)) + { + writeRecord(rec, 0); + numAdditionals++; + } + } + + /** + * Add an answer to the message. + */ + void addAnswer(DNSRecord rec, long now) throws IOException + { + if (numAuthorities > 0 || numAdditionals > 0) + { + throw new IllegalStateException("Questions must be added before answers"); + } + if (rec != null) + { + if ((now == 0) || !rec.isExpired(now)) + { + writeRecord(rec, now); + numAnswers++; + } + } + } + + private LinkedList authorativeAnswers = new LinkedList(); + + /** + * Add an authorative answer to the message. + */ + void addAuthorativeAnswer(DNSRecord rec) throws IOException + { + if (numAdditionals > 0) + { + throw new IllegalStateException("Authorative answers must be added before additional answers"); + } + authorativeAnswers.add(rec); + writeRecord(rec, 0); + numAuthorities++; + + // VERIFY: + + } + + void writeByte(int value) throws IOException + { + if (off >= data.length) + { + throw new IOException("buffer full"); + } + data[off++] = (byte) value; + } + + void writeBytes(String str, int off, int len) throws IOException + { + for (int i = 0; i < len; i++) + { + writeByte(str.charAt(off + i)); + } + } + + void writeBytes(byte data[]) throws IOException + { + if (data != null) + { + writeBytes(data, 0, data.length); + } + } + + void writeBytes(byte data[], int off, int len) throws IOException + { + for (int i = 0; i < len; i++) + { + writeByte(data[off + i]); + } + } + + void writeShort(int value) throws IOException + { + writeByte(value >> 8); + writeByte(value); + } + + void writeInt(int value) throws IOException + { + writeShort(value >> 16); + writeShort(value); + } + + void writeUTF(String str, int off, int len) throws IOException + { + // compute utf length + int utflen = 0; + for (int i = 0; i < len; i++) + { + int ch = str.charAt(off + i); + if ((ch >= 0x0001) && (ch <= 0x007F)) + { + utflen += 1; + } + else + { + if (ch > 0x07FF) + { + utflen += 3; + } + else + { + utflen += 2; + } + } + } + // write utf length + writeByte(utflen); + // write utf data + for (int i = 0; i < len; i++) + { + int ch = str.charAt(off + i); + if ((ch >= 0x0001) && (ch <= 0x007F)) + { + writeByte(ch); + } + else + { + if (ch > 0x07FF) + { + writeByte(0xE0 | ((ch >> 12) & 0x0F)); + writeByte(0x80 | ((ch >> 6) & 0x3F)); + writeByte(0x80 | ((ch >> 0) & 0x3F)); + } + else + { + writeByte(0xC0 | ((ch >> 6) & 0x1F)); + writeByte(0x80 | ((ch >> 0) & 0x3F)); + } + } + } + } + + void writeName(String name) throws IOException + { + while (true) + { + int n = name.indexOf('.'); + if (n < 0) + { + n = name.length(); + } + if (n <= 0) + { +