Ejemplo n.º 1
0
 /// <summary>This parses a MemBlock into the Ethernet fields</summary>
 ///  <param name="Packet">The Ethernet packet</param>
 public EthernetPacket(MemBlock Packet)
 {
     _icpacket = _packet = Packet;
       DestinationAddress = Packet.Slice(0, 6);
       SourceAddress = Packet.Slice(6, 6);
       Type = (Types) ((Packet[12] << 8) | Packet[13]);
       _icpayload = _payload = Packet.Slice(14);
 }
Ejemplo n.º 2
0
 /**
  * This handles the packet forwarding protocol
  */
 public void HandleData(MemBlock b, ISender ret_path, object state)
 {
   /*
    * Check it
    */
   AHSender ahs = ret_path as AHSender;
   if( ahs != null ) {
     //This was an AHSender:
     /*
      * This goes A -> B -> C
      */
     if( b[0] == 0 ) {
       int offset = 1;
       //This is the first leg, going from A->B
       Address add_c = AddressParser.Parse(b.Slice(offset, Address.MemSize));
       offset += Address.MemSize;
       //Since ahs a sender to return, we would be the source:
       Address add_a = ahs.Destination;
       short ttl = NumberSerializer.ReadShort(b, offset);//2 bytes
       offset += 2;
       ushort options = (ushort) NumberSerializer.ReadShort(b, offset);//2 bytes
       offset += 2;
       MemBlock payload = b.Slice(offset);
       MemBlock f_header = MemBlock.Reference( new byte[]{1} );
       /*
        * switch the packet from [A B f0 C] to [B C f 1 A]
        */
       ICopyable new_payload = new CopyList(PType.Protocol.Forwarding,
                                        f_header, add_a, payload);
       /*
        * ttl and options are present in the forwarding header.
        */
       AHSender next = new AHSender(_n, ahs.ReceivedFrom, add_c,
                                    ttl,
                                    options); 
       next.Send(new_payload);
     }
     else if ( b[0] == 1 ) {
       /*
        * This is the second leg: B->C
        * Make a Forwarding Sender, and unwrap the inside packet
        */
       Address add_a = AddressParser.Parse(b.Slice(1, Address.MemSize));
       Address add_b = ahs.Destination;
       MemBlock rest_of_payload = b.Slice(1 + Address.MemSize);
       //Here's the return path:
       ISender new_ret_path = new ForwardingSender(_n, add_b, add_a);
       _n.HandleData(rest_of_payload, new_ret_path, this);
     }
   }
   else {
     //This is not (currently) supported.
     Console.Error.WriteLine("Got a forwarding request from: {0}", ret_path);
   }
 }
