Source code: Freenet/message/Request.java
1 package Freenet.message;
2 import Freenet.*;
3 import Freenet.node.*;
4 import Freenet.support.*;
5 import java.util.*;
6
7 public abstract class Request extends Message {
8
9 public Key searchKey;
10
11 public Request(long idnum, long htl, long depth, Key key)
12 {
13 super(idnum, htl, depth);
14 searchKey=key;
15 }
16
17 public Request(RawMessage raw) throws InvalidMessageException
18 {
19 super(raw);
20 searchKey=new StringKey(popField("SearchKey"));
21 if(searchKey.toString()==null) throw new InvalidMessageException
22 ("Can't find SearchKey field");
23 }
24
25 public RawMessage toRawMessage()
26 {
27 RawMessage raw=super.toRawMessage();
28 raw.setField("SearchKey", searchKey.toString());
29 return raw;
30 }
31
32 /**
33 * Called by a node after it receives this message
34 * @param n The node that called this message. This should be used
35 * to make any nescessary modifications to the DataStore etc.
36 * @param sb Null unless this node has been seen before. If non-null it
37 * is the Object returned by the received method of the
38 * last message seen with this ID.
39 * @return The object to be passed to any messages received in the near
40 * future with the same ID as this one. Null if no object should
41 * be passed.
42 **/
43 public MessageMemory pReceived(Node n, MessageMemory sb)
44 {
45 if(sb!=null) // Uh-oh! Must be a loop.
46 {
47 Logger.log("message/Request","loop - backtracking",Logger.MINOR);
48 RequestFailed rf=new RequestFailed(id, hopsToLive);
49 try {
50 sendReply(n, rf);
51 // we expect no further connections from this node, so we close the connection after sending
52 } catch(SendFailedException sfe) {
53 Logger.log("message/Request.java","Return to " + sfe.peer + " failed on loop",Logger.NORMAL);
54 }
55 return sb;
56 }
57
58 Data data;
59 Address ref;
60
61 if ((data=n.ds.searchData(searchKey))!=null) { // I have the data
62 try {
63 dataFound(data, n);
64 } catch (RequestAbortException rae) {
65 return rae.mm;
66 }
67 } else if ((ref=n.ds.searchRef(searchKey))!=null) { // Reference found
68 try {
69 refFound(ref, n);
70 } catch (RequestAbortException rae) {
71 return rae.mm;
72 }
73 }
74
75
76 // Going on forward the query
77 Logger.log("message/Request.java","Forwarding query for " + searchKey,Logger.MINOR);
78 Address addr; boolean failed;
79
80 KeyedMM kmm=new KeyedMM(source, depth, receivedWith, searchKey, null, this.getClass());
81
82 do { // until the send doesn't fail
83 do { // until the reference isn't back or used
84 kmm.lastAttempt=n.ds.findClosestKey(searchKey,kmm.lastAttempt);
85 addr=n.ds.searchRef(kmm.lastAttempt);
86 } while (addr != null && (addr.equals(kmm.origRec)
87 || kmm.usedAddresses.contains(addr)) );
88
89 if(kmm.lastAttempt==null) // Out of references
90 {
91 Logger.log("message/Request.java","No more nodes to send " + Long.toHexString(id) + " to, returning to " + kmm.origRec,Logger.MINOR);
92 RequestFailed rf=new RequestFailed(id, hopsToLive);
93 try {
94 rf.sendBack(n,kmm);
95 } catch(SendFailedException sfe) {
96 Logger.log("message/Request.java","Return to " + sfe.peer + " failed on no more references",Logger.NORMAL);
97 }
98 return kmm;
99 }
100
101 // mark that we've already tried to send to this address
102 kmm.usedAddresses.addElement(addr);
103
104 failed = false;
105 try {
106 Logger.log("message/Request.java","Forwarding query to " + addr,Logger.MINOR);
107 ConnectionHandler ch = n.makeConnection(addr);
108 sending(n, ch);
109 ch.sendMessage(this, null, null);
110 } catch(ConnectFailedException cfe) {
111 failed = true;
112 } catch(SendFailedException sfe) {
113 failed = true;
114 }
115 } while (failed);
116
117 kmm.lastAddr = addr;
118
119 // add a timer callback to time out on no reply
120 Node.timer.add(id, hopsToLive * Node.timePerHop, new RequestCB(n, kmm, id, hopsToLive));
121
122 return kmm;
123 }
124
125 /*
126 * method should is called when RequestFailed times out. It should be
127 * overwritten to mirror the different timeout behaviour of
128 * different requests
129 */
130
131 public static KeyedMM failedTimedOut(Node n, long id, KeyedMM kmm) {
132 Logger.log("message/Request.java","right right right",Logger.DEBUGGING);
133 // Cancel existing timeout
134 n.timer.cancel(id);
135
136 TimedOut to=new TimedOut(id, kmm.depth);
137
138 try {
139 to.sendBack(n, kmm);
140 } catch(SendFailedException sfe) {
141 Logger.log("Request.java","Sending of timeout to Failed message failed",Logger.NORMAL);
142 }
143 return null;
144 }
145
146 //Private & Protected methods
147
148 public static class RequestAbortException extends Exception {
149 MessageMemory mm;
150 public RequestAbortException(MessageMemory mm) {
151 this.mm = mm;
152 }
153 }
154
155
156 /*
157 * This method is called if a ref is found to the searchkey of the
158 * the request. To abort the current request, throw a RequestAbortException
159 * containing the MM to be returned.
160 */
161 protected abstract void refFound(Address ref, Node n) throws RequestAbortException;
162 /*
163 * This method is called if data is found to the searchkey of the
164 * the request. To abort the current request, throw a RequestAbortException
165 * containing the MM to be returned.
166 */
167 protected abstract void dataFound(Data data, Node n) throws RequestAbortException;
168
169 protected MessageMemory timeOut(Node n, MessageMemory mm) {
170
171 Data data;
172 Address ref;
173
174 if ((data=n.ds.searchData(searchKey))!=null) { // I have the data
175 try {
176 dataFound(data, n);
177 } catch (RequestAbortException rae) {
178 return rae.mm;
179 }
180 } else if ((ref=n.ds.searchRef(searchKey))!=null) { // Reference found
181 try {
182 refFound(ref, n);
183 } catch (RequestAbortException rae) {
184 return rae.mm;
185 }
186 }
187 if (mm != null && mm instanceof KeyedMM)
188 ((KeyedMM) mm).pending = false;
189
190 return super.timeOut(n, mm);
191 }
192 }
193