public synchronized void handlePacket(Connection c, Packet p) {
    Address address = c.getAddress();
    System.out.println(p.toString());

    // silently ignore packets from a connection if we haven't received a version packet

    if (!c.hasReceivedVersion() && p.packetType() != PacketType.VERSION) {
      return;
    }

    switch (p.packetType()) {
      case VERSION:
        VersionPacket v = (VersionPacket) p;
        long ourVersion = ProtocolVersion.version(),
            theirVersion = v.getVersion(),
            negotiatedVersion;
        negotiatedVersion = theirVersion < ourVersion ? theirVersion : ourVersion;
        c.setVersion(negotiatedVersion);
        c.hasReceivedVersion(true);
        addressBook.justSeen(address);
        if (negotiatedVersion >= 209) {
          Packet verack = c.createPacket(PacketType.VERACK);
          c.sendPacket(verack);
        }
        break;
      case VERACK:
        c.hasRecievedVerack(true);
        addressBook.justSeen(address);
        break;
      case HEADERS:
        // primitive headers function
        HeadersPacket h = (HeadersPacket) p;
        if (h.headers().size() == 0) {
          break;
        }
        for (Block header : h.headers()) {
          try {
            blockChain.addBlock(header);

          } catch (InvalidBlockException e) {
            // TODO actually handle
            e.printStackTrace();
            continue;
          } catch (OrphanBlockException e) {
            // TODO actually handle
            e.printStackTrace();
            continue;
          } catch (BlockExistsException e) {
            // TODO actually handle
            e.printStackTrace();
            continue;
          }
        }
        GetHeadersPacket gh = (GetHeadersPacket) c.createPacket(PacketType.GETHEADERS);
        gh.startHashes().add(blockChain.topBlock().hash());
        c.sendPacket(gh);
    }
  }
 public synchronized Connection connectTo(Address a) throws IOException {
   addressBook.justTried(a);
   Connection c = new Connection(this, a);
   connections.add(c);
   addressBook.justConnected(a);
   VersionPacket p = (VersionPacket) c.createPacket(PacketType.VERSION);
   p.setRemoteAddress(c.getAddress());
   p.setFromAddress(localAddress);
   c.sendPacket(p);
   c.connect();
   return c;
 }
 public synchronized void bootstrap()
     throws UnknownHostException, IOException, InterruptedException {
   IrcBootStrap irc =
       new IrcBootStrap(
           ProtocolVersion.ircHost(), ProtocolVersion.ircPort(), ProtocolVersion.ircChannel());
   Vector<Address> addresses = irc.getAddresses();
   for (Address a : addresses) {
     addressBook.justSeen(a);
   }
 }
  public synchronized void maintainConnections() {
    int connectionsToAdd = connectionsToMaintain - connections.size();
    if (connectionsToAdd <= 0) {
      return;
    }
    List<Address> toConnect;
    Vector<Address> possible = addressBook.getAddressConnectList();

    removeConnectionsFromAddressList(connections, possible);

    if (possible.size() < connectionsToAdd && ircBootStrap) {

      try {
        System.out.println("addresses: " + possible.size());

        bootstrap();
        possible = addressBook.getAddressConnectList();
        possible.removeAll(connections);
        System.out.println("addresses2: " + possible.size());
      } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    toConnect =
        possible.subList(
            0, (connectionsToMaintain < possible.size() ? connectionsToMaintain : possible.size()));
    for (Address a : toConnect) {
      try {
        connectTo(a);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
 public void addAddress(Address a) {
   addressBook.justSeen(a);
 }