Ejemplo n.º 3
0
  public void Test() {
    System.Random r = new System.Random();

    byte[] data;
    for(int i = 0; i < 100; i++) {
      data = new byte[ r.Next(1024) ];
      r.NextBytes(data);
      int offset = r.Next(data.Length);
      MemBlock mb1 = new MemBlock(data, 0, data.Length);
      MemBlock mb1a = MemBlock.Copy(data, 0, data.Length);
      Assert.AreEqual(mb1, mb1a, "MemBlock.Copy");
      Assert.AreEqual(mb1, data, "MemBlock == byte[]");
      MemBlock mb2 = new MemBlock(data, offset, data.Length - offset);
      MemBlock mb2a = mb1.Slice(offset);
      MemBlock mb3 = new MemBlock(data, 0, offset);
      MemBlock mb3a = mb1.Slice(0, offset);
      Assert.IsTrue(mb3.Equals( mb3a ), "mb3.Equals(mb3a)");
      Assert.IsTrue(mb3a.Equals( mb3 ), "mb3a.Equals(mb3)");
      Assert.AreEqual(mb3.CompareTo(mb2) + mb2.CompareTo(mb3), 0, "CompareTo");
      Assert.IsTrue(mb2.Equals( mb2a ), "mb2.Equals(mb2a)");
      Assert.IsTrue(mb2a.Equals( mb2 ), "mb2a.Equals(mb2)");

      MemBlock cat = MemBlock.Concat(mb3, mb2);
      MemBlock cata = MemBlock.Concat(mb3a, mb2a);
      Assert.IsTrue(cat.Equals(cata), "Concat Equals");
      Assert.IsTrue(cata.Equals(cat), "Concat a Equals");
      Assert.IsTrue(mb1.Equals(cat), "Concat Equals Original");
      if( offset != 0 ) {
        //These should not be equal
        Assert.IsFalse(mb2.Equals(mb1), "mb2 != mb1");
      }
      int mb2a_l = mb2a.Length;
      byte[] tmp_data = new byte[mb2a_l];
      mb2a.CopyTo(tmp_data, 0);
      MemBlock mb2b = new MemBlock(tmp_data, 0, tmp_data.Length);
      Assert.IsTrue(mb2a.Equals(mb2b), "mb2a.Equals(mb2b)");
      Assert.IsTrue(mb2b.Equals(mb2a), "mb2b.Equals(mb2a)");

      //Check the Hash:
      Assert.AreEqual(mb2b.GetHashCode(), mb2a.GetHashCode(), "GetHashCode");

      //Here are some manual equality testing using the indexer
      bool all_equals = true;
      int j = 0;
      while( all_equals && (j < mb1.Length) ) {
        all_equals = (mb1[ j ] == cat[ j ]);
        j++;
      }
      Assert.IsTrue(all_equals, "Manual equality test mb1");
      all_equals = true;
      j = 0;
      while( all_equals && (j < mb2.Length) ) {
        all_equals = (mb2[ j ] == mb2a[ j ]);
        j++;
      }
      Assert.IsTrue(all_equals, "Manual equality test mb2");
      all_equals = true;
      j = 0;
      while( all_equals && (j < mb2.Length) ) {
        all_equals = (mb2[ j ] == mb2b[ j ]);
        j++;
      }
      Assert.IsTrue(all_equals, "Manual equality test mb2b");
    }
  }
 public SecurityDataMessage(MemBlock data): base(data) {
   try {
     int pos = 0;
     _spi = NumberSerializer.ReadInt(data, pos);
     pos += 4;
     _epoch = NumberSerializer.ReadInt(data, pos);
     pos += 4;
     _seqid = NumberSerializer.ReadInt(data, pos);
     pos += 4;
     _encrypted_data = data.Slice(pos);
   } catch {
     throw new Exception("Invalid SecurityDataMessage");
   }
   _update_icpacket = false;
 }
Ejemplo n.º 5
0
        /**
        <summary>Constructor when creating a ZoneAuthority from a MemBlock, this
        is incomplete.</summary>
        */
        public ZoneAuthority(MemBlock data)
        {
            int idx = 0;
              MNAME = String.Empty;
              while(data[idx] != 0) {
            byte length = data[idx++];
            for(int i = 0; i < length; i++) {
              MNAME += (char) data[idx++];
            }
            if(data[idx] != 0) {
              MNAME  += ".";
            }
              }
              idx++;

              RNAME = String.Empty;
              while(data[idx] != 0) {
            byte length = data[idx++];
            for(int i = 0; i < length; i++) {
              RNAME += (char) data[idx++];
            }
            if(data[idx] != 0) {
              RNAME  += ".";
            }
              }
              idx++;

              SERIAL = (data[idx++] << 24) + (data[idx++] << 16) +
              (data[idx++] << 8) + data[idx++] << 24;
              REFRESH = (data[idx++] << 24) + (data[idx++] << 16) +
              (data[idx++] << 8) + data[idx++] << 24;
              RETRY = (data[idx++] << 24) + (data[idx++] << 16) +
              (data[idx++] << 8) + data[idx++] << 24;
              EXPIRE = (data[idx++] << 24) + (data[idx++] << 16) +
              (data[idx++] << 8) + data[idx++] << 24;
              MINIMUM = (data[idx++] << 24) + (data[idx++] << 16) +
              (data[idx++] << 8) + data[idx++] << 24;
              _icpacket = _packet = data.Slice(0, idx);
        }
