Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/ttorrent-torrent
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
# limitations under the License.

EXEFILE="${0%-torrent}"
MAINCLASS="com.turn.ttorrent.common.Torrent" "${EXEFILE}" "$@"
MAINCLASS="com.turn.ttorrent.cli.TorrentMain" "${EXEFILE}" "$@"
2 changes: 1 addition & 1 deletion bin/ttorrent-tracker
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
# limitations under the License.

EXEFILE="${0%-tracker}"
MAINCLASS="com.turn.ttorrent.tracker.Tracker" "${EXEFILE}" "$@"
MAINCLASS="com.turn.ttorrent.cli.TrackerMain" "${EXEFILE}" "$@"
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.turn.ttorrent.client.Client</Main-Class>
<Main-Class>com.turn.ttorrent.cli.ClientMain</Main-Class>
</manifestEntries>
</transformer>
</transformers>
Expand Down
176 changes: 176 additions & 0 deletions src/main/java/com/turn/ttorrent/cli/ClientMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* Copyright (C) 2011-2013 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.cli;

import com.turn.ttorrent.client.Client;
import com.turn.ttorrent.client.SharedTorrent;

import java.io.File;
import java.io.PrintStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.UnsupportedAddressTypeException;
import java.util.Enumeration;

import jargs.gnu.CmdLineParser;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.PatternLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Command-line entry-point for starting a {@link Client}
*/
public class ClientMain {

private static final Logger logger =
LoggerFactory.getLogger(ClientMain.class);

/**
* Default data output directory.
*/
private static final String DEFAULT_OUTPUT_DIRECTORY = "/tmp";

/**
* Returns a usable {@link Inet4Address} for the given interface name.
*
* <p>
* If an interface name is given, return the first usable IPv4 address for
* that interface. If no interface name is given or if that interface
* doesn't have an IPv4 address, return's localhost address (if IPv4).
* </p>
*
* <p>
* It is understood this makes the client IPv4 only, but it is important to
* remember that most BitTorrent extensions (like compact peer lists from
* trackers and UDP tracker support) are IPv4-only anyway.
* </p>
*
* @param iface The network interface name.
* @return A usable IPv4 address as a {@link Inet4Address}.
* @throws UnsupportedAddressTypeException If no IPv4 address was available
* to bind on.
*/
private static Inet4Address getIPv4Address(String iface)
throws SocketException, UnsupportedAddressTypeException,
UnknownHostException {
if (iface != null) {
Enumeration<InetAddress> addresses =
NetworkInterface.getByName(iface).getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr instanceof Inet4Address) {
return (Inet4Address)addr;
}
}
}

InetAddress localhost = InetAddress.getLocalHost();
if (localhost instanceof Inet4Address) {
return (Inet4Address)localhost;
}

throw new UnsupportedAddressTypeException();
}

/**
* Display program usage on the given {@link PrintStream}.
*/
private static void usage(PrintStream s) {
s.println("usage: Client [options] <torrent>");
s.println();
s.println("Available options:");
s.println(" -h,--help Show this help and exit.");
s.println(" -o,--output DIR Read/write data to directory DIR.");
s.println(" -i,--iface IFACE Bind to interface IFACE.");
s.println(" -s,--seed SECONDS Time to seed after downloading (default: infinitely).");
s.println(" -d,--max-download KB/SEC Max download rate (default: unlimited).");
s.println(" -u,--max-upload KB/SEC Max upload rate (default: unlimited).");
s.println();
}

/**
* Main client entry point for stand-alone operation.
*/
public static void main(String[] args) {
BasicConfigurator.configure(new ConsoleAppender(
new PatternLayout("%d [%-25t] %-5p: %m%n")));

CmdLineParser parser = new CmdLineParser();
CmdLineParser.Option help = parser.addBooleanOption('h', "help");
CmdLineParser.Option output = parser.addStringOption('o', "output");
CmdLineParser.Option iface = parser.addStringOption('i', "iface");
CmdLineParser.Option seedTime = parser.addIntegerOption('s', "seed");
CmdLineParser.Option maxUpload = parser.addDoubleOption('u', "max-upload");
CmdLineParser.Option maxDownload = parser.addDoubleOption('d', "max-download");

try {
parser.parse(args);
} catch (CmdLineParser.OptionException oe) {
System.err.println(oe.getMessage());
usage(System.err);
System.exit(1);
}

// Display help and exit if requested
if (Boolean.TRUE.equals((Boolean)parser.getOptionValue(help))) {
usage(System.out);
System.exit(0);
}

String outputValue = (String)parser.getOptionValue(output,
DEFAULT_OUTPUT_DIRECTORY);
String ifaceValue = (String)parser.getOptionValue(iface);
int seedTimeValue = (Integer)parser.getOptionValue(seedTime, -1);

double maxDownloadRate = (Double)parser.getOptionValue(maxDownload, 0.0);
double maxUploadRate = (Double)parser.getOptionValue(maxUpload, 0.0);

String[] otherArgs = parser.getRemainingArgs();
if (otherArgs.length != 1) {
usage(System.err);
System.exit(1);
}

try {
Client c = new Client(
getIPv4Address(ifaceValue),
SharedTorrent.fromFile(
new File(otherArgs[0]),
new File(outputValue)));

c.setMaxDownloadRate(maxDownloadRate);
c.setMaxUploadRate(maxUploadRate);

// Set a shutdown hook that will stop the sharing/seeding and send
// a STOPPED announce request.
Runtime.getRuntime().addShutdownHook(
new Thread(new Client.ClientShutdown(c, null)));

c.share(seedTimeValue);
if (Client.ClientState.ERROR.equals(c.getState())) {
System.exit(1);
}
} catch (Exception e) {
logger.error("Fatal error: {}", e.getMessage(), e);
System.exit(2);
}
}
}
169 changes: 169 additions & 0 deletions src/main/java/com/turn/ttorrent/cli/TorrentMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* Copyright (C) 2011-2013 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.cli;

