public void testQRP() throws Exception {
    RoutedConnection c = connectionManager.getInitializedConnections().get(0);
    c.getRoutedConnectionStatistics().incrementNextQRPForwardTime(0);
    PatchTableMessage ptm =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(
            testUP[0], PatchTableMessage.class, 22000);
    assertNotNull(ptm);
    QueryRouteTable qrt = new QueryRouteTable();
    qrt.patch(ptm);

    // initially, the qrp words should be included
    assertTrue(qrt.contains(queryRequestFactory.createQuery("badger")));

    // change some words, an updated qrp should be sent shortly
    SearchSettings.LIME_QRP_ENTRIES.set(new String[] {"mushroom"});
    c.getRoutedConnectionStatistics().incrementNextQRPForwardTime(0);
    triggerSimppUpdate();
    ptm =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(
            testUP[0], PatchTableMessage.class, 12000);
    assertNotNull(ptm);
    qrt.patch(ptm);

    // the new word should be there, the old one gone.
    assertTrue(qrt.contains(queryRequestFactory.createQuery("mushroom")));
    assertFalse(qrt.contains(queryRequestFactory.createQuery("badger")));
  }
  /**
   * Test to make sure that dynamic querying sends a query with TTL=1 and other properties when a
   * neighboring Ultrapeer has a hit in its QRP table for that query.
   */
  public void testDynamicQueryingWithQRPHit() throws Exception {
    assertTrue("should be connected", connectionServices.isConnected());

    searchServices.query(searchServices.newQueryGUID(), match);
    Thread.sleep(4000);

    QueryRequest qSent =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0], QueryRequest.class);

    // The TTL on the sent query should be 1 because the other Ultrapeer
    // should have a "hit" in its QRP table.  When there's a hit, we
    // send with TTL 1 simply because it's likely that it's popular.
    if (qSent.getTTL() != 1) {
      // see if qrp got exchanged properly
      int num = connectionManager.getInitializedConnections().size();
      double totalQrp = 0;
      for (RoutedConnection rc : connectionManager.getInitializedClientConnections())
        totalQrp += rc.getRoutedConnectionStatistics().getQueryRouteTablePercentFull();
      fail(
          "ttl was not 1 but "
              + qSent.getTTL()
              + " there were "
              + num
              + " connections with qrp total "
              + totalQrp);
    }
    assertEquals("wrong hops", 0, qSent.getHops());
  }
 /**
  * Tests that only a limited number of connect back messages are sent upon connection
  * initialization.
  */
 public void testLimitedConnectBacksSent() throws Exception {
   final int max = MAX_TCP_CONNECT_BACK_ATTEMPTS + 3; // not exact
   int received = 0;
   for (int i = 0; i < max; i++) {
     testUP[0].send(messagesSupportedVendorMessage);
     testUP[0].flush();
     testUP[1].send(messagesSupportedVendorMessage);
     testUP[1].flush();
     while (BlockingConnectionUtils.getFirstInstanceOfMessageType(
             testUP[0], TCPConnectBackVendorMessage.class, 100)
         != null) received++;
     while (BlockingConnectionUtils.getFirstInstanceOfMessageType(
             testUP[1], TCPConnectBackVendorMessage.class, 100)
         != null) received++;
   }
   assertLessThan(max, received);
 }
  @Override
  public void setUp() throws Exception {
    networkManagerStub = new NetworkManagerStub();
    Injector injector =
        LimeTestUtils.createInjector(
            Stage.PRODUCTION,
            MyCallback.class,
            new LimeTestUtils.NetworkManagerStubModule(networkManagerStub));
    super.setUp(injector);

    fileManager = injector.getInstance(FileManager.class);
    messagesSupportedVendorMessage = injector.getInstance(MessagesSupportedVendorMessage.class);
    searchServices = injector.getInstance(SearchServices.class);
    responseFactory = injector.getInstance(ResponseFactory.class);
    queryReplyFactory = injector.getInstance(QueryReplyFactory.class);
    replyNumberVendorMessageFactory = injector.getInstance(ReplyNumberVendorMessageFactory.class);
    queryRequestFactory = injector.getInstance(QueryRequestFactory.class);
    downloadServices = injector.getInstance(DownloadServices.class);
    messageRouter = injector.getInstance(MessageRouter.class);
    messageFactory = injector.getInstance(MessageFactory.class);
    pingReplyFactory = injector.getInstance(PingReplyFactory.class);
    onDemandUnicaster = injector.getInstance(OnDemandUnicaster.class);
    callback = (MyCallback) injector.getInstance(ActivityCallback.class);
    macManager = injector.getInstance(MACCalculatorRepositoryManager.class);
    remoteFileDescFactory = injector.getInstance(RemoteFileDescFactory.class);
    pushEndpointFactory = injector.getInstance(PushEndpointFactory.class);

    networkManagerStub.setAcceptedIncomingConnection(true);
    networkManagerStub.setCanReceiveSolicited(true);
    networkManagerStub.setCanReceiveUnsolicited(true);
    networkManagerStub.setOOBCapable(true);
    networkManagerStub.setPort(SERVER_PORT);

    File file = TestUtils.getResourceFile("com/limegroup/gnutella/metadata/metadata.mp3");
    assertNotNull(fileManager.getGnutellaFileList().add(file).get(1, TimeUnit.SECONDS));

    UDP_ACCESS = new DatagramSocket[10];
    for (int i = 0; i < UDP_ACCESS.length; i++) UDP_ACCESS[i] = new DatagramSocket();

    for (int i = 0; i < testUP.length; i++) {
      assertTrue("should be open", testUP[i].isOpen());
      assertTrue(
          "should be up -> leaf",
          testUP[i].getConnectionCapabilities().isSupernodeClientConnection());
      BlockingConnectionUtils.drain(testUP[i], 100);
      // OOB client side needs server side leaf guidance
      testUP[i].send(messagesSupportedVendorMessage);
      testUP[i].flush();
    }

    Thread.sleep(250);

    // we should now be guess capable and tcp incoming capable....
    // test on acceptor since network manager is stubbed out
    //        assertTrue(injector.getInstance(Acceptor.class).acceptedIncoming());
  }
    private void doNormalTest(boolean settingOn, boolean expectTLS) throws Exception {
        
        setAccepted(true);
        
        if(settingOn)
            networkManagerStub.setIncomingTLSEnabled(true);
        
        BlockingConnectionUtils.drain(testUP[0]);
        // some setup
        byte[] clientGUID = GUID.makeGuid();

        // construct and send a query
        byte[] guid = GUID.makeGuid();
        searchServices.query(guid, "golf is awesome");

        // the testUP[0] should get it
        Message m;
        do {
            m = testUP[0].receive(TIMEOUT);
        } while (!(m instanceof QueryRequest));

        // send a reply with NO PushProxy info
        Response[] res = new Response[1];
        res[0] = responseFactory.createResponse(10, 10, "golf is awesome", UrnHelper.SHA1);
        m = queryReplyFactory.createQueryReply(m.getGUID(), (byte) 1, 6355,
                myIP(), 0, res, clientGUID, new byte[0], false, false, true,
                true, false, false, null);
        testUP[0].send(m);
        testUP[0].flush();

        // wait a while for Leaf to process result
        assertNotNull(callback.getRFD());

        // tell the leaf to download the file, should result in normal TCP
        // PushRequest
        Downloader downloader = downloadServices.download(
                (new RemoteFileDesc[] { callback.getRFD() }), true, new GUID(m.getGUID()));

        // await a PushRequest
        do {
            m = testUP[0].receive(25 * TIMEOUT);
        } while (!(m instanceof PushRequest));
        
        PushRequest pr = (PushRequest)m;
        assertNotNull(pr);
        assertEquals(expectTLS, pr.isTLSCapable());
        assertEquals(clientGUID, pr.getClientGUID());
        assertEquals(networkManagerStub.getAddress(), pr.getIP());
        assertEquals(networkManagerStub.getPort(), pr.getPort());
        assertEquals(10, pr.getIndex());
        assertFalse(pr.isFirewallTransferPush());
        
        downloader.stop();
    }
 /**
  * Test to make sure we will never send with a TTL of 1 to a Ultrapeer that doesn't have a hit.
  */
 public void testSentQueryIsNotTTL1() throws Exception {
   assertTrue("should be connected", connectionServices.isConnected());
   searchServices.query(searchServices.newQueryGUID(), noMatch);
   Thread.sleep(2000);
   // we will send the query, but with a TTL of 2, not 1, because
   // the ultrapeer doesn't have this query in its qrp table.
   QueryRequest qSent =
       BlockingConnectionUtils.getFirstInstanceOfMessageType(ULTRAPEER[0], QueryRequest.class);
   assertEquals("wrong ttl", 2, qSent.getTTL());
   assertEquals("wrong hops", 0, qSent.getHops());
 }
  public void testResponse() throws Exception {
    QueryRequest qr = queryRequestFactory.createNonFirewalledQuery("badger", (byte) 1);
    testUP[0].send(qr);
    testUP[0].flush();
    Thread.sleep(1000);
    QueryReply r = BlockingConnectionUtils.getFirstQueryReply(testUP[0]);
    assertNotNull(r);
    QueryReply expected = staticMessages.getLimeReply();
    assertTrue(expected.getResultsAsList().containsAll(r.getResultsAsList()));
    assertTrue(r.getResultsAsList().containsAll(expected.getResultsAsList()));

    // change the words to something else
    SearchSettings.LIME_SEARCH_TERMS.set(new String[] {"mushroom"});
    qr = queryRequestFactory.createNonFirewalledQuery("badger", (byte) 1);
    testUP[0].send(qr);
    testUP[0].flush();
    Thread.sleep(1000);
    r = BlockingConnectionUtils.getFirstQueryReply(testUP[0]);
    assertNull(r);

    qr = queryRequestFactory.createNonFirewalledQuery("mushroom", (byte) 1);
    testUP[0].send(qr);
    testUP[0].flush();
    Thread.sleep(1000);
    r = BlockingConnectionUtils.getFirstQueryReply(testUP[0]);
    assertNotNull(r);
    assertTrue(expected.getResultsAsList().containsAll(r.getResultsAsList()));
    assertTrue(r.getResultsAsList().containsAll(expected.getResultsAsList()));

    // turn off responding completely
    SearchSettings.SEND_LIME_RESPONSES.setValue(0);
    qr = queryRequestFactory.createNonFirewalledQuery("mushroom", (byte) 1);
    testUP[0].send(qr);
    testUP[0].flush();
    Thread.sleep(1000);
    r = BlockingConnectionUtils.getFirstQueryReply(testUP[0]);
    assertNull(r);
  }
  public void testXMLReturned1() throws Exception {
    drainAll();

    // send a query
    QueryRequest query = queryRequestFactory.createQuery("ID3V24");
    ULTRAPEER[0].send(query);
    ULTRAPEER[0].flush();

    // wait for processing
    Thread.sleep(750);

    // confirm that result has heXML.
    QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
    assertNotNull(reply);
    assertNotNull(reply.getXMLBytes());
    assertTrue("xml length = " + reply.getXMLBytes().length, reply.getXMLBytes().length > 10);
  }
  public void testXMLReturned2() throws Exception {
    drainAll();

    String richQuery =
        "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio genre=\"Bass\"></audio></audios>";

    // send a query
    QueryRequest query = queryRequestFactory.createQuery("Bass", richQuery);
    ULTRAPEER[0].send(query);
    ULTRAPEER[0].flush();

    // wait for processing
    Thread.sleep(750);

    // confirm that result has heXML.
    QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
    assertNotNull(reply);
    assertNotNull(reply.getXMLBytes());
    assertTrue("xml length = " + reply.getXMLBytes().length, reply.getXMLBytes().length > 10);
  }
  /**
   * Tests that if the leaf is connected to only one ultrapeer it will send a few redundant requests
   */
  public void testTCPRedundantRequestsSent() throws Exception {
    BlockingConnectionUtils.drainAllParallel(testUP);
    // wait some time - both UPs should get a single connect back
    // sleep
    Thread.sleep(MY_EXPIRE_TIME + 1000);
    readNumConnectBacks(1, testUP[0], TIMEOUT);
    readNumConnectBacks(1, testUP[1], TIMEOUT);

    // leave only one connection open
    assertGreaterThan(1, connectionManager.getNumInitializedConnections());
    testUP[1].close();
    Thread.sleep(500);
    assertEquals(1, connectionManager.getNumInitializedConnections());

    drainAll();
    // sleep
    Thread.sleep(MY_VALIDATE_TIME + 1000);

    // we should receive more than one connect back redirects
    readNumConnectBacks(ConnectionManager.CONNECT_BACK_REDUNDANT_REQUESTS, testUP[0], TIMEOUT);
  }
  public void testBitrateExclusion() throws Exception {
    // test that a mismatching artist name doesn't return a result
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" artist=\"junk\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("junk 64", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we don't get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNull(reply);
    }

    // test that a matching artist name does return a result
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" artist=\"artist test\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("title 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we do get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNotNull(reply);
      assertNotNull(reply.getXMLBytes());
      assertTrue("xml length = " + reply.getXMLBytes().length, reply.getXMLBytes().length > 10);
    }

    // test that a null price value doesn't return a result
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" price=\"$19.99\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("$19.99 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we don't get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNull(reply);
    }

    // 3 fields - bitrate matches, but only one other, so no return
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" artist=\"artist test\" title=\"junk\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("Test junk 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we don't get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNull(reply);
    }

    // 3 fields - all match, should return
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" artist=\"artist test\" title=\"title test\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("Test mpg 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we do get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNotNull(reply);
      assertNotNull(reply.getXMLBytes());
      assertTrue("xml length = " + reply.getXMLBytes().length, reply.getXMLBytes().length > 10);
    }

    // 3 fields - 1 match, 1 null, should return
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" artist=\"artist test\" type=\"Audiobook\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("Test Audiobook 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we do get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNotNull(reply);
      assertNotNull(reply.getXMLBytes());
      assertTrue("xml length = " + reply.getXMLBytes().length, reply.getXMLBytes().length > 10);
    }

    // 3 fields - 2 null, should not return
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" price=\"$19.99\" type=\"Audiobook\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("$19.99 Audiobook 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we don't get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNull(reply);
    }

    // 3 fields - 1 null, 1 mismatch, should not return
    {
      drainAll();

      String richQuery =
          "<?xml version=\"1.0\"?><audios xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/audio.xsd\"><audio bitrate=\"64\" price=\"$19.99\" artist=\"Tester\"></audio></audios>";

      // send a query
      QueryRequest query = queryRequestFactory.createQuery("$19.99 Tester 16", richQuery);
      ULTRAPEER[0].send(query);
      ULTRAPEER[0].flush();

      // wait for processing
      Thread.sleep(750);

      // confirm that we don't get a result
      QueryReply reply = BlockingConnectionUtils.getFirstQueryReply(ULTRAPEER[0]);
      assertNull(reply);
    }
  }
  public void testDownloadFinishes() throws Exception {

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    DatagramPacket pack = null;

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "whatever");
    // i need to pretend that the UI is showing the user the query still
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // ok, the leaf is sending OOB queries - good stuff, now we should send
    // a lot of results back and make sure it buffers the bypassed OOB ones
    for (int i = 0; i < testUP.length; i++) {
      Response[] res = new Response[200];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "whatever " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              qr.getGUID(),
              (byte) 1,
              6355,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // create a test uploader and send back that response
    TestUploader uploader = new TestUploader(networkManagerStub);
    uploader.start("whatever", UPLOADER_PORT, false);
    uploader.setBusy(true);
    URN urn = TestFile.hash();
    RemoteFileDesc rfd = makeRFD(urn);

    // wait for processing
    Thread.sleep(1500);

    // just do it for 1 UDP guy
    {
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(
              new GUID(qr.getGUID()), 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[0].send(pack);
    }

    // wait for processing
    Thread.sleep(500);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(qr.getGUID(), 1);
    }

    long currTime = System.currentTimeMillis();
    Downloader downloader =
        downloadServices.download(new RemoteFileDesc[] {rfd}, false, new GUID(guid));

    final int MAX_TRIES = 60;
    for (int i = 0; i <= MAX_TRIES; i++) {
      Thread.sleep(500);
      if (downloader.getState() == DownloadState.ITERATIVE_GUESSING) break;
      if (i == MAX_TRIES) fail("didn't GUESS!!");
    }

    // we should get a query key request
    {
      boolean gotPing = false;
      while (!gotPing) {
        byte[] datagramBytes = new byte[1000];
        pack = new DatagramPacket(datagramBytes, 1000);
        UDP_ACCESS[0].setSoTimeout(10000); // may need to wait
        UDP_ACCESS[0].receive(pack);
        InputStream in = new ByteArrayInputStream(pack.getData());
        m = messageFactory.read(in, Network.TCP);
        m.hop();
        if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest();
      }
    }

    // send back a query key
    AddressSecurityToken qk =
        new AddressSecurityToken(InetAddress.getLocalHost(), SERVER_PORT, macManager);
    {
      byte[] ip = new byte[] {(byte) 127, (byte) 0, (byte) 0, (byte) 1};
      PingReply pr =
          pingReplyFactory.createQueryKeyReply(
              GUID.makeGuid(), (byte) 1, UDP_ACCESS[0].getLocalPort(), ip, 10, 10, false, qk);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      pr.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[0].send(pack);
    }

    Thread.sleep(500);

    // ensure that it gets into the OnDemandUnicaster
    {
      // now we should make sure MessageRouter retains the key
      Map _queryKeys = (Map) PrivilegedAccessor.getValue(onDemandUnicaster, "_queryKeys");
      assertNotNull(_queryKeys);
      assertEquals(1, _queryKeys.size());
    }

    byte[] urnQueryGUID = null;
    { // confirm a URN query
      boolean gotQuery = false;
      while (!gotQuery) {
        byte[] datagramBytes = new byte[1000];
        pack = new DatagramPacket(datagramBytes, 1000);
        UDP_ACCESS[0].setSoTimeout(10000); // may need to wait
        UDP_ACCESS[0].receive(pack);
        InputStream in = new ByteArrayInputStream(pack.getData());
        m = messageFactory.read(in, Network.TCP);
        if (m instanceof QueryRequest) {
          QueryRequest qReq = (QueryRequest) m;
          Set queryURNs = qReq.getQueryUrns();
          gotQuery = queryURNs.contains(urn);
          if (gotQuery) {
            gotQuery = qReq.getQueryKey().isFor(InetAddress.getLocalHost(), SERVER_PORT);
            if (gotQuery) urnQueryGUID = qReq.getGUID();
          }
        }
      }
    }

    assertNotNull(urnQueryGUID);

    long timeoutVal = 8000 - (System.currentTimeMillis() - currTime);
    Thread.sleep(timeoutVal > 0 ? timeoutVal : 0);
    assertEquals(DownloadState.BUSY, downloader.getState());
    // purge front end of query
    callback.clearGUID();

    // create a new Uploader to service the download
    TestUploader uploader2 = new TestUploader(networkManagerStub);
    uploader2.start("whatever", UPLOADER_PORT + 1, false);
    uploader2.setRate(100);

    { // send back a query request, the TestUploader should service upload
      rfd = makeRFD(urn, UPLOADER_PORT + 1);
      Response[] res = new Response[] {responseFactory.createResponse(10, 10, "whatever", urn)};
      m =
          queryReplyFactory.createQueryReply(
              urnQueryGUID,
              (byte) 1,
              UPLOADER_PORT + 1,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      m.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[0].send(pack);
    }

    // after a while, the download should finish, the bypassed results
    // should be discarded
    Thread.sleep(10000);
    assertEquals(DownloadState.COMPLETE, downloader.getState());

    {
      // now we should make sure MessageRouter clears the map
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }
    uploader.stopThread();
  }
    private void doQRPCGTest(boolean sendTLS, boolean settingOn, boolean listenTLS) throws Exception {
        if(settingOn)
            networkManagerStub.setOutgoingTLSEnabled(true);
        
    	setAccepted(false);
        BlockingConnectionUtils.drain(testUP[0]);

        // make sure leaf is sharing
        assertEquals(2, gnutellaFileView.size());
        assertEquals(1, connectionManager.getNumConnections());

        // send a query that should be answered
        QueryRequest query = queryRequestFactory.createQueryRequest(GUID.makeGuid(), (byte) 1,
                "berkeley", null, null, null, false, Network.UNKNOWN, false, 0);
        testUP[0].send(query);
        testUP[0].flush();

        // await a response
        Message m;
        do {
            m = testUP[0].receive(TIMEOUT);
        } while (!(m instanceof QueryReply));

        // confirm it has proxy info
        QueryReply reply = (QueryReply) m;
        assertNotNull(reply.getPushProxies());

        // check out PushProxy info
        Set proxies = reply.getPushProxies();
        assertEquals(1, proxies.size());
        Iterator iter = proxies.iterator();
        IpPort ppi = (IpPort) iter.next();
        assertEquals(ppi.getPort(), 6355);
        assertTrue(ppi.getInetAddress().equals(testUP[0].getInetAddress()));

        // set up a ServerSocket to get give on
        ServerSocket ss;
        if(listenTLS) {
            SSLContext context = SSLUtils.getTLSContext();
            SSLServerSocket sslServer = (SSLServerSocket)context.getServerSocketFactory().createServerSocket();
            sslServer.setNeedClientAuth(false);
            sslServer.setWantClientAuth(false);
            sslServer.setEnabledCipherSuites(new String[] {"TLS_DH_anon_WITH_AES_128_CBC_SHA"});
            ss = sslServer;
        } else {
            ss = new ServerSocket();
        }

        try {
            ss.setReuseAddress(true);        
            ss.setSoTimeout(TIMEOUT);
            ss.bind(new InetSocketAddress(9000));
            // test that the client responds to a PushRequest
            PushRequest pr = new PushRequestImpl(GUID.makeGuid(), (byte) 1, 
                                             applicationServices.getMyGUID(),
                                             0, 
                                             InetAddress.getLocalHost().getAddress(),
                                             9000,
                                             Network.TCP,
                                             sendTLS);

            // send the PR off
            testUP[0].send(pr);
            testUP[0].flush();

            // we should get a incoming GIV
            Socket givSock = ss.accept();
            try {
                assertNotNull(givSock);

                // start reading and confirming the HTTP request
                String currLine;
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(givSock.getInputStream()));

                // confirm a GIV
                currLine = reader.readLine();
                GUID guid = new GUID(
                        applicationServices.getMyGUID());
                String givLine = "GIV 0:" + guid.toHexString();
                assertTrue(currLine.startsWith(givLine));
            } finally {
                givSock.close();
            }
        } finally {
            ss.close();
        }
    }
  public void testSendsPushRequest() throws Exception {
    BlockingConnectionUtils.drain(testUP[0]);
    // some setup
    final byte[] clientGUID = GUID.makeGuid();

    // construct and send a query
    byte[] guid = GUID.makeGuid();
    searchServices.query(guid, "anita");

    // the testUP[0] should get it
    Message m = null;
    do {
      m = testUP[0].receive(TIMEOUT);
    } while (!(m instanceof QueryRequest));

    // send a reply with some BAD PushProxy info
    final IpPortSet proxies = new IpPortSet(new IpPortImpl("127.0.0.1", 7001));
    Response[] res =
        new Response[] {responseFactory.createResponse(10, 10, "anita.yay", UrnHelper.SHA1)};
    m =
        queryReplyFactory.createQueryReply(
            m.getGUID(),
            (byte) 1,
            7000,
            InetAddress.getLocalHost().getAddress(),
            0,
            res,
            clientGUID,
            new byte[0],
            true,
            false,
            true,
            true,
            false,
            false,
            proxies);
    testUP[0].send(m);
    testUP[0].flush();

    // wait a while for Leaf to process result
    assertNotNull(callback.getRFD());

    // tell the leaf to browse host the file,
    searchServices.doAsynchronousBrowseHost(
        new MockFriendPresence(
            new MockFriend(), null, new AddressFeature(callback.getRFD().getAddress())),
        new GUID(),
        new BrowseListener() {
          public void handleBrowseResult(SearchResult searchResult) {
            // To change body of implemented methods use File | Settings | File Templates.
          }

          public void browseFinished(boolean success) {
            // To change body of implemented methods use File | Settings | File Templates.
          }
        });
    // nothing works for the guy, we should get a PushRequest
    do {
      m = testUP[0].receive(TIMEOUT * 30);
    } while (!(m instanceof PushRequest));

    // awesome - everything checks out!
  }
  public void testMultipleDownloadsNoPurge() throws Exception {

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    DatagramPacket pack = null;

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "whatever");
    // i need to pretend that the UI is showing the user the query still
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // ok, the leaf is sending OOB queries - good stuff, now we should send
    // a lot of results back and make sure it buffers the bypassed OOB ones
    for (int i = 0; i < testUP.length; i++) {
      Response[] res = new Response[200];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "whatever " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              qr.getGUID(),
              (byte) 1,
              6355,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // create a test uploader and send back that response
    TestUploader uploader = new TestUploader(networkManagerStub);
    uploader.start("whatever", UPLOADER_PORT, false);
    uploader.setBusy(true);
    RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ");

    TestUploader uploader2 = new TestUploader(networkManagerStub);
    uploader2.start("whatever", UPLOADER_PORT * 2, false);
    uploader2.setBusy(true);
    RemoteFileDesc rfd2 = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSASUSH");

    // wait for processing
    Thread.sleep(1500);

    { // bypass 1 result only
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(
              new GUID(qr.getGUID()), 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[0].send(pack);
    }

    // wait for processing
    Thread.sleep(500);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(qr.getGUID(), 1);
    }

    Downloader downloader =
        downloadServices.download(new RemoteFileDesc[] {rfd}, false, new GUID(guid));

    //  Don't try using the same default file
    Downloader downloader2 =
        downloadServices.download(
            new RemoteFileDesc[] {rfd2}, new GUID(guid), false, null, "anotherFile");

    // let downloaders do stuff
    final int MAX_TRIES = 60;
    boolean oneGood = false, twoGood = false;
    for (int i = 0; i <= MAX_TRIES; i++) {
      Thread.sleep(500);
      if (downloader.getState() == DownloadState.BUSY) oneGood = true;
      if (downloader2.getState() == DownloadState.BUSY) twoGood = true;
      if (oneGood && twoGood) break;
      if (i == MAX_TRIES) fail("didn't GUESS!!");
    }

    callback.clearGUID(); // isQueryAlive == false
    downloader.stop();

    Thread.sleep(500);

    {
      // we should still have bypassed results since downloader2 alive
      assertByPassedResultsCacheHasSize(qr.getGUID(), 1);
    }

    downloader2.stop();
    Thread.sleep(1000);

    {
      // now we should make sure MessageRouter clears the map
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }
    uploader.stopThread();
    uploader2.stopThread();
  }
  public void testPushProxyRequest() throws Exception {
    // wait for connections to process any messages
    Thread.sleep(6000);

    BlockingConnectionUtils.drain(testUP[0]);
    // some setup
    final byte[] clientGUID = GUID.makeGuid();

    // construct and send a query
    byte[] guid = GUID.makeGuid();
    searchServices.query(guid, "nyu.edu");

    // the testUP[0] should get it
    Message m = null;
    do {
      m = testUP[0].receive(TIMEOUT);
    } while (!(m instanceof QueryRequest));

    // set up a server socket to wait for proxy request
    ServerSocket ss = new ServerSocket(7000);
    try {
      ss.setReuseAddress(true);
      ss.setSoTimeout(TIMEOUT * 4);

      // send a reply with some PushProxy info
      final IpPortSet proxies = new IpPortSet();
      proxies.add(new IpPortImpl("127.0.0.1", 7000));
      Response[] res = new Response[1];
      res[0] = responseFactory.createResponse(10, 10, "nyu.edu", UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              m.getGUID(),
              (byte) 1,
              6999,
              InetAddress.getLocalHost().getAddress(),
              0,
              res,
              clientGUID,
              new byte[0],
              true,
              false,
              true,
              true,
              false,
              false,
              proxies);
      testUP[0].send(m);
      testUP[0].flush();

      // wait a while for Leaf to process result
      assertNotNull(callback.getRFD());

      // tell the leaf to browse host the file, should result in PushProxy
      // request
      searchServices.doAsynchronousBrowseHost(
          new MockFriendPresence(
              new MockFriend(), null, new AddressFeature(callback.getRFD().getAddress())),
          new GUID(),
          new BrowseListener() {
            public void handleBrowseResult(SearchResult searchResult) {
              // To change body of implemented methods use File | Settings | File Templates.
            }

            public void browseFinished(boolean success) {
              // To change body of implemented methods use File | Settings | File Templates.
            }
          });

      // wait for the incoming PushProxy request
      // increase the timeout since we send udp pushes first
      ss.setSoTimeout(7000);
      Socket httpSock = ss.accept();
      try {
        BufferedWriter sockWriter =
            new BufferedWriter(
                new OutputStreamWriter(httpSock.getOutputStream(), HTTP.DEFAULT_PROTOCOL_CHARSET));
        sockWriter.write("HTTP/1.1 202 OK\r\n");
        sockWriter.flush();

        // start reading and confirming the HTTP request
        String currLine = null;
        BufferedReader reader =
            new BufferedReader(
                new InputStreamReader(httpSock.getInputStream(), HTTP.DEFAULT_PROTOCOL_CHARSET));

        // confirm a GET/HEAD pushproxy request
        currLine = reader.readLine();
        assertTrue(
            currLine.startsWith("GET /gnutella/push-proxy")
                || currLine.startsWith("HEAD /gnutella/push-proxy"));

        // make sure it sends the correct client GUID
        int beginIndex = currLine.indexOf("ID=") + 3;
        String guidString = currLine.substring(beginIndex, beginIndex + 26);
        GUID guidFromBackend = new GUID(clientGUID);
        GUID guidFromNetwork = new GUID(Base32.decode(guidString));
        assertEquals(guidFromNetwork, guidFromBackend);

        // make sure the node sends the correct X-Node
        currLine = reader.readLine();
        assertTrue(currLine.startsWith("X-Node:"));
        StringTokenizer st = new StringTokenizer(currLine, ":");
        assertEquals(st.nextToken(), "X-Node");
        InetAddress addr = InetAddress.getByName(st.nextToken().trim());
        Arrays.equals(addr.getAddress(), networkManagerStub.getAddress());
        assertEquals(SERVER_PORT, Integer.parseInt(st.nextToken()));

        // now we need to GIV
        Socket push = new Socket(InetAddress.getLocalHost(), SERVER_PORT);
        try {
          BufferedWriter writer =
              new BufferedWriter(
                  new OutputStreamWriter(push.getOutputStream(), HTTP.DEFAULT_PROTOCOL_CHARSET));
          writer.write("GIV 0:" + new GUID(clientGUID).toHexString() + "/\r\n");
          writer.write("\r\n");
          writer.flush();

          assertIsBrowse(push, push.getLocalPort());
        } finally {
          push.close();
        }
      } finally {
        httpSock.close();
      }

      try {
        do {
          m = testUP[0].receive(TIMEOUT);
          assertNotInstanceof(m.toString(), PushRequest.class, m);
        } while (true);
      } catch (InterruptedIOException expected) {
      }
    } finally {
      ss.close();
    }
  }
  // RUN THIS TEST LAST!!
  // TODO move this test case to OnDemandUnicasterTest, sounds like a pure unit test
  // proabably doesn't make sense anymore since it doesn't have any data from the
  // previous tests to clear
  public void testUnicasterClearingCode() throws Exception {

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    { // clear all the unicaster data structures
      Long[] longs = new Long[] {new Long(0), new Long(1)};
      Class[] classTypes = new Class[] {Long.TYPE, Long.TYPE};
      // now confirm that clearing code works
      Object ret =
          PrivilegedAccessor.invokeMethod(
              onDemandUnicaster, "clearDataStructures", longs, classTypes);
      assertTrue(ret instanceof Boolean);
      assertTrue(((Boolean) ret).booleanValue());
    }

    DatagramPacket pack = null;

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "whatever");
    // i need to pretend that the UI is showing the user the query still
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // ok, the leaf is sending OOB queries - good stuff, now we should send
    // a lot of results back and make sure it buffers the bypassed OOB ones
    for (int i = 0; i < testUP.length; i++) {
      Response[] res = new Response[200];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "whatever " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              qr.getGUID(),
              (byte) 1,
              6355,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // create a test uploader and send back that response
    TestUploader uploader = new TestUploader(networkManagerStub);
    uploader.start("whatever", UPLOADER_PORT, false);
    uploader.setBusy(true);
    RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ");

    // wait for processing
    Thread.sleep(1500);

    for (int i = 0; i < UDP_ACCESS.length; i++) {
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(
              new GUID(qr.getGUID()), i + 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[i].send(pack);
    }

    // wait for processing
    Thread.sleep(500);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(qr.getGUID(), UDP_ACCESS.length);
    }

    Downloader downloader =
        downloadServices.download(new RemoteFileDesc[] {rfd}, false, new GUID(guid));

    final int MAX_TRIES = 60;
    for (int i = 0; i <= MAX_TRIES; i++) {
      Thread.sleep(500);
      if (downloader.getState() == DownloadState.ITERATIVE_GUESSING) break;
      if (i == MAX_TRIES) fail("didn't GUESS!!");
    }

    // we should start getting guess queries on all UDP ports, actually
    // querykey requests
    for (int i = 0; i < UDP_ACCESS.length; i++) {
      boolean gotPing = false;
      while (!gotPing) {
        try {
          byte[] datagramBytes = new byte[1000];
          pack = new DatagramPacket(datagramBytes, 1000);
          UDP_ACCESS[i].setSoTimeout(10000); // may need to wait
          UDP_ACCESS[i].receive(pack);
          InputStream in = new ByteArrayInputStream(pack.getData());
          m = messageFactory.read(in, Network.TCP);
          m.hop();
          if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest();
        } catch (InterruptedIOException iioe) {
          assertTrue("was successful for " + i, false);
        }
      }
    }

    // Prepopulate Query Keys
    AddressSecurityToken qk =
        new AddressSecurityToken(InetAddress.getLocalHost(), SERVER_PORT, macManager);
    for (int i = 0; i < (UDP_ACCESS.length / 2); i++) {
      byte[] ip = new byte[] {(byte) 127, (byte) 0, (byte) 0, (byte) 1};
      PingReply pr =
          pingReplyFactory.createQueryKeyReply(
              GUID.makeGuid(), (byte) 1, UDP_ACCESS[i].getLocalPort(), ip, 10, 10, false, qk);
      pr.hop();
      onDemandUnicaster.handleQueryKeyPong(pr);
    }

    // ensure that it gets into the OnDemandUnicaster
    {
      // now we should make sure MessageRouter retains the key
      Map _queryKeys = (Map) PrivilegedAccessor.getValue(onDemandUnicaster, "_queryKeys");
      assertNotNull(_queryKeys);
      assertEquals((UDP_ACCESS.length / 2), _queryKeys.size());

      // now make sure some URNs are still buffered
      Map _bufferedURNs = (Map) PrivilegedAccessor.getValue(onDemandUnicaster, "_bufferedURNs");
      assertNotNull(_bufferedURNs);
      assertEquals((UDP_ACCESS.length / 2), _bufferedURNs.size());
    }

    // now until those guys get expired
    Thread.sleep(60 * 1000);

    {
      Long[] longs = new Long[] {new Long(0), new Long(1)};
      Class[] classTypes = new Class[] {Long.TYPE, Long.TYPE};
      // now confirm that clearing code works
      Object ret =
          PrivilegedAccessor.invokeMethod(
              onDemandUnicaster, "clearDataStructures", longs, classTypes);
      assertTrue(ret instanceof Boolean);
      assertTrue(((Boolean) ret).booleanValue());
    }

    // ensure that clearing worked
    {
      // now we should make sure MessageRouter retains the key
      Map _queryKeys = (Map) PrivilegedAccessor.getValue(onDemandUnicaster, "_queryKeys");
      assertNotNull(_queryKeys);
      assertEquals(0, _queryKeys.size());

      // now make sure some URNs are still buffered
      Map _bufferedURNs = (Map) PrivilegedAccessor.getValue(onDemandUnicaster, "_bufferedURNs");
      assertNotNull(_bufferedURNs);
      assertEquals(0, _bufferedURNs.size());
    }

    assertEquals(DownloadState.BUSY, downloader.getState());

    callback.clearGUID();
    downloader.stop();

    Thread.sleep(1000);

    {
      // now we should make sure MessageRouter clears the map
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }
  }
  public void testHTTPRequest() throws Exception {

    BlockingConnectionUtils.drain(testUP[0]);
    // some setup
    final byte[] clientGUID = GUID.makeGuid();

    // construct and send a query
    byte[] guid = GUID.makeGuid();
    searchServices.query(guid, "boalt.org");

    // the testUP[0] should get it
    Message m = null;
    do {
      m = testUP[0].receive(TIMEOUT);
    } while (!(m instanceof QueryRequest));

    // set up a server socket
    ServerSocket ss = new ServerSocket(7000);
    try {
      ss.setReuseAddress(true);
      ss.setSoTimeout(TIMEOUT);

      // send a reply
      Response[] res = new Response[1];
      res[0] = responseFactory.createResponse(10, 10, "boalt.org", UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              m.getGUID(),
              (byte) 1,
              7000,
              InetAddress.getLocalHost().getAddress(),
              0,
              res,
              clientGUID,
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[0].send(m);
      testUP[0].flush();

      // wait a while for Leaf to process result
      assertNotNull(callback.getRFD());

      // tell the leaf to browse host the file, should result in direct HTTP
      // request
      searchServices.doAsynchronousBrowseHost(
          new MockFriendPresence(
              new MockFriend(), null, new AddressFeature(callback.getRFD().getAddress())),
          new GUID(),
          new BrowseListener() {
            public void handleBrowseResult(SearchResult searchResult) {
              // To change body of implemented methods use File | Settings | File Templates.
            }

            public void browseFinished(boolean success) {
              // To change body of implemented methods use File | Settings | File Templates.
            }
          });

      // wait for the incoming HTTP request
      Socket httpSock = ss.accept();
      try {
        assertIsBrowse(httpSock, 7000);
      } finally {
        httpSock.close();
      }

      try {
        do {
          m = testUP[0].receive(TIMEOUT);
          assertTrue(!(m instanceof PushRequest));
        } while (true);
      } catch (InterruptedIOException expected) {
      }
    } finally {
      // awesome - everything checks out!
      ss.close();
    }
  }
  public void testNoDownloadQueryDonePurge() throws Exception {

    // set smaller clear times so we can test in a timely fashion

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "whatever");
    // i need to pretend that the UI is showing the user the query still
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // ok, the leaf is sending OOB queries - good stuff, now we should send
    // a lot of results back and make sure it buffers the bypassed OOB ones
    for (int i = 0; i < testUP.length; i++) {
      Response[] res = new Response[200];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "whatever " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              qr.getGUID(),
              (byte) 1,
              6355,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // wait for processing
    Thread.sleep(2000);

    for (int i = 0; i < UDP_ACCESS.length; i++) {
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(
              new GUID(qr.getGUID()), i + 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      DatagramPacket pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[i].send(pack);
    }

    // wait for processing
    Thread.sleep(1000);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(qr.getGUID(), UDP_ACCESS.length);
    }

    {
      // now we should make sure MessageRouter clears the map
      searchServices.stopQuery(new GUID(qr.getGUID()));
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }
    callback.clearGUID();
  }
    private void doHTTPRequestTest(boolean settingOn, boolean expectTLS) throws Exception {
        if(settingOn)
            networkManagerStub.setIncomingTLSEnabled(true);
        
    	setAccepted(true);
        BlockingConnectionUtils.drain(testUP[0]);
        // some setup
        byte[] clientGUID = GUID.makeGuid();

        // construct and send a query
        byte[] guid = GUID.makeGuid();
        searchServices.query(guid, "boalt.org");

        // the testUP[0] should get it
        Message m;
        do {
            m = testUP[0].receive(TIMEOUT);
        } while (!(m instanceof QueryRequest));

        // set up a server socket
        ServerSocket ss = new ServerSocket(7000);
        try {
            ss.setReuseAddress(true);
            ss.setSoTimeout(25 * TIMEOUT);

            // send a reply with some PushProxy info
            Set<IpPort> proxies = new TreeSet<IpPort>(IpPort.COMPARATOR);
            proxies.add(new IpPortImpl("127.0.0.1", 7000));
            Response[] res = new Response[1];
            res[0] = responseFactory.createResponse(10, 10, "boalt.org", UrnHelper.SHA1);
            m = queryReplyFactory.createQueryReply(m.getGUID(), (byte) 1, 6355,
                    myIP(), 0, res, clientGUID, new byte[0], true, false,
                    true, true, false, false, proxies);
            testUP[0].send(m);
            testUP[0].flush();

            // wait a while for Leaf to process result
            assertNotNull(callback.getRFD());


            // tell the leaf to download the file, should result in push proxy
            // request
            Downloader download = downloadServices.download((new RemoteFileDesc[] 
                { callback.getRFD() }), true, 
                    new GUID(m.getGUID()));
    
            // wait for the incoming HTTP request
            Socket httpSock = ss.accept();
            try {
                assertNotNull(httpSock);
        
                // start reading and confirming the HTTP request
                String currLine;
                BufferedReader reader = 
                    new BufferedReader(new
                                       InputStreamReader(httpSock.getInputStream()));
        
                // confirm a GET/HEAD pushproxy request
                currLine = reader.readLine();
                assertTrue(currLine.startsWith("GET /gnutella/push-proxy") ||
                           currLine.startsWith("HEAD /gnutella/push-proxy"));
                
                if(expectTLS) {
                    assertTrue(currLine.contains("tls=true"));
                } else {
                    assertFalse(currLine.contains("tls"));
                }
                
                // make sure it sends the correct client GUID
                int beginIndex = currLine.indexOf("ID=") + 3;
                String guidString = currLine.substring(beginIndex, beginIndex+26);
                GUID guidFromBackend = new GUID(clientGUID);
                GUID guidFromNetwork = new GUID(Base32.decode(guidString));
                assertEquals(guidFromNetwork, guidFromBackend);
        
                // make sure the node sends the correct X-Node
                currLine = reader.readLine();
                assertTrue(currLine.startsWith("X-Node:"));
                StringTokenizer st = new StringTokenizer(currLine, ":");
                assertEquals(st.nextToken(), "X-Node");
                InetAddress addr = InetAddress.getByName(st.nextToken().trim());
                Arrays.equals(addr.getAddress(), networkManagerStub.getAddress());
                assertEquals(PORT, Integer.parseInt(st.nextToken()));
        
                // send back a 202 and make sure no PushRequest is sent via the normal
                // way
                BufferedWriter writer = 
                    new BufferedWriter(new
                                       OutputStreamWriter(httpSock.getOutputStream()));
                
                writer.write("HTTP/1.1 202 gobbledygook");
                writer.flush();
            } finally {
                httpSock.close();
            }
    
            try {
                do {
                    m = testUP[0].receive(TIMEOUT);
                    assertTrue(!(m instanceof PushRequest));
                } while (true) ;
            } catch (InterruptedIOException ignore) {}
    
            // now make a connection to the leaf to confirm that it will send a
            // correct download request
            Socket push = new Socket(InetAddress.getLocalHost(), PORT);
            try {
                BufferedWriter writer = 
                    new BufferedWriter(new
                                       OutputStreamWriter(push.getOutputStream()));
                writer.write("GIV ");
                writer.flush();
                NIOTestUtils.waitForNIO();
                
                // the PUSH request is not matched in PushList.getBestHost() if 
                // this is set to false: the RemoteFileDesc contains the IP 
                // 192.168.0.1 but since we are connecting from a different IP 
                // it is not matched but it'll accept it this is set to true and 
                // both IPs are private 
                ConnectionSettings.LOCAL_IS_PRIVATE.setValue(true); 
                writer.write("0:" + new GUID(clientGUID).toHexString() + "/\r\n");
                writer.write("\r\n"); 
                writer.flush(); 
          
               BufferedReader reader = new BufferedReader(new InputStreamReader(push.getInputStream())); 
               String currLine = reader.readLine(); 
               assertEquals(MessageFormat.format("GET /uri-res/N2R?{0} HTTP/1.1", UrnHelper.SHA1), currLine); 
           } finally { 
               push.close(); 
           }
           
           download.stop();
           
       } finally { 
           ss.close(); 
       } 
    }
  public void testDownloadProgressQueryDoneNoPurge() throws Exception {

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    // luckily there is hacky little way to go through the download paces -
    // download from yourself :) .

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "metadata");
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // just return ONE real result and the rest junk
    Response resp = null;
    QueryReply reply = null;
    {
      // get a correct response object
      QueryRequest qrTemp = queryRequestFactory.createQuery("metadata");
      testUP[0].send(qrTemp);
      testUP[0].flush();

      reply = BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryReply.class);
      assertNotNull(reply);
      resp = (reply.getResultsAsList()).get(0);
    }
    assertNotNull(reply);
    assertNotNull(resp);
    Response[] res = new Response[] {resp};

    // this isn't really needed but just for completeness send it back to
    // the test Leaf
    m =
        queryReplyFactory.createQueryReply(
            guid,
            (byte) 1,
            SERVER_PORT,
            myIP(),
            0,
            res,
            GUID.makeGuid(),
            new byte[0],
            false,
            false,
            true,
            true,
            false,
            false,
            null);
    testUP[0].send(m);
    testUP[0].flush();

    // send back a lot of results via TCP so you konw the UDP one will be
    // bypassed
    for (int i = 0; i < testUP.length; i++) {
      res = new Response[75];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "metadata " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              guid,
              (byte) 1,
              testUP[0].getPort(),
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // allow for processing
    Thread.sleep(3000);

    {
      // now we should make sure MessageRouter has not bypassed anything
      // yet
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }

    // send back a UDP response and make sure it was saved in bypassed...
    {
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(new GUID(guid), 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      DatagramPacket pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[0].send(pack);
    }

    // allow for processing
    Thread.sleep(500);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(guid, 1);
    }

    // now do the download, wait for it to finish, and then bypassed results
    // should be empty again
    RemoteFileDesc rfd =
        resp.toRemoteFileDesc(reply, null, remoteFileDescFactory, pushEndpointFactory);

    assertFalse("file should not be saved yet", new File(_savedDir, "metadata.mp3").exists());

    downloadServices.download(new RemoteFileDesc[] {rfd}, false, new GUID(guid));
    UploadSettings.UPLOAD_SPEED.setValue(5);

    searchServices.stopQuery(new GUID(guid));
    callback.clearGUID();

    // download still in progress, don't purge
    assertByPassedResultsCacheHasSize(guid, 1);

    UploadSettings.UPLOAD_SPEED.setValue(100);

    // sleep to make sure the download starts
    Thread.sleep(20000);

    assertTrue("file should saved", new File(_savedDir, "metadata.mp3").exists());

    // now we should make sure MessageRouter clears the cache
    assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
  }
    public void testCanReactToBadPushProxy() throws Exception {
        // assume client accepted connections from the outside successfully
        setAccepted(true);
        
        BlockingConnectionUtils.drain(testUP[0]);
        // some setup
        byte[] clientGUID = GUID.makeGuid();

        // construct and send a query
        byte[] guid = GUID.makeGuid();
        searchServices.query(guid, "berkeley.edu");

        // the testUP[0] should get it
        Message m;
        do {
            m = testUP[0].receive(TIMEOUT);
        } while (!(m instanceof QueryRequest));

        // set up a server socket
        ServerSocket ss = new ServerSocket(7000);
        try {
            ss.setReuseAddress(true);
            ss.setSoTimeout(25 * TIMEOUT);

            // send a reply with some BAD PushProxy info
            // PushProxyInterface[] proxies = new
            // QueryReply.PushProxyContainer[2];
            Set<IpPort> proxies = new TreeSet<IpPort>(IpPort.COMPARATOR);
            proxies.add(new IpPortImpl("127.0.0.1", 7000));
            proxies.add(new IpPortImpl("127.0.0.1", 8000));
            Response[] res = new Response[1];
            res[0] = responseFactory.createResponse(10, 10, "berkeley.edu", UrnHelper.SHA1);
            m = queryReplyFactory.createQueryReply(m.getGUID(), (byte) 1, 6355,
                    myIP(), 0, res, clientGUID, new byte[0], true, false,
                    true, true, false, false, proxies);
            testUP[0].send(m);
            testUP[0].flush();

            // wait a while for Leaf to process result
            assertNotNull(callback.getRFD());

            // tell the leaf to download the file, should result in push proxy
            // request
            downloadServices
                    .download(
                            (new RemoteFileDesc[] { callback.getRFD() }), true, new GUID((m.getGUID())));

            // wait for the incoming HTTP request
            Socket httpSock = ss.accept();
            try {
                // send back an error and make sure the PushRequest is sent via
                // the normal way
                BufferedWriter writer = new BufferedWriter(
                        new OutputStreamWriter(httpSock.getOutputStream()));

                writer.write("HTTP/1.1 410 gobbledygook");
                writer.flush();
            } finally {
                httpSock.close();
            }

            // await a PushRequest
            do {
                m = testUP[0].receive(TIMEOUT * 8);
            } while (!(m instanceof PushRequest));
        } finally {
            ss.close();
        }
    }
  public void testBusyDownloadLocatesSources() throws Exception {

    BlockingConnectionUtils.keepAllAlive(testUP, pingReplyFactory);
    // clear up any messages before we begin the test.
    drainAll();

    DatagramPacket pack = null;

    Message m = null;

    byte[] guid = searchServices.newQueryGUID();
    searchServices.query(guid, "whatever");
    // i need to pretend that the UI is showing the user the query still
    callback.setGUID(new GUID(guid));

    QueryRequest qr =
        BlockingConnectionUtils.getFirstInstanceOfMessageType(testUP[0], QueryRequest.class);
    assertNotNull(qr);
    assertTrue(qr.desiresOutOfBandReplies());

    // ok, the leaf is sending OOB queries - good stuff, now we should send
    // a lot of results back and make sure it buffers the bypassed OOB ones
    for (int i = 0; i < testUP.length; i++) {
      Response[] res = new Response[200];
      for (int j = 0; j < res.length; j++)
        res[j] =
            responseFactory.createResponse(
                10 + j + i, 10 + j + i, "whatever " + j + i, UrnHelper.SHA1);
      m =
          queryReplyFactory.createQueryReply(
              qr.getGUID(),
              (byte) 1,
              6355,
              myIP(),
              0,
              res,
              GUID.makeGuid(),
              new byte[0],
              false,
              false,
              true,
              true,
              false,
              false,
              null);
      testUP[i].send(m);
      testUP[i].flush();
    }

    // create a test uploader and send back that response
    TestUploader uploader = new TestUploader(networkManagerStub);
    uploader.start("whatever", UPLOADER_PORT, false);
    uploader.setBusy(true);
    RemoteFileDesc rfd = makeRFD("GLIQY64M7FSXBSQEZY37FIM5QQSA2OUJ");

    // wait for processing
    Thread.sleep(1500);

    for (int i = 0; i < UDP_ACCESS.length; i++) {
      ReplyNumberVendorMessage vm =
          replyNumberVendorMessageFactory.createV3ReplyNumberVendorMessage(
              new GUID(qr.getGUID()), i + 1);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      vm.write(baos);
      pack =
          new DatagramPacket(
              baos.toByteArray(),
              baos.toByteArray().length,
              testUP[0].getInetAddress(),
              SERVER_PORT);
      UDP_ACCESS[i].send(pack);
    }

    // wait for processing
    Thread.sleep(500);

    {
      // all the UDP ReplyNumberVMs should have been bypassed
      assertByPassedResultsCacheHasSize(qr.getGUID(), UDP_ACCESS.length);
    }

    Downloader downloader =
        downloadServices.download(new RemoteFileDesc[] {rfd}, false, new GUID(guid));

    final int MAX_TRIES = 60;
    for (int i = 0; i <= MAX_TRIES; i++) {
      Thread.sleep(1000);
      if (downloader.getState() == DownloadState.ITERATIVE_GUESSING) break;
      if (i == MAX_TRIES) fail("didn't GUESS!!");
    }

    // we should start getting guess queries on all UDP ports, actually
    // querykey requests
    for (int i = 0; i < UDP_ACCESS.length; i++) {
      boolean gotPing = false;
      while (!gotPing) {
        try {
          byte[] datagramBytes = new byte[1000];
          pack = new DatagramPacket(datagramBytes, 1000);
          UDP_ACCESS[i].setSoTimeout(10000); // may need to wait
          UDP_ACCESS[i].receive(pack);
          InputStream in = new ByteArrayInputStream(pack.getData());
          m = messageFactory.read(in, Network.TCP);
          m.hop();
          if (m instanceof PingRequest) gotPing = ((PingRequest) m).isQueryKeyRequest();
        } catch (InterruptedIOException iioe) {
          fail("was successful for " + i, iioe);
        }
      }
    }

    // Thread.sleep((UDP_ACCESS.length * 1000) -
    // (System.currentTimeMillis() - currTime));
    int guessWaitTime = 5000;
    Thread.sleep(guessWaitTime + 2000);
    assertEquals(DownloadState.BUSY, downloader.getState());

    callback.clearGUID();
    downloader.stop();

    Thread.sleep(1000);

    {
      // now we should make sure MessageRouter clears the map
      assertByPassedResultsCacheHasSize(qr.getGUID(), 0);
    }

    uploader.stopThread();
  }