Ejemplo n.º 6
0
        /**
        <summary>Parse a MemBlock packet into a DHCP Packet</summary>
        <param name="Packet">The dhcp packet to parse</param>
        */
        public DHCPPacket(MemBlock Packet)
        {
            if(Packet.Length < 240) {
            throw new Exception("Invalid DHCP Packet:  Length < 240.");
              }

              _packet = Packet;
              op = Packet[0];
              int hlen = Packet[2];
              xid = Packet.Slice(4, 4);
              ciaddr = Packet.Slice(12, 4);
              yiaddr = Packet.Slice(16, 4);
              siaddr = Packet.Slice(20, 4);
              chaddr = Packet.Slice(28, hlen);
              MemBlock key = Packet.Slice(236, 4);
              if(!key.Equals(magic_key)) {
            throw new Exception("Invalid DHCP Packet: Invalid magic key.");
              }
              int idx = 240;

              /* Parse the options */
              Options = new Dictionary<OptionTypes, MemBlock>();
              /*  255 is end of options */
              while(Packet[idx] != 255) {
            /* 0 is padding */
            if(Packet[idx] != 0) {
              OptionTypes type = (OptionTypes) Packet[idx++];
              byte length = Packet[idx++];
              Options[type] = Packet.Slice(idx, length);
              idx += length;
            }
            else {
              idx++;
            }
              }
        }
Ejemplo n.º 7
0
 // Methods /////
 /**
  * This is either a request or response.  Look up the handler
  * for it, and pass the packet to the handler
  */
 public void HandleData(MemBlock p, ISender from, object state) {
   //Simulate packet loss
   //if ( _rand.NextDouble() < 0.1 ) { return; }
   //Is it a request or reply?
   ReqrepType rt = (ReqrepType)((byte)p[0]);
   int idnum = NumberSerializer.ReadInt(p,1);
   MemBlock rest = p.Slice(5); //Skip the type and the id
   if( rt == ReqrepType.Request || rt == ReqrepType.LossyRequest ) {
     HandleRequest(rt, idnum, rest, from);
   }
   else if( rt == ReqrepType.Reply ) {
     HandleReply(rt, idnum, rest, from);
   }
   else if (rt == ReqrepType.ReplyAck ) {
     HandleReplyAck(rt, idnum, rest, from);
   }
   else if (rt == ReqrepType.RequestAck ) {
     HandleRequestAck(rt, idnum, rest, from);
   }
   else if( rt == ReqrepType.Error ) {
     HandleError(rt, idnum, rest, from);
   }
 }
Ejemplo n.º 8
0
 /**
  * This handles lightweight control messages that may be sent
  * by UDP
  */
 protected void HandleControlPacket(int remoteid, int n_localid, MemBlock buffer,
                                    object state)
 {
   int local_id = ~n_localid;
   //Reading from a hashtable is treadsafe
   UdpEdge e = (UdpEdge)_id_ht[local_id];
   if( (e != null) && (e.RemoteID == remoteid) ) {
     //This edge has some control information.
     try {
       ControlCode code = (ControlCode)NumberSerializer.ReadInt(buffer, 0);
       if(ProtocolLog.UdpEdge.Enabled)
         ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
           "Got control {1} from: {0}", e, code));
       if( code == ControlCode.EdgeClosed ) {
         //The edge has been closed on the other side
         RequestClose(e);
         CloseHandler(e, null);
       }
       else if( code == ControlCode.EdgeDataAnnounce ) {
         //our NAT mapping may have changed:
         IDictionary info =
           (IDictionary)AdrConverter.Deserialize( buffer.Slice(4) );
         string our_local_ta = (string)info["RemoteTA"]; //his remote is our local
         if( our_local_ta != null ) {
           //Update our list:
           TransportAddress new_ta = TransportAddressFactory.CreateInstance(our_local_ta);
           TransportAddress old_ta = e.PeerViewOfLocalTA;
           if( ! new_ta.Equals( old_ta ) ) {
             if(ProtocolLog.UdpEdge.Enabled)
               ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
                 "Local NAT Mapping changed on Edge: {0}\n{1} => {2}",
              e, old_ta, new_ta));
             //Looks like matters have changed:
             this.UpdateLocalTAs(e, new_ta);
             /**
              * @todo, maybe we should ping the other edges sharing this
              * EndPoint, but we need to be careful not to do some O(E^2)
              * operation, which could easily happen if each EdgeDataAnnounce
              * triggered E packets to be sent
              */
           }
         }
       }
       else if( code == ControlCode.Null ) {
         //Do nothing in this case
       }
     }
     catch(Exception x) {
     //This could happen if this is some control message we don't understand
       if(ProtocolLog.Exceptions.Enabled)
         ProtocolLog.Write(ProtocolLog.Exceptions, x.ToString());
     }
   }
 }