import com.turn.ttorrent.common.Torrent;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.util.Arrays;

import jargs.gnu.CmdLineParser;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.PatternLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Command-line entry-point for reading and writing {@link Torrent} files.
*/
public class TorrentMain {

private static final Logger logger =
LoggerFactory.getLogger(TorrentMain.class);

/**
* Display program usage on the given {@link PrintStream}.
*/
private static void usage(PrintStream s) {
usage(s, null);
}

/**
* Display a message and program usage on the given {@link PrintStream}.
*/
private static void usage(PrintStream s, String msg) {
if (msg != null) {
s.println(msg);
s.println();
}

s.println("usage: Torrent [options] [file|directory]");
s.println();
s.println("Available options:");
s.println(" -h,--help Show this help and exit.");
s.println(" -t,--torrent FILE Use FILE to read/write torrent file.");
s.println();
s.println(" -c,--create Create a new torrent file using " +
"the given announce URL and data.");
s.println(" -a,--announce Tracker URL (can be repeated).");
s.println();
}

/**
* Torrent reader and creator.
*
* <p>
* You can use the {@code main()} function of this class to read or create
* torrent files. See usage for details.
* </p>
*
* TODO: support multiple announce URLs.
*/
public static void main(String[] args) {
BasicConfigurator.configure(new ConsoleAppender(
new PatternLayout("%-5p: %m%n")));

CmdLineParser parser = new CmdLineParser();
CmdLineParser.Option help = parser.addBooleanOption('h', "help");
CmdLineParser.Option filename = parser.addStringOption('t', "torrent");
CmdLineParser.Option create = parser.addBooleanOption('c', "create");
CmdLineParser.Option announce = parser.addStringOption('a', "announce");

try {
parser.parse(args);
} catch (CmdLineParser.OptionException oe) {
System.err.println(oe.getMessage());
usage(System.err);
System.exit(1);
}

// Display help and exit if requested
if (Boolean.TRUE.equals((Boolean)parser.getOptionValue(help))) {
usage(System.out);
System.exit(0);
}

String filenameValue = (String)parser.getOptionValue(filename);
if (filenameValue == null) {
usage(System.err, "Torrent file must be provided!");
System.exit(1);
}

Boolean createFlag = (Boolean)parser.getOptionValue(create);
String announceURL = (String)parser.getOptionValue(announce);

String[] otherArgs = parser.getRemainingArgs();

if (Boolean.TRUE.equals(createFlag) &&
(otherArgs.length != 1 || announceURL == null)) {
usage(System.err, "Announce URL and a file or directory must be " +
"provided to create a torrent file!");
System.exit(1);
}

OutputStream fos = null;
try {
if (Boolean.TRUE.equals(createFlag)) {
if (filenameValue != null) {
fos = new FileOutputStream(filenameValue);
} else {
fos = System.out;
}

URI announceURI = new URI(announceURL);
File source = new File(otherArgs[0]);
if (!source.exists() || !source.canRead()) {
throw new IllegalArgumentException(
"Cannot access source file or directory " +
source.getName());
}

String creator = String.format("%s (ttorrent)",
System.getProperty("user.name"));

Torrent torrent = null;
if (source.isDirectory()) {
File[] files = source.listFiles();
Arrays.sort(files);
torrent = Torrent.create(source, Arrays.asList(files),
announceURI, creator);
} else {
torrent = Torrent.create(source, announceURI, creator);
}

torrent.save(fos);
} else {
Torrent.load(new File(filenameValue), true);
}
} catch (Exception e) {
logger.error("{}", e.getMessage(), e);
System.exit(2);
} finally {
if (fos != null && fos != System.out) {
try {
fos.close();
} catch (IOException ioe) {
}
}
}
}
}
Loading