Lots of fresh code! You have been warned!!! Do pls report trouble!
[android6bed4] / src / nl / openfortress / android6bed4 / NeighborCache.java
1 package nl.openfortress.android6bed4;
2
3
4 import java.util.Hashtable;
5 import java.util.Queue;
6 import java.util.ArrayDeque;
7
8 import java.net.DatagramPacket;
9 import java.net.DatagramSocket;
10 import java.net.InetSocketAddress;
11 import java.net.Inet4Address;
12 import java.net.UnknownHostException;
13
14 import java.io.IOException;
15
16
17
18 /* The Neighbor Cache is modelled in Java, because Android/Java won't
19  * give access to the network stack.
20  * 
21  * The primary task of the cache is to map IPv6-addresses in byte [16]
22  * format to a destination, which is stored as a Inet4SocketAddress
23  * for direct use with DatagramPacket facilities in Java.  A hash is
24  * used to gain fast access to the target object.
25  * 
26  * To find mappings, the cache will send up to 3 Neighor Solicitation
27  * messages to the direct peer.  During this period it will pass through
28  * states ATTEMPT1 to ATTEMPT3, and finally become FAILED.  This is a sign
29  * that no further attempts need to be made until the expiration of the
30  * mapping, about 30 seconds after starting it.  This process starts
31  * when an unknown peer is approached, or one that is STALE.
32  * 
33  * If a Neighbor Advertisement comes in, this information is sent here
34  * for processing.  The cache entry will usually go to REACHABLE in such
35  * situations.
36  * 
37  * When traffic comes in with the direct address of this peer as its
38  * destination, then the cache is informed; if no mapping in REACHABLE
39  * state exists, then new attempts are started, so as to enable direct
40  * connectivity after the remote peer has opened a hole to us.
41  * 
42  * The cache maintains a seperate timer queue for each state, and will
43  * act upon the objects if they expire.  This makes the queue rather
44  * self-controlled.
45  * 
46  * Before changing any piece of this code, please assure yourself that
47  * you understand each single synchronized section, and convince
48  * yourself that you understand the trick in NeighborQueue.dequeue().
49  * This is not just multitasking code; it may well be the most complex
50  * example of multitasking code that you ever came accross.  Do not
51  * change the code unless you are absolutely certain that you have
52  * understood all the invariants that make this code work!
53  */
54
55 class NeighborCache {
56         
57         /* The states of neighbors in the cache.
58          */
59         public final static int ATTEMPT1 = 0;           /* Discovery sequence */
60         public final static int ATTEMPT2 = 1;
61         public final static int ATTEMPT3 = 2;
62         public final static int FAILED = 3;
63         public final static int REACHABLE = 4;          /* Confirmed in the last ~30s */
64         public final static int STALE = 5;                      /* Not used for up to ~30s */
65         public final static int NUM_NGB_STATES = 6;     /* Count of normal states */
66         public final static int INTRANSIT = 7;          /* Traveling between queues */
67         
68         
69         /* The timing spent in the various states of a cache entry.  Stable states
70          * take up several seconds, while waiting for a response is faster.
71          * Note the remarks at NeighborQueue.dequeue() for an important constraint;
72          * specifically, STALE is spent in an attempt to recycle an entry as
73          * REACHABLE, so the time spent in STALE must not exceed the time spent
74          * in REACHABLE.  This avoids having two entries for one neighbor in a
75          * queue, which would jeapourdise the timeout calculations.  Note that
76          * this problem does not arise when an object occurs in multiple queues
77          * at once, because a mismatch with the queue's state means that those
78          * lingering neighbors are ignored as timeout sources.
79          * 
80          * TODO: I found that Android can be pretty slow in responding over eth0,
81          * possibly worse over UMTS or (shiver) GPRS.  So, it may be that the
82          * following timing must be slowed down, *or* that NgbAdv ought to be
83          * accepted in the STALE state.
84          */
85         final static int state_timing_millis [] = {
86                         50, 50, 50, 30000,                              /* Discovery -- a few ms between steps */
87                         27500,                                                  /* STALE -- 30 additional seconds */
88                         30000                                                   /* REACHABLE -- 30 seconds of bliss */
89         };
90         
91         /* The timer queues for neighbor discovery, each in its own thread */
92         NeighborQueue queues [];
93         
94         /* The neighbor cache contains all elements, regardless of their state.
95          * This is needed to avoid doing double work.  If a neighbor is considered
96          * to be available, then it should be in here.  Once it stops being of
97          * interest (STALE or FAILED expires) it will be removed.
98          * 
99          * Note that the key and value are both Neighbor objects.  The only part
100          * of the Neighbor dictating equality (and the hashCode) is the 6-byte
101          * key holding the remote peer's IPv4 address and UDP port, so it is
102          * possible to put one object into the Hashtable as both key and value;
103          * and then to lookup an entry with a minimally setup Neighbor as key
104          * to find a more evolved value; the latter will be incorporated into
105          * the procedures of the Neighbor Cache, including the various queues.
106          */
107         private Hashtable <Integer, Neighbor> neighbor_cache;
108         
109         
110         /* The public server, used as default return value for queires after
111          * unsettled neighbor cache entries.
112          */
113         private InetSocketAddress public_server;
114         
115         
116         /* The socket used as uplink to the rest of the 6bed4-using World.
117          */
118         private DatagramSocket uplink;
119         
120         
121         /* The 6bed4 address as a 16-byte array; may also be used as an 8-byte prefix.
122          */
123         private byte address_6bed4 [];
124         
125         /* The 6bed4 address as a 6-byte key.
126          */
127         private byte address_6bed4_key [];
128         
129         
130         /* Construct a neighbor cache with no entries but a lot of structure */
131         public NeighborCache (DatagramSocket ipv4_uplink, InetSocketAddress pubserver, byte link_address_6bed4 []) {
132                 uplink = ipv4_uplink;
133                 public_server = pubserver;
134                 address_6bed4 = new byte [16];
135                 TunnelService.memcp_address (address_6bed4, 0, link_address_6bed4, 0);
136                 address_6bed4_key = new byte [6];
137                 address2key (address_6bed4, 0, address_6bed4_key);
138                 queues = new NeighborQueue [NUM_NGB_STATES];
139                 for (int i=0; i < NUM_NGB_STATES; i++) {
140                         queues [i] = new NeighborQueue (this, i);
141                 }
142                 neighbor_cache = new Hashtable <Integer,Neighbor> ();
143         }
144
145         /* Remove an expired entry from the neighbor cache.
146          */
147         public void remove_from_cache (Neighbor ngb) {
148                 byte key [] = new byte [6];
149                 socketaddress2key (ngb.target, key);
150                 synchronized (neighbor_cache) {
151                         neighbor_cache.remove (key);
152                 }
153         }
154         
155         /* Attempt to retrieve an entry from the neighbor cache.  The resulting
156          * actions as well as the return value may differ, depending on the
157          * state of the cache entry.  This function always returns immediately,
158          * with the tunnel server as a default response for instant connections,
159          * but the cache may asynchronously attempt to find a direct path to the
160          * neighbor.
161          * 
162          * The "playful" argument is rather special.  When set to true, it
163          * indicates that an initial experiment attempting to contact the
164          * neighbor directly is acceptable.  This is usually the cae if the
165          * following conditions apply:
166          *  1. The message is resent upon failure
167          *  2. Success can be recognised and reported back here
168          *  Setting this flag causes the first (and only the first) result
169          *  from lookup_neighbor to point directly to the host; resends will
170          *  be sent through the tunnel, while a few neighbor discoveries are
171          *  still tried towards the remote peer, until something comes back
172          *  directly to acknowledge contact.  When something comes back over
173          *  a direct route, this should be reported to the neighbor cache
174          *  through received_peer_direct_acknowledgement() so it can
175          *  learn that future traffic can be directly sent to the peer.
176          *  
177          * A common case for which this holds is TCP connection setup:
178          *  1. Packets with SYN are sent repeatedly if need be
179          *  2. Packets with ACK stand out in a crowd
180          * So, when TCP packets with SYN are sent, their lookup_neighbor()
181          * invocation can set the playful flag; the first attempt will go
182          * directly to the peer and hopefully initiate direct contact; if
183          * not, future attempts are sent through the tunnel.  When the
184          * remote peer accepts, it will return a packet with ACK set over
185          * the direct route, which is enough reason to signal success to
186          * the neighbor cache.  Interestingly, the first reply message
187          * from a TCP server will generally hold the SYN flag as well, so
188          * if the remote 6bed4 stack is also playful about TCP, it is
189          * likely to send it back directly even if it received the opening
190          * SYN through the tunnel.  This means that even a blocking NAT on
191          * the remote end will cause a new attempt on return.  As usual,
192          * an ACK from client to server follows, which asserts to the
193          * server that it can talk directly (because, at that time, the
194          * client has picked up on the directly sent SYN+ACK).
195          * 
196          * It is possible for TCP to initiate a connection from both ends
197          * at the same time.  Effectively this splits the SYN+ACK into
198          * two messages, one with SYN and one with ACK.  It may happen
199          * that direct contact is not correctly established if that is
200          * done, but the follow-up neighbor discovery that follow on a
201          * playful SYN that does not return an ACK over the direct route
202          * will establish NAT-passthrough if it is technically possible.
203          * A similar thing occurs when the initial SYN is lost for some
204          * reason. 
205          */
206         public InetSocketAddress lookup_neighbor (byte addr [], int addrofs, boolean playful) {
207                 if (!is6bed4 (addr, addrofs)) {
208                         return public_server;
209                 }
210                 boolean puppy = false;
211                 Neighbor ngb;
212                 byte seeker_key [] = new byte [6];
213                 address2key (addr, addrofs, seeker_key);        //TODO// Only used for seeker creation?
214                 int seeker_hash = key2hash (seeker_key);
215                 synchronized (neighbor_cache) {
216                         ngb = neighbor_cache.get (seeker_hash);
217                         if (ngb == null) {
218                                 ngb = new Neighbor (seeker_key, playful);       //TODO// Possibly seeker.clone ()
219                                 neighbor_cache.put (seeker_hash, ngb);
220                                 puppy = true;
221                         }
222                 }
223                 switch (ngb.state) {
224                 case ATTEMPT1:
225                 case ATTEMPT2:
226                 case ATTEMPT3:
227                 case FAILED:
228                 case INTRANSIT:
229                         //
230                         // No usable entry exists, but no new attempts are needed.
231                         // Simply return the default router's address.
232                         //
233                         // If the new entry was just inserted into the neighbor
234                         // cache for this thread, then enqueue into ATTEMPT1, part
235                         // of which is sending a neighbor solicitation.  However,
236                         // if the  request is made by a playful puppy, then skip
237                         // sending the Neighbor Discovery upon insertion into the
238                         // ATTEMPT1 queue; the 6bed4 stack will instead send the
239                         // initial message directly to the peer.  To that end, return
240                         // the direct neighbor instead of the safe default of the
241                         // public server.  Note that a repeat of the packet will
242                         // no longer count as a puppy, so this is done only once.
243                         if (puppy) {
244                                 queues [ATTEMPT1].enqueue (ngb, playful);
245                                 if (playful) {
246                                         return ngb.target;
247                                 }
248                         }
249                         return public_server;
250                 case STALE:
251                         //
252                         // The neighbor has been reached directly before; assume this
253                         // is still possible (continue into REACHABLE) but also send a
254                         // neighbor solicitation to keep the lines open.
255                         solicit_neighbor (ngb);
256                 case REACHABLE:
257                         //
258                         // The neighbor is known to be available for direct contact.
259                         // There is no work to be done to that end.
260                         return ngb.target;
261                 default:
262                         return public_server;
263                 }
264         }
265         
266         /* Send a Neighbor Solicitation to the peer.  When this succeeds at
267          * penetrating to the remote peer's 6bed4 stack, then a Neighbor
268          * Advertisement will return, and be reported through the method
269          * NeighborCache.received_peer_direct_acknowledgement() so the
270          * cache can update its state, and support direct sending to the
271          * remote peer.  
272          * 
273          * Even though this kind of message may be sent after failed
274          * playful attempts, it still does not rule out the possibility
275          * of any such attempts returning, so the "playful" flag for
276          * the Neighbor solicited is not changed.
277          */
278         public void solicit_neighbor (Neighbor ngb) {
279                 byte key [] = new byte [6];
280                 socketaddress2key (ngb.target, key);
281                 byte ngbsol [] = new byte [72];
282                 //
283                 // IPv6 header:
284                 ngbsol [0] = 0x60;
285                 ngbsol [1] = ngbsol [2] = ngbsol [3] = 0;
286                 ngbsol [4] = 0; ngbsol [5] = 4 + 28;
287                 ngbsol [6] = TunnelService.IPPROTO_ICMPV6;
288                 ngbsol [7] = (byte) 255;
289                 TunnelService.memcp_address (ngbsol, 8, address_6bed4, 0);
290                 key2ipv6address (key, ngbsol, 24);
291                 int ofs = 40;
292                 // ICMPv6 header:
293                 ngbsol [ofs++] = (byte) TunnelService.ND_NEIGHBOR_SOLICIT;
294                 ngbsol [ofs++] = 0;
295                 ofs += 2;       // Checksum
296                 ngbsol [ofs++] =
297                 ngbsol [ofs++] =
298                 ngbsol [ofs++] =
299                 ngbsol [ofs++] = 0x00;
300                 key2ipv6address (ngb.key, ngbsol, ofs);
301                 ofs += 16;
302                 // ICMPv6 Option: Source Link-Layer Address
303                 ngbsol [ofs++] = 1;     // SrcLLAddr
304                 ngbsol [ofs++] = 1;     // length is 1x 8 bytes
305                 for (int i=0; i<6; i++) {
306                         ngbsol [ofs++] = address_6bed4_key [i];
307                 }
308                 int csum = TunnelService.checksum_icmpv6 (ngbsol, 0);
309                 ngbsol [42] = (byte) ((csum >> 8) & 0xff);
310                 ngbsol [43] = (byte) ( csum       & 0xff);
311                 try {
312                         DatagramPacket pkt = new DatagramPacket (ngbsol, ngbsol.length, ngb.target);
313                         uplink.send (pkt);
314                 } catch (IOException ioe) {
315                         ;
316                 }
317         }
318         
319         /* The TunnelServer reports having received a neighbor advertisement
320          * by calling this function.  This may signal the cache that the
321          * corresponding cache entry needs updating.
322          * 
323          * The "playful" flag is used to indicate that the acknowledgement
324          * arrived as part of a playful attempt in lookup_neighbor().  This
325          * information is used to determine if resends have taken place
326          * through the tunnel server.  If such resends were sent, then it
327          * is not safe anymore to assume that a one-to-one exchange has
328          * taken place, and it becomes necessary to rely on the generic
329          * mechanism of Neighbor Discovery to detect the ability for direct
330          * contact between peers.
331          */
332         public void received_peer_direct_acknowledgement (byte addr [], int addrofs, boolean playful) {
333                 Neighbor ngb;
334                 byte key [] = new byte [6];
335                 address2key (addr, addrofs, key);
336                 int seeker_hash = key2hash (key);
337                 synchronized (neighbor_cache) {
338                         ngb = neighbor_cache.get (seeker_hash);
339                 }
340                 if (ngb == null) {
341                         return;
342                 }
343                 if (playful && !ngb.playful) {
344                         return;
345                 }
346                 int nst = ngb.state;
347                 switch (nst) {
348                 case ATTEMPT1:
349                 case ATTEMPT2:
350                 case ATTEMPT3:
351                 case STALE:
352                         //
353                         // There is an entry waiting to be resolved.
354                         // Apply the lessons learnt to that entry.
355                         // Be careful -- another thread may be trying
356                         // the same, so we use the dequeue function
357                         // that checks again before proceeding.
358                         if (queues [nst].dequeue (ngb)) {
359                                 //
360                                 // Only one thread will continue here, having dequeued the neighbor
361                                 queues [REACHABLE].enqueue (ngb);
362                         }
363                         break;
364                 case REACHABLE:
365                 case FAILED:
366                         //
367                         // A persistent state has been reached, and any
368                         // advertisements coming in have missed their
369                         // window of opportunity.  Note that this may be
370                         // a sign of attempted abuse.  So ignore it.
371                         break;
372                 case INTRANSIT:
373                         //
374                         // Some thread is already working on this neighbor, so drop
375                         // this extra notification.
376                         break;
377                 default:
378                         break;
379                 }
380         }
381
382         
383         /* The Neighbor class represents individual entries in the NeighborCache.
384          * Each contains an IPv6 address as 16 bytes, its state, and a timeout for
385          * its current state queue.
386          * 
387          * Most of this class is storage, and is publicly accessible by the
388          * other components in this class/file.
389          * 
390          * Note that the Neighbor class serves in the hashtable as a key and value;
391          * but as a key, the only input used are the 6 bytes with the remote peer's
392          * IPv4 address and UDP port.  This means that another object can easily be
393          * constructed as a search entry, to resolve into the full entry.
394          * 
395          * TODO: Inner class -- does that mean that the context is copied into this object?  That'd be wasteful!
396          */
397         static class Neighbor {
398                 protected int state;
399                 protected InetSocketAddress target;
400                 protected long timeout;
401                 byte key [];
402                 boolean playful;
403                 
404                 /* The hashCode for this object depends solely on the key value.
405                  * Integrate all the bits of the key for optimal spreading.  The
406                  * hashCode may only differ if the equals() output below also
407                  * differs.
408                  */
409                 public int hashCode () {
410                         return key2hash (key);
411                 }
412                 
413                 /* The equals output determines that two Neighbor objects are
414                  * the same if their key matches; that is, if their remote
415                  * IPv4 address and UDP port is the same.  It is guaranteed
416                  * that the hashCode is the same for two equal objects; if two
417                  * objects are unequal then their hashCode is *likely* to differ,
418                  * but not guaranteed. 
419                  */
420                 public boolean equals (Object oth) {
421                         try {
422                                 Neighbor other = (Neighbor) oth;
423                                 for (int i=0; i<5; i++) {
424                                         if (this.key [i] != ((Neighbor) other).key [i]) {
425                                                 return false;
426                                         }
427                                 }
428                                 return true;
429                         } catch (Throwable thr) {
430                                 return false;
431                         }
432                 }
433                 
434                 /* Construct a new Neighbor based on its 6-byte key */
435                 public Neighbor (byte fromkey [], boolean create_playfully) {
436                         key = new byte [6];
437                         for (int i=0; i<6; i++) {
438                                 key [i] = fromkey [i];
439                         }
440                         state = NeighborCache.ATTEMPT1;
441                         target = key2socketaddress (key);
442                         playful = create_playfully;
443                 }
444         }
445         
446         /* The NeighborQueue inner class represents a timer queue.  The objects in this
447          * queue each have their own timeouts, as specified by state_timing_millis.
448          * New entries are attached to the back, timeouts are picked up at the front.
449          * 
450          * The queues have understanding of the various states, and how to handle
451          * expiration.
452          */
453         class NeighborQueue extends Thread {
454                 
455                 private NeighborCache cache;
456                 private int whoami;
457                 private Queue <Neighbor> queue;
458                 
459                 public NeighborQueue (NeighborCache owner, int mystate) {
460                         cache = owner;
461                         whoami = mystate;
462                         queue = new ArrayDeque <Neighbor> ();
463                         this.start ();
464                 }
465                 
466                 public void run () {
467                         while (true) {
468                                 //
469                                 // First, fetch the head element (or wait for one to appear).
470                                 // Sample its timeout.  Even if the head disappears later on,
471                                 // any further entries are certain to have a later timeout.
472                                 long timeout;
473                                 synchronized (queue) {
474                                         Neighbor head = null;
475                                         while (head == null) {
476                                                 head = queue.peek ();
477                                                 if (head == null) {
478                                                         try {
479                                                                 queue.wait ();
480                                                         } catch (InterruptedException io) {
481                                                                 ;
482                                                         }
483                                                 }
484                                         }
485                                         if (head.state == whoami) {
486                                                 timeout = 0;
487                                         } else {
488                                                 timeout = head.timeout;
489                                         }
490                                 }
491                                 //
492                                 // Now wait until the timeout expires.  This is not done in
493                                 // a synchronous fashion, so the queue can be changed as
494                                 // desired by other threads.  Note that misplaced items
495                                 // in the queue will be removed by the code further down
496                                 // before this thread can find rest.
497                                 if (timeout != 0) {
498                                         try {
499                                                 sleep (timeout - System.currentTimeMillis ());
500                                         } catch (InterruptedException ie) {
501                                                 ;
502                                         }
503                                 }
504                                 //
505                                 // Now the time has come to remove the head elements that
506                                 // have expired.  If nothing happened to the head of the
507                                 // queue, then this one should at least be removed, but
508                                 // following entries may just as well need removal.  Do
509                                 // this in a queue-synchronous manner to stop other threads
510                                 // from altering the queue.
511                                 long now = System.currentTimeMillis ();
512                                 Queue <Neighbor> removed = new ArrayDeque <Neighbor> ();
513                                 synchronized (queue) {
514                                         Neighbor head = queue.peek ();
515                                         while ((head != null) && ((head.state != whoami) || (head.timeout <= now))) {
516                                                 head = queue.remove ();
517                                                 if (head.state == whoami) {
518                                                         removed.offer (head);
519                                                 } // else, misplaced item that can be silently dropped
520                                                 head = queue.peek ();
521                                         }
522                                 }
523                                 //
524                                 // We now have a few elements in a temporary removed list;
525                                 // handle those by inserting them into their next lifecycle
526                                 // state (possibly meaning, destroy them).
527                                 switch (whoami) {
528                                 case ATTEMPT3:
529 /* TODO: Why would we want to remove the remote socket address?
530                                         //
531                                         // Remove the remote socket address, and continue with
532                                         // promotion to the next lifecycle state
533                                         for (Neighbor ngb : removed) {
534                                                 ngb.target = null;
535                                         }
536  */
537                                 case ATTEMPT1:
538                                 case ATTEMPT2:
539                                 case REACHABLE:
540                                         //
541                                         // Promote the neighbor to its next lifecycle state
542                                         for (Neighbor ngb : removed) {
543                                                 queues [whoami + 1].enqueue (ngb);
544                                         }
545                                         break;
546                                 case FAILED:
547                                 case STALE:
548                                         //
549                                         // Remove the neighbor from the cache
550                                         for (Neighbor ngb : removed) {
551                                                 cache.remove_from_cache (ngb);
552                                         }
553                                         break;
554                                 default:
555                                         break;
556                                 }
557                         }
558                 }
559
560                 /* Insert a new element into the queue.  If this is the first
561                  * entry, be sure to notify the thread that may be waiting for
562                  * something to chew on.
563                  * Note that an entry may be enqueued only once, use dequeue
564                  * to remove it from a possible former queue.
565                  */
566                 public void enqueue (Neighbor ngb) {
567                         enqueue (ngb, false);
568                 }
569                 
570                 /* Insert a new element into the queue.  If this is the first
571                  * entry, be sure to notify the thread that may be waiting for
572                  * something to chew on.
573                  * Note that an entry may be enqueued only once, use dequeue
574                  * to remove it from a possible former queue.
575                  * The flag "no_action" requests that the side-effects that
576                  * may take place after inserting the element in the queue
577                  * should be skipped.
578                  */
579                 public void enqueue (Neighbor ngb, boolean no_action) {
580                         //
581                         // Initialise the neighbor for this queue
582                         ngb.state = whoami;
583                         ngb.timeout = System.currentTimeMillis () + NeighborCache.state_timing_millis [whoami];
584                         //
585                         // Insert the Neighbor into the queue
586                         synchronized (queue) {
587                                 boolean wasEmpty = queue.isEmpty ();
588                                 queue.offer (ngb);
589                                 if (wasEmpty) {
590                                         queue.notifyAll ();
591                                 }
592                         }
593                         //
594                         // Skip the side-effect of insertion is so desired.
595                         if (no_action) {
596                                 return;
597                         }
598                         //
599                         // If this queue represents waiting for a reply to Neighbor
600                         // Solicitation, then solicit the neighbor.  This is not
601                         // synchronous, because networking does not directly modify
602                         // the queue, is slow and is asynchronous in nature anyway.
603                         switch (whoami) {
604                         case ATTEMPT1:
605                         case ATTEMPT2:
606                         case ATTEMPT3:
607                                 cache.solicit_neighbor (ngb);
608                                 break;
609                         default:
610                                 break;
611                         }
612                 }
613
614                 /* Remove an element from the queue without awaiting timer
615                  * expiration.  This is only of interest when incoming traffic
616                  * follows a direct route, while our previous attempts ran into
617                  * FAILED because the remote didn't have its ports open for us yet.
618                  * In addition, this may be used when a timer has gone STALE.
619                  * Note that expiration timers on the queue can continue to run,
620                  * they may simply find that the first element has not timed out
621                  * and another cycle is needed for what is then the head.
622                  * The state and timeout of the neighbor entry will not be modified
623                  * by this call, but future enqueueing may do that nonetheless.
624                  * The function returns success; that is, it tells the caller if
625                  * the object was indeed found in the queue. 
626                  * 
627                  * *** Implementation note ***
628                  * 
629                  * Dequeueing is expensive, as it involves going through the list
630                  * of stored items.  Keeping the structures up to date to speedup
631                  * this operation is hardly more pleasant.  So, we'll use a trick.
632                  * We simply won't dequeue.  This means that queues can hold items
633                  * that should have been removed.  As long as objects never cycle
634                  * back to this queue before their timers in this queue have
635                  * expired, the misplacement of a queue item could be directly
636                  * inferred from the state, which does not match the queue's state.
637                  * Such misplaced items can be silently removed.  Doing this, the
638                  * only remaining task for dequeue is to change the state in an
639                  * atomic fashion -- that is, without risk of overlapping similar
640                  * operations by other threads.  As originally intended, there
641                  * must be only one thread that receives true when removing an
642                  * item from a queue that holds it.  The loop that removes the
643                  * queue elements from the head also changes to accommodate this
644                  * behaviour.    
645                  */
646                 public boolean dequeue (Neighbor ngb) {
647                         boolean wasthere;
648                         synchronized (queue) {
649                                 if (ngb.state != whoami) {
650                                         wasthere = false;
651                                 } else {
652                                         ngb.state = NeighborCache.INTRANSIT;
653                                         wasthere = true;
654                                 }
655                         }
656                         return wasthere;
657                 }
658         }
659
660         
661         /***
662          *** UTILITIES
663          ***/
664         
665         
666         /* Check if an address is a 6bed4 address.
667          */
668         public boolean is6bed4 (byte addr [], int addrofs) {
669                 if (TunnelService.memdiff_halfaddr (addr, addrofs, address_6bed4, 0)) {
670                         return false;
671                 }
672                 if ((addr [addrofs + 11] != (byte) 0xff) || (addr [addrofs + 12] != (byte) 0xfe)) {
673                         return false;
674                 }
675                 //TODO// Possibly require that the port number is even
676                 return true;
677         }
678         
679         /* Map an address to a 6-byte key in the provided space.  Assume that the
680          * address is known to be a 6bed4 address.
681          */
682         private static void address2key (byte addr [], int addrofs, byte key []) {
683                 key [0] = (byte) (addr [addrofs +  8] ^ 0x02);
684                 key [1] = addr [addrofs +  9];
685                 key [2] = addr [addrofs + 10];
686                 key [3] = addr [addrofs + 13];
687                 key [4] = addr [addrofs + 14];
688                 key [5] = addr [addrofs + 15];
689         }
690
691         /* Map an InetSocketAddress to a 6-byte key in the provided space.
692          */
693         private static void socketaddress2key (InetSocketAddress sa, byte key []) {
694                 int port = sa.getPort ();
695                 byte addr [] = sa.getAddress ().getAddress ();
696                 key [0] = (byte) (port & 0xff);
697                 key [1] = (byte) (port >> 8  );
698                 key [2] = addr [0];
699                 key [3] = addr [1];
700                 key [4] = addr [2];
701                 key [5] = addr [3];
702         }
703
704         /* Map a key to an IPv6 address, following the 6bed4 structures.
705          */
706         private void key2ipv6address (byte key [], byte addr [], int addrofs) {
707                 for (int i=0; i<8; i++) {
708                         addr [addrofs + i] = address_6bed4 [i];
709                 }
710                 addr [addrofs +  8] = (byte) (key [0] ^ 0x02);
711                 addr [addrofs +  9] = key [1];
712                 addr [addrofs + 10] = key [2];
713                 addr [addrofs + 11] = (byte) 0xff;
714                 addr [addrofs + 12] = (byte) 0xfe;
715                 addr [addrofs + 13] = key [3];
716                 addr [addrofs + 14] = key [4];
717                 addr [addrofs + 15] = key [5];
718         }
719
720         /* Map a key to an InetSocketAddress.
721          */
722         private static InetSocketAddress key2socketaddress (byte key []) {
723                 int port = (int) (key [0] & 0xff);
724                 port = port | (((int) (key [1] << 8)) & 0xff00);
725                 byte v4addr [] = new byte [4];
726                 v4addr [0] = key [2];
727                 v4addr [1] = key [3];
728                 v4addr [2] = key [4];
729                 v4addr [3] = key [5];
730                 try {
731                         Inet4Address remote = (Inet4Address) Inet4Address.getByAddress (v4addr);
732                         return new InetSocketAddress (remote, port);                                            
733                 } catch (UnknownHostException uhe) {
734                         throw new RuntimeException ("Internet Error", uhe);
735                 }
736         }
737         
738         private static int key2hash (byte key []) {
739                 int retval;
740                 retval = key [0] ^ key [3];
741                 retval <<= 8;
742                 retval += key [1] ^ key [4];
743                 retval <<= 8;
744                 retval += key [2] ^ key [5];
745                 return retval;
746         }
747
748 }