Ejemplo n.º 9
0
        /**
        <summary>Creates a response given the entire packet.</summary>
        <remarks>The entire packet must be given, because some name servers take
        advantage of pointers to reduce their size.</remarks>
        <param name="Data">The entire DNS packet.</param>
        <param name="Start">The starting position of the Response.</param>
        */
        public Response(MemBlock Data, int Start)
        {
            int idx = 0;
              NAME_BLOB = DNSPacket.RetrieveBlob(Data, Start, out idx);

              int type = (Data[idx++] << 8) + Data[idx++];
              TYPE = (DNSPacket.TYPES) type;

              CACHE_FLUSH = ((Data[idx] & 0x80) == 0x80) ? true : false;
              int rclass = ((Data[idx++] << 8) & 0x7F) + Data[idx++];
              CLASS = (DNSPacket.CLASSES) rclass;

              TTL = (Data[idx++] << 24);
              TTL |= (Data[idx++] << 16);
              TTL |= (Data[idx++] << 8);
              TTL |= (Data[idx++]);

              RDLENGTH = (short) ((Data[idx++] << 8) + Data[idx++]);
              RDATA_BLOB = Data.Slice(idx, RDLENGTH);

              if(TYPE == DNSPacket.TYPES.PTR) {
            try {
              NAME = DNSPacket.PtrMemBlockToString(NAME_BLOB);
            }
            catch {
              NAME = DNSPacket.HostnameMemBlockToString(NAME_BLOB);
            }
            int End = 0;
            RDATA_BLOB = DNSPacket.RetrieveBlob(Data, idx, out End);
            RDATA = DNSPacket.HostnameMemBlockToString(RDATA_BLOB);
              }
              else if(TYPE == DNSPacket.TYPES.A) {
            NAME = DNSPacket.HostnameMemBlockToString(NAME_BLOB);
            RDATA = DNSPacket.IPMemBlockToString(RDATA_BLOB);
              }
              _icpacket = _packet = Data.Slice(Start, idx + RDLENGTH - Start);
        }
