Package com.turn.ttorrent.common.protocol.http

Source Code of com.turn.ttorrent.common.protocol.http.HTTPAnnounceRequestMessage

/**
* Copyright (C) 2012 Turn, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.turn.ttorrent.common.protocol.http;

import com.turn.ttorrent.bcodec.BDecoder;
import com.turn.ttorrent.bcodec.BEValue;
import com.turn.ttorrent.bcodec.BEncoder;
import com.turn.ttorrent.bcodec.InvalidBEncodingException;
import com.turn.ttorrent.common.Peer;
import com.turn.ttorrent.common.Torrent;
import com.turn.ttorrent.common.protocol.TrackerMessage.AnnounceRequestMessage;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;


/**
* The announce request message for the HTTP tracker protocol.
*
* <p>
* This class represents the announce request message in the HTTP tracker
* protocol. It doesn't add any specific fields compared to the generic
* announce request message, but it provides the means to parse such
* messages and craft them.
* </p>
*
* @author mpetazzoni
*/
public class HTTPAnnounceRequestMessage extends HTTPTrackerMessage
  implements AnnounceRequestMessage {

  private final byte[] infoHash;
  private final Peer peer;
  private final long uploaded;
  private final long downloaded;
  private final long left;
  private final boolean compact;
  private final boolean noPeerId;
  private final RequestEvent event;
  private final int numWant;

  private HTTPAnnounceRequestMessage(ByteBuffer data,
    byte[] infoHash, Peer peer, long uploaded, long downloaded,
    long left, boolean compact, boolean noPeerId, RequestEvent event,
    int numWant) {
    super(Type.ANNOUNCE_REQUEST, data);
    this.infoHash = infoHash;
    this.peer = peer;
    this.downloaded = downloaded;
    this.uploaded = uploaded;
    this.left = left;
    this.compact = compact;
    this.noPeerId = noPeerId;
    this.event = event;
    this.numWant = numWant;
  }

  @Override
  public byte[] getInfoHash() {
    return this.infoHash;
  }

  @Override
  public String getHexInfoHash() {
    return Torrent.byteArrayToHexString(this.infoHash);
  }

  @Override
  public byte[] getPeerId() {
    return this.peer.getPeerId().array();
  }

  @Override
  public String getHexPeerId() {
    return this.peer.getHexPeerId();
  }

  @Override
  public int getPort() {
    return this.peer.getPort();
  }

  @Override
  public long getUploaded() {
    return this.uploaded;
  }

  @Override
  public long getDownloaded() {
    return this.downloaded;
  }

  @Override
  public long getLeft() {
    return this.left;
  }

  @Override
  public boolean getCompact() {
    return this.compact;
  }

  @Override
  public boolean getNoPeerIds() {
    return this.noPeerId;
  }

  @Override
  public RequestEvent getEvent() {
    return this.event;
  }

  @Override
  public String getIp() {
    return this.peer.getIp();
  }

  @Override
  public int getNumWant() {
    return this.numWant;
  }

  /**
   * Build the announce request URL for the given tracker announce URL.
   *
   * @param trackerAnnounceURL The tracker's announce URL.
   * @return The URL object representing the announce request URL.
   */
  public URL buildAnnounceURL(URL trackerAnnounceURL)
    throws UnsupportedEncodingException, MalformedURLException {
    String base = trackerAnnounceURL.toString();
    StringBuilder url = new StringBuilder(base);
    url.append(base.contains("?") ? "&" : "?")
      .append("info_hash=")
      .append(URLEncoder.encode(
        new String(this.getInfoHash(), Torrent.BYTE_ENCODING),
        Torrent.BYTE_ENCODING))
      .append("&peer_id=")
      .append(URLEncoder.encode(
        new String(this.getPeerId(), Torrent.BYTE_ENCODING),
        Torrent.BYTE_ENCODING))
      .append("&port=").append(this.getPort())
      .append("&uploaded=").append(this.getUploaded())
      .append("&downloaded=").append(this.getDownloaded())
      .append("&left=").append(this.getLeft())
      .append("&compact=").append(this.getCompact() ? 1 : 0)
      .append("&no_peer_id=").append(this.getNoPeerIds() ? 1 : 0);

    if (this.getEvent() != null &&
      !RequestEvent.NONE.equals(this.getEvent())) {
      url.append("&event=").append(this.getEvent().getEventName());
    }

    if (this.getIp() != null) {
      url.append("&ip=").append(this.getIp());
    }

    return new URL(url.toString());
  }

  public static HTTPAnnounceRequestMessage parse(ByteBuffer data)
    throws IOException, MessageValidationException {
    BEValue decoded = BDecoder.bdecode(data);
    if (decoded == null) {
      throw new MessageValidationException(
        "Could not decode tracker message (not B-encoded?)!");
    }

    Map<String, BEValue> params = decoded.getMap();

    if (!params.containsKey("info_hash")) {
      throw new MessageValidationException(
        ErrorMessage.FailureReason.MISSING_HASH.getMessage());
    }

    if (!params.containsKey("peer_id")) {
      throw new MessageValidationException(
        ErrorMessage.FailureReason.MISSING_PEER_ID.getMessage());
    }

    if (!params.containsKey("port")) {
      throw new MessageValidationException(
        ErrorMessage.FailureReason.MISSING_PORT.getMessage());
    }

    try {
      byte[] infoHash = params.get("info_hash").getBytes();
      byte[] peerId = params.get("peer_id").getBytes();
      int port = params.get("port").getInt();

      // Default 'uploaded' and 'downloaded' to 0 if the client does
      // not provide it (although it should, according to the spec).
      long uploaded = 0;
      if (params.containsKey("uploaded")) {
        uploaded = params.get("uploaded").getLong();
      }

      long downloaded = 0;
      if (params.containsKey("downloaded")) {
        downloaded = params.get("downloaded").getLong();
      }

      // Default 'left' to -1 to avoid peers entering the COMPLETED
      // state when they don't provide the 'left' parameter.
      long left = -1;
      if (params.containsKey("left")) {
        left = params.get("left").getLong();
      }

      boolean compact = false;
      if (params.containsKey("compact")) {
        compact = params.get("compact").getInt() == 1;
      }

      boolean noPeerId = false;
      if (params.containsKey("no_peer_id")) {
        noPeerId = params.get("no_peer_id").getInt() == 1;
      }

      int numWant = AnnounceRequestMessage.DEFAULT_NUM_WANT;
      if (params.containsKey("numwant")) {
        numWant = params.get("numwant").getInt();
      }

      String ip = null;
      if (params.containsKey("ip")) {
        ip = params.get("ip").getString(Torrent.BYTE_ENCODING);
      }

      RequestEvent event = RequestEvent.NONE;
      if (params.containsKey("event")) {
        event = RequestEvent.getByName(params.get("event")
          .getString(Torrent.BYTE_ENCODING));
      }

      return new HTTPAnnounceRequestMessage(data, infoHash,
        new Peer(ip, port, ByteBuffer.wrap(peerId)),
        uploaded, downloaded, left, compact, noPeerId,
        event, numWant);
    } catch (InvalidBEncodingException ibee) {
      throw new MessageValidationException(
        "Invalid HTTP tracker request!", ibee);
    }
  }

  public static HTTPAnnounceRequestMessage craft(byte[] infoHash,
    byte[] peerId, int port, long uploaded, long downloaded, long left,
    boolean compact, boolean noPeerId, RequestEvent event,
    String ip, int numWant)
    throws IOException, MessageValidationException,
      UnsupportedEncodingException {
    Map<String, BEValue> params = new HashMap<String, BEValue>();
    params.put("info_hash", new BEValue(infoHash));
    params.put("peer_id", new BEValue(peerId));
    params.put("port", new BEValue(port));
    params.put("uploaded", new BEValue(uploaded));
    params.put("downloaded", new BEValue(downloaded));
    params.put("left", new BEValue(left));
    params.put("compact", new BEValue(compact ? 1 : 0));
    params.put("no_peer_id", new BEValue(noPeerId ? 1 : 0));

    if (event != null) {
      params.put("event",
        new BEValue(event.getEventName(), Torrent.BYTE_ENCODING));
    }

    if (ip != null) {
      params.put("ip",
        new BEValue(ip, Torrent.BYTE_ENCODING));
    }

    if (numWant != AnnounceRequestMessage.DEFAULT_NUM_WANT) {
      params.put("numwant", new BEValue(numWant));
    }

    return new HTTPAnnounceRequestMessage(
      BEncoder.bencode(params),
      infoHash, new Peer(ip, port, ByteBuffer.wrap(peerId)),
      uploaded, downloaded, left, compact, noPeerId, event, numWant);
  }
}
TOP

Related Classes of com.turn.ttorrent.common.protocol.http.HTTPAnnounceRequestMessage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.