Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Freenet/Message.java


1   package Freenet;
2   import Freenet.node.*;
3   import Freenet.message.TimedOut;
4   import Freenet.support.*;
5   import java.lang.reflect.*;
6   import java.net.*;
7   import java.util.Hashtable;
8   import java.util.Enumeration;
9   /*
10    This code is part of the Java Adaptive Network Client by Ian Clarke. 
11    It is distributed under the GNU Public Licence (GPL) version 2.  See
12    http://www.gnu.org/ for further details of the GPL.
13  
14    Explanation of Code Versions: 
15      0.0.0      = Initial Description
16      0.0.1      = API Specified
17      0.x (x>0)  = Partial Implementation
18      x.0 (x>0)  = Operational
19                  
20    Requires Classes: Node (1.0)
21                      Address (1.0)
22   */
23  
24  /**
25   * This is the abstract superclass of all messages
26   *
27   * @see Node
28   * @see Address
29   * @author Brandon Wiley (blanu@uts.cc.utexas.edu)
30   * @author Ian Clarke (I.Clarke@strs.co.uk)
31   **/
32  
33  public abstract class Message
34  {
35      public static final String messageName="";
36  
37    /** The Address of the node where this message originated **/
38    public Address source;
39      /** Address of this node on the network that this message came from **/
40      public Address receivedAt = null;
41      /** ConnectionHandler that accepted that received message **/
42      public ConnectionHandler receivedWith = null;
43    /** The number of times this message should be forwarded before
44        generating a TimedOutMessage **/
45    public long hopsToLive;
46      /** The number number of hops this message is from its originating node **/
47      public long depth;
48    /** A randomly generated unique ID used to identify related messages **/
49    public long id;
50      /** Whether the connection should be kept open after sending this **/
51      public boolean keepAlive = true;
52  
53      /** Any unknown / unused fields **/
54      private Hashtable otherFields = new Hashtable();
55      protected String popField(String s) {String rs = (String) otherFields.get(s);otherFields.remove(s);return rs;}
56  
57  
58    public Message(long idnum, long htl, long dpth)
59      {
60        id=idnum;
61        hopsToLive=htl;
62        depth=dpth;
63      }
64  
65    public Message(RawMessage raw) throws InvalidMessageException
66    {
67        try {
68  
69      for (Enumeration e = raw.fieldNames(); e.hasMoreElements();) {
70          String key = (String) e.nextElement();
71          otherFields.put(key, raw.readField(key));
72      }
73      id=hextolong(popField("UniqueID"));
74      hopsToLive= Long.parseLong(popField("HopsToLive"));
75      depth=Long.parseLong(popField("Depth"));
76      popField("KeepAlive"); // this is not preserved
77        // Source is not set by the other constructer, so I'll be consistant, and take it away here (it is set by a call to initSources() or sending()) 
78        //  source = raw.readField("Source") == null ? null : new Address(raw.readField("Source"));
79        } catch (ClassCastException e) {
80      throw new InvalidMessageException("Bad field");
81        } catch (NumberFormatException e) {
82      throw new InvalidMessageException("Bad number");
83        }
84    }
85  
86  /* I know, you're thinking Brandon, why don't you use Long.valueOf(hex,
87  16). Well, because Long.toHexString() generates unsigned values and
88  Long.valueOf expects a signed value. So if you know the elegant way to do
89  this, please tell me. It's one line in C and Python. */
90    private long hextolong(String hex) throws NumberFormatException
91    {
92      long l=0;
93      char c;
94  
95      int len=hex.length();
96      int p=len-1;
97  
98      for (int i=0; i<len; i++) {
99        c=hex.charAt(i);
100       if((c>='0')&&(c<='9'))       l=l+((c-'0')*(long)Math.pow(16,p-i));
101       else if ((c>='a')&&(c<='f')) l=l+((c-'a'+10)*(long)Math.pow(16,p-i));
102       else if ((c>='A')&&(c<='F')) l=l+((c-'A'+10)*(long)Math.pow(16,p-i));
103       else throw new NumberFormatException();
104     }
105     return l;
106   }
107 
108   public RawMessage toRawMessage()
109     {
110       RawMessage r = new RawMessage("");
111       r.trailingFieldName="EndMessage";
112       r.setField("UniqueID", Long.toHexString(id));
113       r.setField("HopsToLive", String.valueOf(hopsToLive));
114       r.setField("Depth", String.valueOf(depth));
115       r.setField("Source", source.toString());
116  
117       for (Enumeration e = otherFields.keys(); e.hasMoreElements();) {
118     String key = (String) e.nextElement();
119     r.setField(key, (String) otherFields.get(key));
120       }
121       if (!keepAlive)
122     r.setField("KeepAlive","false");
123       return r;
124     }
125 
126 
127     /** 
128      * Called by the connection handler after right constructing
129      * the message, while still in touch with the connection
130      * @param me The address of this node that the message was
131      *           received on.
132      * @param peer The address of the node the message was received
133      *             from.
134      **/
135 
136     public void initSources(Address me, Address peer, ConnectionHandler ch)
137     {
138   receivedAt = me;
139   source = peer;
140   receivedWith = ch;
141     }
142 
143   /**
144    * Called by a node after this message is received.  This allows
145    * message handling code to be packaged within the message class
146    * that is being handled.
147    * @param n The node that called this message.  This should be used
148    *          to make any nescessary modifications to the DataStore etc.
149    * @param sb Null unless this node has been seen before.  If non-null it
150    *           is the Object returned by the received method of the
151    *           last message seen with this ID.
152    * @return The object to be passed to any messages received in the near
153    *         future with the same ID as this one.  Null if no object 
154    *         should be passed.
155    **/
156   public final MessageMemory received(Node n, MessageMemory sb)
157     { 
158   // Reduce the lifespan of this message
159   hopsToLive--;
160   
161   if(hopsToLive<=0) { // Message expired. Inform sender.
162       return timeOut(n, sb);
163   } else {
164       // Increase the depth
165       depth++;
166       return pReceived(n, sb); // Actually do something with the message
167   }
168     }
169 
170     public void sending(Core n, ConnectionHandler ch) throws SendFailedException {
171   sending(n,ch.peer(),ch.local(n.myAddress));
172     }
173 
174     /**
175      * Called just before the message is sent, and makes any last minute
176      * changes.
177      *
178      * @param n          The node that is sending the message
179      * @param peer       The address to which the message is being sent
180      * @param myAddress  The sending nodes address with respect to peer
181      **/
182 
183     public void sending(Core n, Address peer, Address myAddress) throws SendFailedException
184     {
185   if (myAddress.equals(peer))
186       throw new SendFailedException(peer); // don't send to yourself
187   source = myAddress;
188     }
189 
190   /**
191    * An overridable version of the received message.
192    * @param n The node that called this message.  This should be used
193    *          to make any nescessary modifications to the DataStore etc.
194    * @param sb Null unless this node has been seen before.  If non-null it
195    *           is the Object returned by the received method of the
196    *           last message seen with this ID.
197    * @return The object to be passed to any messages received in the near
198    *         future with the same ID as this one.  Null if no object 
199    *         should be passed.
200    **/
201 
202     abstract protected MessageMemory pReceived(Node n, MessageMemory sb);
203 
204 
205     protected MessageMemory timeOut(Node n, MessageMemory sb)
206     {
207   Logger.log("Message.java","Message timed out, sending timeout to original source",Logger.MINOR);
208   TimedOut to=new TimedOut(id, depth); // this message is going in
209     
210   try {
211       (sendReply(n,to)).close();
212   } catch(SendFailedException sfe) {
213       Logger.log("Message.java","Send of timeout failed",Logger.NORMAL);
214   }
215   
216   return sb;
217     }
218     
219     /**
220      * Sends a message back to the node from which this message was received.
221      * If a connection is open, that will be used, otherwise a new one opened
222      * @param n this node
223      * @param m the message to send.
224      * @return if there was an open connection back, or if there was a
225      *         a connection back that was closed, the connection over which
226      *         the message was sent is returned. If there was no connection
227      *         back, the new connection is closed after send, and null
228      *         is returned.
229      *         
230      **/
231 
232     protected ConnectionHandler sendReply(Node n, Message m) throws SendFailedException {
233   try {
234       ConnectionHandler ch;
235       if (receivedWith == null) {
236     ch = n.makeConnection(source);
237     m.keepAlive = false; // close again after sending message
238       } else if (!receivedWith.isOpen())
239     ch = n.makeConnection(source);
240       else 
241     ch = receivedWith;
242 
243       m.sending(n, receivedWith);
244       receivedWith.sendMessage(m);
245 
246       return receivedWith == null ? null : ch;
247   } catch (ConnectFailedException e) {
248       throw new SendFailedException(e.peer);
249   }
250     }
251 
252     /**
253      * Sends this message back to the node from which the chain was originally
254      * received.
255      * @param n   this node.
256      * @param mm  The MessageMemory for this chain of messages.
257      * @return    If there was an open connection back in the MessageMemory,
258      *            or if there was a connection back that had been closed,
259      *            the connection which this message is sent on is returned. 
260      *            If there was no  connection back stored, null is returned.
261      **/
262 
263     public ConnectionHandler sendBack(Node n, MessageMemory mm) throws SendFailedException {
264   try {
265       ConnectionHandler ch;
266       if (mm.replyCon == null) {
267     ch = n.makeConnection(mm.origRec);
268     keepAlive = false;
269       } else if (!mm.replyCon.isOpen()) {
270     ch = n.makeConnection(mm.origRec);
271       } else {
272     ch = mm.replyCon;
273       }
274       sending(n, ch);
275       ch.sendMessage(this, null, null);
276       return mm.replyCon == null ? null : ch;
277   } catch (ConnectFailedException e) {
278       throw new SendFailedException(e.peer);
279   }
280     }
281 
282     public String toString()
283     {
284   //        RawMessage r = toRawMessage();
285   return "Src:"+source+" htl:"+hopsToLive+
286       " depth:" + depth + " id:"+Long.toHexString(id) +
287       " type:" + this.getClass().getName();
288     }
289 }
290 
291