Ejemplo n.º 10
0
 /**
  * Parse the PType starting at mb, and return all of mb <b>after</b>
  * the PType.
  */
 public static PType Parse(MemBlock mb, out MemBlock rest) {
   PType result = null;
   byte fb = mb[0];
   bool is_v_n = IsValidNumeric( (int)fb );
   /**
    * Since ptypes must be valid UTF8 strings,
    * if the second byte is null, the first byte is an ascii character
    * and hence has a value less than ASCII_UPPER_BOUND 
    */
   bool store_in_tbl = ( is_v_n || (mb[1] == 0) );
   if( store_in_tbl ) {
     //This is stored in our table:
     result = _table[ fb ];
     if( result != null ) {
       if( is_v_n ) {
         //There is no null
         rest = mb.Slice(1);
       }
       else {
         //Skip the null
         rest = mb.Slice(2);
       }
       return result;
     }
   }
   //Otherwise we have to make it:
   MemBlock raw_data = null;
   result = new PType();
   if( is_v_n ) {
     /*
      * Don't set the raw_data since it is only one byte and we may not need
      * it
      */
     rest = mb.Slice(1);
     result._type_num = (int)fb;
   }
   else {
     int null_pos = mb.IndexOf(0);
     if( null_pos > 0 ) {
       //Include the "null", but make a copy so we don't keep some data in
       //scope for ever
       raw_data = MemBlock.Copy( (ICopyable)mb.Slice(0, null_pos + 1) );
       rest = mb.Slice(null_pos + 1); 
     }
     else {
       //There is no terminating Null, panic!!
       throw new ParseException(
         System.String.Format("PType not null terminated: {0}", mb.ToBase16String()));
     }
     result._type_num = -2;
     result._raw_data = raw_data;
   }
   if( store_in_tbl ) {
     //Make sure we don't have to create an object like this again
     _table[ fb ] = result;
   }
   return result;
 }
        /**
        <summary>Implements the ITranslator portion for ManagedAddress..., takes an
        IP Packet, based upon who the originating Brunet Sender was, changes who
        the packet was sent from and then switches the destination address to the
        local nodes address</summary>
        <param name="packet">The IP Packet to translate.</param>
        <param name="from">The Brunet address the packet was sent from.</param>
        <returns>The translated IP Packet.</returns>
        */
        public MemBlock Translate(MemBlock packet, Address from)
        {
            MemBlock source_ip = (MemBlock) _addr_ip[from];
              if(source_ip == null) {
            throw new Exception("Invalid mapping " + from + ".");
              }

              // Attempt to translate a MDNS packet
              IPPacket ipp = new IPPacket(packet);
              MemBlock hdr = packet.Slice(0,12);
              bool fragment = ((packet[6] & 0x1F) | packet[7]) != 0;

              if(ipp.Protocol == IPPacket.Protocols.UDP && !fragment) {
            UDPPacket udpp = new UDPPacket(ipp.Payload);
            // MDNS runs on 5353
            if(udpp.DestinationPort == 5353) {
              DNSPacket dnsp = new DNSPacket(udpp.Payload);
              String ss_ip = DNSPacket.IPMemBlockToString(source_ip);
              bool change = mDnsTranslate(dnsp.Answers, ss_ip);
              change |= mDnsTranslate(dnsp.Authority, ss_ip);
              change |= mDnsTranslate(dnsp.Additional, ss_ip);
              // If we make a change let's make a new packet!
              if(change) {
            dnsp = new DNSPacket(dnsp.ID, dnsp.QUERY, dnsp.OPCODE, dnsp.AA,
                                 dnsp.RA, dnsp.RD, dnsp.Questions, dnsp.Answers,
                                 dnsp.Authority, dnsp.Additional);
            udpp = new UDPPacket(udpp.SourcePort, udpp.DestinationPort,
                                 dnsp.ICPacket);
            ipp = new IPPacket(ipp.Protocol, source_ip, ipp.DestinationIP,
                               hdr, udpp.ICPacket);
            return ipp.Packet;
              }
            }
            else if(udpp.DestinationPort >= 5060 && udpp.DestinationPort < 5100) {
              udpp = SIPTranslate(udpp, source_ip, ipp.SSourceIP,
                              ipp.SDestinationIP);
              ipp = new IPPacket(ipp.Protocol, source_ip, _local_ip, hdr,
                             udpp.ICPacket);
              return ipp.Packet;
            }
              }
              return IPPacket.Translate(packet, source_ip, _local_ip);
        }
Ejemplo n.º 12
0
 /**
 <summary>Takes in a MemBlock and parses it into IP Header fields</summary>
 <param name="Packet">The IP Packet to parse.</param>
 */
 public IPPacket(MemBlock Packet) {
   _icpacket = _packet = Packet;
   Protocol = (Protocols) Packet[9];
   SourceIP = Packet.Slice(12, 4);
   DestinationIP = Packet.Slice(16, 4);
   _icpayload = _payload = Packet.Slice(20);
 }
Ejemplo n.º 13
0
    /**
     * Handles packet received for the EdgeListener. It can be data received on 
     * a tunnel edge or packet for edge maintenance. 
     * @param packet that has been received.
     * @param return_path return path for the packet (to send it back).
     * @param state state supplied when subscribing to receive packets of some type. 
     */
    public void HandleData(MemBlock packet, ISender return_path, object state)
    {
      if (0 == _running) {
#if TUNNEL_DEBUG
        Console.Error.WriteLine("TunnelEdgeListener: not running (cannot handle packet)");
#endif 
        return;
      }
      //read the payload?
      MessageType type = (MessageType) packet[0];
      int remoteid = NumberSerializer.ReadInt(packet, 1);
      int localid = NumberSerializer.ReadInt(packet, 5);
      
#if TUNNEL_DEBUG
      Console.Error.WriteLine("TunnelEdgeListener: Receiving on base connection: {0}", return_path);
      Console.Error.WriteLine("Receiving edge packet, remoteid: {0}, localid: {1}", remoteid, localid);
#endif
      // 1 + 4 + 4 = 9
      MemBlock rest_of_payload = packet.Slice(9);
      if (type == MessageType.EdgeRequest) {
        HandleEdgeRequest(remoteid, localid, rest_of_payload, return_path);
      }
      else if (type == MessageType.EdgeResponse) {
        HandleEdgeResponse(remoteid, localid, rest_of_payload);
      }
      else if(type == MessageType.EdgeData) {
        HandleEdgeData(remoteid, localid, rest_of_payload);
      }
      else if (type == MessageType.EdgeControl) {
        HandleEdgeControl(remoteid, localid, rest_of_payload);
      }
      else if (type == MessageType.EdgeSync) {
        HandleEdgeSync(remoteid, localid, rest_of_payload);
      }
    }
