Author: zothar
Date: 2006-08-20 22:55:18 +0000 (Sun, 20 Aug 2006)
New Revision: 10219
Modified:
trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/PacketSender.java
trunk/freenet/src/freenet/node/PeerNode.java
Log:
Now N2NTMs can be sent to multiple peers at once and N2NTMs to disconnected
peers are queued until they connect. Theme owners should take a look as this
and my last commit probably need some fiddling to look right, etc. Calling
maybeOnConnect() from PacketSender seems like a hack, but calling onConnect()
from the end of completedHandshake() seemed unreliable, in that the queued
N2NTM didn't go through, but repeating the disconnect/connect cycle caused it
to go through. Perhaps another dev can improve on things.
Modified: trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-08-20 20:57:44 UTC (rev 10218)
+++ trunk/freenet/src/freenet/clients/http/DarknetConnectionsToadlet.java
2006-08-20 22:55:18 UTC (rev 10219)
@@ -339,7 +339,7 @@
peerRow.addChild("td", "class",
"peer-status").addChild("span", "class", peerNodeStatus.getStatusCSSName(),
statusString + (peerNodeStatus.isFetchingARK() ? "*" : ""));
// name column
- if (peerNodeStatus.isConnected() &&
(Integer.parseInt(peerNodeStatus.getSimpleVersion()) > 476)) {
+ if
(Integer.parseInt(peerNodeStatus.getSimpleVersion()) > 476) {
peerRow.addChild("td", "class",
"peer-name").addChild("a", "href", "/send_n2ntm/?peernode_hashcode=" +
peerNodeStatus.hashCode(), peerNodeStatus.getName());
} else {
peerRow.addChild("td", "class",
"peer-name").addChild("#", peerNodeStatus.getName()); // TODO: This branch can
probably be removed at some point
@@ -447,7 +447,7 @@
HTMLNode actionSelect = peerForm.addChild("select",
"name", "action");
actionSelect.addChild("option", "value", "", "-- Select
action --");
- //actionSelect.addChild("option", "value",
"send_n2ntm", "Send N2NTM to selected peers"); // Disabled until we have
queue-for-send-on-connect
+ actionSelect.addChild("option", "value", "send_n2ntm",
"Send N2NTM to selected peers");
actionSelect.addChild("option", "value",
"update_notes", "Update changed private notes");
if(advancedEnabled) {
actionSelect.addChild("option", "value",
"enable", "Enable selected peers");
Modified: trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2006-08-20
20:57:44 UTC (rev 10218)
+++ trunk/freenet/src/freenet/clients/http/N2NTMToadlet.java 2006-08-20
22:55:18 UTC (rev 10219)
@@ -13,9 +13,11 @@
import freenet.node.Node;
import freenet.node.NodeClientCore;
import freenet.node.PeerNode;
+import freenet.support.Base64;
import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.MultiValueTable;
+import freenet.support.SimpleFieldSet;
import freenet.support.io.Bucket;
public class N2NTMToadlet extends Toadlet {
@@ -130,9 +132,16 @@
try {
Message n2ntm =
DMT.createNodeToNodeTextMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT,
node.getMyName(), pn.getName(), message);
if(!pn.isConnected()) {
- sendStatusShort =
"Failed";
- sendStatusLong = "Not
connected: Message not sent to peer";
- sendStatusClass =
"n2ntm-send-failed";
+ sendStatusShort =
"Queued";
+ sendStatusLong =
"Queued: Peer not connected, so message queued for when it connects";
+ sendStatusClass =
"n2ntm-send-queued";
+ SimpleFieldSet fs = new
SimpleFieldSet();
+ fs.put("type",
Integer.toString(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT));
+
fs.put("source_nodename", Base64.encode(node.getMyName().getBytes()));
+
fs.put("target_nodename", Base64.encode(pn.getName().getBytes()));
+ fs.put("text",
Base64.encode(message.getBytes()));
+ pn.queueN2NTM(fs);
+ Logger.normal(this,
"Queued N2NTM to '"+pn.getName()+"': "+message);
} else
if(pn.getPeerNodeStatus() == Node.PEER_NODE_STATUS_ROUTING_BACKED_OFF) {
sendStatusShort =
"Delayed";
sendStatusLong =
"Backed off: Sending of message possibly delayed to peer";
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-08-20 20:57:44 UTC (rev
10218)
+++ trunk/freenet/src/freenet/node/Node.java 2006-08-20 22:55:18 UTC (rev
10219)
@@ -394,6 +394,7 @@
public static final int N2N_TEXT_MESSAGE_TYPE_USERALERT = 1;
public static final int EXTRA_PEER_DATA_TYPE_N2NTM = 1;
public static final int EXTRA_PEER_DATA_TYPE_PEER_NOTE = 2;
+ public static final int EXTRA_PEER_DATA_TYPE_QUEUED_TO_SEND_N2NTM = 3;
public static final int PEER_NOTE_TYPE_PRIVATE_DARKNET_COMMENT = 1;
public final long bootID;
Modified: trunk/freenet/src/freenet/node/PacketSender.java
===================================================================
--- trunk/freenet/src/freenet/node/PacketSender.java 2006-08-20 20:57:44 UTC
(rev 10218)
+++ trunk/freenet/src/freenet/node/PacketSender.java 2006-08-20 22:55:18 UTC
(rev 10219)
@@ -158,6 +158,7 @@
PeerNode pn = nodes[i];
lastReceivedPacketFromAnyNode =
Math.max(pn.lastReceivedPacketTime(),
lastReceivedPacketFromAnyNode);
+ pn.maybeOnConnect();
if(pn.isConnected()) {
if(pn.isRoutable() && pn.shouldDisconnectNow()) {
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2006-08-20 20:57:44 UTC
(rev 10218)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2006-08-20 22:55:18 UTC
(rev 10219)
@@ -127,6 +127,10 @@
*/
private boolean isConnected;
private boolean isRoutable;
+
+ /** Used by maybeOnConnect */
+ private boolean wasDisconnected;
+
/**
* ARK fetcher.
*/
@@ -277,6 +281,9 @@
/** Private comment on the peer for /darknet/ page's extra peer data file
number */
private int privateDarknetCommentFileNumber;
+ /** Queued-to-send N2NTM extra peer data file numbers */
+ private Vector queuedToSendN2NTMExtraPeerDataFileNumbers;
+
/**
* Create a PeerNode from a SimpleFieldSet containing a
* node reference for one. This must contain the following
@@ -515,12 +522,17 @@
// status may have changed from PEER_NODE_STATUS_DISCONNECTED to
PEER_NODE_STATUS_NEVER_CONNECTED
setPeerNodeStatus(now);
+ // Setup the private darknet comment note
privateDarknetComment = new String();
privateDarknetCommentFileNumber = -1;
// Setup the extraPeerDataFileNumbers
extraPeerDataFileNumbers = new Vector();
extraPeerDataFileNumbers.removeAllElements();
+
+ // Setup the queuedToSendN2NTMExtraPeerDataFileNumbers
+ queuedToSendN2NTMExtraPeerDataFileNumbers = new Vector();
+ queuedToSendN2NTMExtraPeerDataFileNumbers.removeAllElements();
}
private boolean parseARK(SimpleFieldSet fs, boolean onStartup) {
@@ -1378,6 +1390,9 @@
synchronized(this) {
sentInitialMessages = false;
}
+ if(isConnected()) {
+ onConnect();
+ }
return true;
}
@@ -2387,6 +2402,25 @@
return !gotError;
}
+ public boolean rereadExtraPeerDataFile(int fileNumber) {
+ String extraPeerDataDirPath = node.getExtraPeerDataDir();
+ File extraPeerDataPeerDir = new
File(extraPeerDataDirPath+File.separator+getIdentityString());
+ if(!extraPeerDataPeerDir.exists()) {
+ Logger.error(this, "Extra peer data directory for peer
does not exist: "+extraPeerDataPeerDir.getPath());
+ return false;
+ }
+ if(!extraPeerDataPeerDir.isDirectory()) {
+ Logger.error(this, "Extra peer data directory for peer
not a directory: "+extraPeerDataPeerDir.getPath());
+ return false;
+ }
+ File extraPeerDataFile = new
File(extraPeerDataDirPath+File.separator+getIdentityString()+File.separator+fileNumber);
+ if(!extraPeerDataFile.exists()) {
+ Logger.error(this, "Extra peer data file for peer does
not exist: "+extraPeerDataFile.getPath());
+ return false;
+ }
+ return readExtraPeerDataFile(extraPeerDataFile, fileNumber);
+ }
+
public boolean readExtraPeerDataFile(File extraPeerDataFile, int
fileNumber) {
boolean gotError = false;
if(!extraPeerDataFile.exists()) {
@@ -2465,6 +2499,41 @@
}
Logger.error(this, "Read unknown peer note type
'"+peerNoteType+"' from file "+extraPeerDataFile.getPath());
return false;
+ } else if(extraPeerDataType ==
Node.EXTRA_PEER_DATA_TYPE_QUEUED_TO_SEND_N2NTM) {
+ boolean sendSuccess = false;
+ if(isConnected()) {
+ String source_nodename = null;
+ String target_nodename = null;
+ String text = null;
+ try {
+ source_nodename = new
String(Base64.decode(fs.get("source_nodename")));
+ target_nodename = new
String(Base64.decode(fs.get("target_nodename")));
+ text = new
String(Base64.decode(fs.get("text")));
+ } catch (IllegalBase64Exception e) {
+ Logger.error(this, "Bad Base64 encoding
when decoding a N2NTM SimpleFieldSet", e);
+ return false;
+ }
+ Message n2ntm =
DMT.createNodeToNodeTextMessage(Node.N2N_TEXT_MESSAGE_TYPE_USERALERT,
source_nodename, target_nodename, text);
+ try {
+ node.usm.send(this, n2ntm, null);
+ Logger.normal(this, "Sent N2NTM to
'"+getName()+"': "+text);
+ sendSuccess = true;
+
synchronized(queuedToSendN2NTMExtraPeerDataFileNumbers) {
+
if(queuedToSendN2NTMExtraPeerDataFileNumbers.contains(new Integer(fileNumber)))
{
+
queuedToSendN2NTMExtraPeerDataFileNumbers.addElement(new Integer(fileNumber));
+ }
+ }
+ deleteExtraPeerDataFile(fileNumber);
+ } catch (NotConnectedException e) {
+ sendSuccess = false; // redundant, but
clear
+ }
+ }
+ if(!sendSuccess) {
+
synchronized(queuedToSendN2NTMExtraPeerDataFileNumbers) {
+
queuedToSendN2NTMExtraPeerDataFileNumbers.addElement(new Integer(fileNumber));
+ }
+ }
+ return true;
}
Logger.error(this, "Read unknown extra peer data type
'"+extraPeerDataType+"' from file "+extraPeerDataFile.getPath());
return false;
@@ -2617,4 +2686,42 @@
rewriteExtraPeerDataFile(fs,
Node.EXTRA_PEER_DATA_TYPE_PEER_NOTE, localFileNumber);
}
}
+
+ public void queueN2NTM(SimpleFieldSet fs) {
+ int fileNumber = writeNewExtraPeerDataFile( fs,
Node.EXTRA_PEER_DATA_TYPE_QUEUED_TO_SEND_N2NTM);
+ synchronized(queuedToSendN2NTMExtraPeerDataFileNumbers) {
+
queuedToSendN2NTMExtraPeerDataFileNumbers.addElement(new Integer(fileNumber));
+ }
+ }
+
+ public void sendQueuedN2NTMs() {
+ Integer[] localFileNumbers = null;
+ synchronized(queuedToSendN2NTMExtraPeerDataFileNumbers) {
+ localFileNumbers = (Integer[])
queuedToSendN2NTMExtraPeerDataFileNumbers.toArray(new
Integer[queuedToSendN2NTMExtraPeerDataFileNumbers.size()]);
+ }
+ Arrays.sort(localFileNumbers);
+ for (int i = 0; i < localFileNumbers.length; i++) {
+ rereadExtraPeerDataFile(localFileNumbers[i].intValue());
+ }
+ }
+
+ public void maybeOnConnect() {
+ if(wasDisconnected && isConnected()) {
+ synchronized(this) {
+ wasDisconnected = false;
+ }
+ onConnect();
+ } else if(!isConnected()) {
+ synchronized(this) {
+ wasDisconnected = true;
+ }
+ }
+ }
+
+ /**
+ * A method to be called once at the beginning of every time
isConnected() is true
+ */
+ private void onConnect() {
+ sendQueuedN2NTMs();
+ }
}