Ejemplo n.º 14
0
        /**
        <summary>Constructor when parsing a DNS Query</summary>
        <param name="Data"> must pass in the entire packet from where the question
        begins, after parsing, can check Data.Length to find where next
        container begins.</param>
        */
        public Question(MemBlock Data, int Start)
        {
            int idx = 0;
              QNAME_BLOB = DNSPacket.RetrieveBlob(Data, Start, out idx);
              int qtype = (Data[idx++] << 8) + Data[idx++];
              QTYPE = (DNSPacket.TYPES) qtype;

              int qclass = (Data[idx++] << 8) + Data[idx];
              QCLASS = (DNSPacket.CLASSES) qclass;

              if(QTYPE == DNSPacket.TYPES.A) {
            QNAME = DNSPacket.HostnameMemBlockToString(QNAME_BLOB);
              }
              else if(QTYPE == DNSPacket.TYPES.PTR) {
            QNAME = DNSPacket.PtrMemBlockToString(QNAME_BLOB);
              }

              _icpacket = _packet = Data.Slice(Start, idx + 1 - Start);
        }
    public SecurityControlMessage(MemBlock data) {
      try {
        int pos = 0;
        _version = NumberSerializer.ReadInt(data, 0);
        pos += 4; 
        _spi = NumberSerializer.ReadInt(data, pos);
        pos += 4;
        _type = (MessageType) NumberSerializer.ReadInt(data, pos);
        pos += 4;
        _local_cookie = data.Slice(pos, CookieLength);
        pos += CookieLength;
        _remote_cookie = data.Slice(pos, CookieLength);
        pos += CookieLength;

        bool read_cas = false;
        bool read_dhe = false;
        bool read_cert = false;
        bool read_hash = false;

        switch(_type) {
          case MessageType.CookieResponse:
            read_cas = true;
            break;
          case MessageType.DHEWithCertificate:
            read_cert = true;
            read_dhe = true;
            break;
          case MessageType.DHEWithCertificateAndCAs:
            read_cas = true;
            read_dhe = true;
            read_cert = true;
            break;
          case MessageType.Confirm:
            read_hash = true;
            break;
        }

        if(read_dhe) {
          int dhe_length = NumberSerializer.ReadInt(data, pos);
          pos += 4;
          _dhe = data.Slice(pos, dhe_length);
          pos += dhe_length;
        }

        if(read_cert) {
          int cert_length = NumberSerializer.ReadInt(data, pos);
          pos +=4;
          _certificate = data.Slice(pos, cert_length);
          pos += cert_length;
        }

        if(read_cas) {
          int cas_length = NumberSerializer.ReadInt(data, pos);
          pos += 4;
          _cas = new List<MemBlock>();
          int end = pos + cas_length;
          while(pos < end) {
            _cas.Add(data.Slice(pos, CALength));
            pos += CALength;
          }
        }

        if(read_hash) {
          int hash_length = NumberSerializer.ReadInt(data, pos);
          pos +=4;
          _hash = data.Slice(pos, hash_length);
          pos += hash_length;
        }

        _signature = data.Slice(pos);
      } catch {
        throw new Exception("Invalid SecurityControlMessage");
      }
      _update_packet = false;
      _packet = data;
    }
Ejemplo n.º 16
0
  private static object Deserialize(MemBlock b, int offset, byte term,
                                    out bool finished, out int size) {
    byte typecode = b[offset];
    finished = false;  //By default, we're not finished
    switch( typecode ) {
      case STRING_S:
        int count;
        string s = NumberSerializer.ReadString(b, offset + 1, out count);
        size = count + 1; //add one for the STRING_S byte
        return s;
      case LIST_S:
        IList lst = new ArrayList();
        bool lfin;
        int lsize;
        size = 1;
        offset++; //Skip the LIST_S
        do {
          object o = Deserialize(b, offset, LIST_E, out lfin, out lsize);
	  if( !lfin ) {
	    //If we are finished, tmp holds a meaningless null
	    lst.Add(o);
	  }
          offset += lsize;
          size += lsize;
        } while( ! lfin );
        return lst;
      case LIST_E:
        if( term == LIST_E ) { finished = true; size = 1; }
        else {
          throw new Exception(
               String.Format("terminator mismatch: found: {0} expected: {1}", term, LIST_E));
        }
        return null;
      case MAP_S:
        //Start of a map:
        IDictionary dresult = new Hashtable();
        bool mfinished = false;
        int msize;
        size = 1;
        offset++;
        do {
          //Magical recursion strikes again
          object key = Deserialize(b, offset, MAP_E, out mfinished, out msize);
          offset += msize;
          size += msize;
          if( !mfinished ) {
            object valu = Deserialize(b, offset, out msize);
            offset += msize;
            size += msize;
            dresult.Add(key, valu);
          }
        } while (false == mfinished);
        return dresult;
      case MAP_E:
        //End of a map:
        if (term == MAP_E) {
          //We were reading a list and now we are done:
          finished = true;
          size = 1;
        }
        else {
          throw new Exception(
               String.Format("terminator mismatch: found: {0} expected: {1}", term, MAP_E));
        }
        return null;
      case TRUE:
        size = 1;
        return true;
      case FALSE:
        size = 1;
        return false;
      case NULL:
        size = 1;
        return null;
      case SBYTE:
        size = 2;
        return (sbyte)b[offset + 1];
      case BYTE:
        size = 2;
        return b[offset + 1];
      case SHORT:
        size = 3;
        return NumberSerializer.ReadShort(b, offset + 1);
      case USHORT:
        size = 3;
        return (ushort)NumberSerializer.ReadShort(b, offset + 1);
      case INT:
        size = 5;
        return NumberSerializer.ReadInt(b, offset + 1);
      case UINT:
        size = 5;
        return (uint)NumberSerializer.ReadInt(b, offset + 1);
      case LONG:
        size = 9;
        return NumberSerializer.ReadLong(b, offset + 1);
      case ULONG:
        size = 9;
        return (ulong)NumberSerializer.ReadLong(b, offset + 1);
      case FLOAT:
        size = 5;
        return NumberSerializer.ReadFloat(b, offset + 1);
      case DOUBLE:
	size = 9;
	return NumberSerializer.ReadDouble(b, offset + 1);
      case EXCEPTION_S:
        //Start of a map:
        Hashtable eresult = new Hashtable();
        bool efinished = false;
        int esize;
        size = 1;
        offset++;
        do {
          //Magical recursion strikes again
          object key = Deserialize(b, offset, EXCEPTION_E, out efinished, out esize);
          offset += esize;
          size += esize;
          if( !efinished ) {
            object valu = Deserialize(b, offset, out esize);
            offset += esize;
            size += esize;
            eresult.Add(key, valu);
          }
        } while (false == efinished);
        return new AdrException(eresult);
      case EXCEPTION_E:
        //End of a map:
        if (term == EXCEPTION_E) {
          //We were reading a list and now we are done:
          finished = true;
          size = 1;
        }
        else {
          throw new Exception(
               String.Format("terminator mismatch: found: {0} expected: {1}",
                             term, EXCEPTION_E));
        }
        return null;
      case ARRAY:
        //Read length:
        int asize;
        object olength = Deserialize(b, offset + 1, out asize);
        //Due to boxing here, we have to be careful about unboxing,
        //this will get easier with generics:
        int length = (int)UnboxToLong(olength); 
        offset += 1 + asize;
	byte atype = b[offset];
        offset++;
	switch (atype) {
          case BYTE:
            byte[] aBresult = new byte[length];
            MemBlock b_a = b.Slice(offset, length);
            b_a.CopyTo(aBresult, 0);
            size = 1 + asize + 1 + length;
            return aBresult;
          case INT:
            int[] airesult = new int[length];
            for(int i = 0; i < airesult.Length; i++) {
              airesult[i] = NumberSerializer.ReadInt(b, offset);
              offset += 4;
            }
            size = 1 + asize + 1 + 4 * length;
            return airesult;
            ///@todo add more array types
          default:
            throw new Exception("Unsupported array type code: " + atype);
	}
      default:
        throw new Exception(String.Format("Unrecognized type code: {0}", typecode));
    }
  }