added simple_client (and added it in the docs as well).

updated documentation to include some sample code.
fixed a nasty network bug.
It now seems to work on linux (at least in cygwin).
This commit is contained in:
Arvid Norberg 2003-11-23 03:00:45 +00:00
parent 086dbd40fe
commit a1356219da
9 changed files with 888 additions and 739 deletions

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ The main goals of libtorrent are:
libtorrent is not finished. It is an ongoing project (including this documentation). libtorrent is not finished. It is an ongoing project (including this documentation).
The current state includes the following features: The current state includes the following features:
* multitracker extension support (as `described by TheShadow`_) * multitracker extension support (as `described by TheShadow`__)
* serves multiple torrents on a single port and a single thread * serves multiple torrents on a single port and a single thread
* supports http proxies and proxy authentication * supports http proxies and proxy authentication
* gzipped tracker-responses * gzipped tracker-responses
@ -41,7 +41,7 @@ The current state includes the following features:
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock). thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
* can limit the upload bandwidth usage * can limit the upload bandwidth usage
.. _`described by TheShadow`: http://home.elp.rr.com/tur/multitracker-spec.txt __ http://home.elp.rr.com/tur/multitracker-spec.txt
.. _Azureus: http://azureus.sourceforge.net .. _Azureus: http://azureus.sourceforge.net
Functions that are yet to be implemented: Functions that are yet to be implemented:
@ -55,7 +55,7 @@ Functions that are yet to be implemented:
* a good upload speed cap * a good upload speed cap
libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread, libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread,
boost.filesystem and various other boost libraries and zlib. boost.filesystem boost.date_time and various other boost libraries and zlib.
libtorrent has been successfully compiled and tested on: libtorrent has been successfully compiled and tested on:
@ -588,7 +588,39 @@ peer every second. It may be -1 if there's no limit.
address address
------- -------
TODO The ``address`` class represents a name of a network endpoint (usually referred to as
IP-address) and a port number. This is the same thing as a ``sockaddr_in`` would contain.
Its declaration looks like this::
class address
{
public:
address();
address(
unsigned char a
, unsigned char b
, unsigned char c
, unsigned char d
, unsigned short port);
address(unsigned int addr, unsigned short port);
address(const std::string& addr, unsigned short port);
address(const address& a);
~address();
std::string as_string() const;
unsigned int ip() const;
unsigned short port() const;
bool operator<(const address& a) const;
bool operator!=(const address& a) const;
bool operator==(const address& a) const;
};
It is less-than comparable to make it possible to use it as a key in a map. ``as_string()`` may block
while it does the DNS lookup, it returns a string that points to the address represented by the object.
``ip()`` will return the 32-bit ip-address as an integer. ``port()`` returns the port number.
@ -681,6 +713,127 @@ The sha1-algorithm used was implemented by Steve Reid and released as public dom
For more info, see ``src/sha1.c``. For more info, see ``src/sha1.c``.
example usage
-------------
dump_torrent
~~~~~~~~~~~~
This is an example of a program that will take a torrent-file as a parameter and
print information about it to std out::
#include <iostream>
#include <fstream>
#include <iterator>
#include <exception>
#include <vector>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/http_settings.hpp"
int main(int argc, char* argv[])
{
using namespace libtorrent;
if (argc != 2)
{
std::cerr << "usage: dump_torrent torrent-file\n";
return 1;
}
try
{
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
// print info about torrent
std::cout << "\n\n----- torrent file info -----\n\n";
std::cout << "trackers:\n";
for (std::vector<announce_entry>::const_iterator i = t.trackers().begin();
i != t.trackers().end();
++i)
{
std::cout << i->tier << ": " << i->url << "\n";
}
std::cout << "number of pieces: " << t.num_pieces() << "\n";
std::cout << "piece length: " << t.piece_length() << "\n";
std::cout << "files:\n";
for (torrent_info::file_iterator i = t.begin_files();
i != t.end_files();
++i)
{
std::cout << " " << std::setw(11) << i->size
<< " " << i->path << " " << i->filename << "\n";
}
}
catch (std::exception& e)
{
std::cout << e.what() << "\n";
}
return 0;
}
simple client
~~~~~~~~~~~~~
This is a simple client. It doesn't have much output to keep it simple::
#include <iostream>
#include <fstream>
#include <iterator>
#include <exception>
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/http_settings.hpp"
int main(int argc, char* argv[])
{
using namespace libtorrent;
if (argc != 2)
{
std::cerr << "usage: ./simple_cient torrent-file\n"
"to stop the client, press return.\n";
return 1;
}
try
{
session s(6881, "E\x1");
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
s.add_torrent(t, "");
// wait for the user to end
char a;
std::cin.unsetf(std::ios_base::skipws);
std::cin >> a;
}
catch (std::exception& e)
{
std::cout << e.what() << "\n";
}
return 0;
}
Feedback Feedback
======== ========
@ -693,8 +846,9 @@ You can usually find me as hydri in ``#btports @ irc.freenode.net``.
Credits Aknowledgements
======= ===============
Written by Arvid Norberg. Copyright (c) 2003 Arvid Norberg
Copyright (c) 2003 Arvid Norberg

View File

@ -123,12 +123,12 @@ bool sleep_and_input(char* c)
void set_cursor(int x, int y) void set_cursor(int x, int y)
{ {
// std::cout << "\033[" << y << ";" << x << "H"; std::cout << "\033[" << y << ";" << x << "H";
} }
void clear() void clear()
{ {
// std::cout << "\033[2J"; std::cout << "\033[2J";
} }
#endif #endif

77
examples/simple_client.cpp Executable file
View File

@ -0,0 +1,77 @@
/*
Copyright (c) 2003, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <iostream>
#include <fstream>
#include <iterator>
#include <exception>
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/http_settings.hpp"
int main(int argc, char* argv[])
{
using namespace libtorrent;
if (argc != 2)
{
std::cerr << "usage: ./simple_cient torrent-file\n"
"to stop the client, press return.\n";
return 1;
}
try
{
session s(6881, "E\x1");
std::ifstream in(argv[1], std::ios_base::binary);
in.unsetf(std::ios_base::skipws);
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
torrent_info t(e);
s.add_torrent(t, "");
// wait for the user to end
char a;
std::cin.unsetf(std::ios_base::skipws);
std::cin >> a;
}
catch (std::exception& e)
{
std::cout << e.what() << "\n";
}
return 0;
}

View File

@ -79,13 +79,13 @@ namespace libtorrent
address(const address& a); address(const address& a);
~address(); ~address();
std::string as_string() const throw(); std::string as_string() const;
unsigned int ip() const throw() { return m_sockaddr.sin_addr.s_addr; } unsigned int ip() const { return m_sockaddr.sin_addr.s_addr; }
unsigned short port() const throw() { return htons(m_sockaddr.sin_port); } unsigned short port() const { return htons(m_sockaddr.sin_port); }
bool operator<(const address& a) const throw() { if (ip() == a.ip()) return port() < a.port(); else return ip() < a.ip(); } bool operator<(const address& a) const { if (ip() == a.ip()) return port() < a.port(); else return ip() < a.ip(); }
bool operator!=(const address& a) const throw() { return (ip() != a.ip()) || port() != a.port(); } bool operator!=(const address& a) const { return (ip() != a.ip()) || port() != a.port(); }
bool operator==(const address& a) const throw() { return (ip() == a.ip()) && port() == a.port(); } bool operator==(const address& a) const { return (ip() == a.ip()) && port() == a.port(); }
private: private:

View File

@ -164,13 +164,17 @@ namespace libtorrent
void tracker_request_timed_out() void tracker_request_timed_out()
{ {
std::cerr << "TRACKER TIMED OUT\n"; #ifndef NDEBUG
debug_log("*** tracker timed out");
#endif
try_next_tracker(); try_next_tracker();
} }
void tracker_request_error(const char* str) void tracker_request_error(const char* str)
{ {
std::cerr << "TRACKER ERROR: " << str << "\n"; #ifndef NDEBUG
debug_log(std::string("*** tracker error: ") + str);
#endif
try_next_tracker(); try_next_tracker();
} }

View File

@ -51,8 +51,6 @@ POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
// TODO: add std::string comment()
namespace libtorrent namespace libtorrent
{ {

View File

@ -97,6 +97,7 @@ libtorrent::peer_connection::peer_connection(
, m_send_quota(-1) , m_send_quota(-1)
, m_send_quota_left(-1) , m_send_quota_left(-1)
{ {
assert(!m_socket->is_blocking());
assert(m_torrent != 0); assert(m_torrent != 0);
#ifndef NDEBUG #ifndef NDEBUG
@ -140,6 +141,7 @@ libtorrent::peer_connection::peer_connection(
, m_send_quota(-1) , m_send_quota(-1)
, m_send_quota_left(-1) , m_send_quota_left(-1)
{ {
assert(!m_socket->is_blocking());
#ifndef NDEBUG #ifndef NDEBUG
m_logger = m_ses->create_log(s->sender().as_string().c_str()); m_logger = m_ses->create_log(s->sender().as_string().c_str());
@ -712,8 +714,10 @@ void libtorrent::peer_connection::send_have(int index)
// throws exception when the client should be disconnected // throws exception when the client should be disconnected
void libtorrent::peer_connection::receive_data() void libtorrent::peer_connection::receive_data()
{ {
assert(!m_socket->is_blocking());
for(;;) for(;;)
{ {
// m_socket->set_blocking(false);
int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos); int received = m_socket->receive(&m_recv_buffer[m_recv_pos], m_packet_size - m_recv_pos);
// connection closed // connection closed
@ -899,6 +903,7 @@ void libtorrent::peer_connection::receive_data()
break; break;
case read_packet: case read_packet:
if (!dispatch_message()) if (!dispatch_message())
{ {
#ifndef NDEBUG #ifndef NDEBUG

View File

@ -230,7 +230,6 @@ namespace libtorrent
} }
#endif #endif
// if nothing happens within 500000 microseconds (0.5 seconds) // if nothing happens within 500000 microseconds (0.5 seconds)
// do the loop anyway to check if anything else has changed // do the loop anyway to check if anything else has changed
// (*m_logger) << "sleeping\n"; // (*m_logger) << "sleeping\n";
@ -257,7 +256,6 @@ namespace libtorrent
break; break;
} }
// ************************ // ************************
// RECEIVE SOCKETS // RECEIVE SOCKETS
// ************************ // ************************
@ -267,11 +265,11 @@ namespace libtorrent
i != readable_clients.end(); i != readable_clients.end();
++i) ++i)
{ {
// special case for listener socket // special case for listener socket
if (*i == listener) if (*i == listener)
{ {
boost::shared_ptr<libtorrent::socket> s = (*i)->accept(); boost::shared_ptr<libtorrent::socket> s = (*i)->accept();
s->set_blocking(false);
if (s) if (s)
{ {
// we got a connection request! // we got a connection request!
@ -289,6 +287,7 @@ namespace libtorrent
m_selector.monitor_readability(s); m_selector.monitor_readability(s);
m_selector.monitor_errors(s); m_selector.monitor_errors(s);
} }
continue; continue;
} }
@ -301,7 +300,7 @@ namespace libtorrent
{ {
try try
{ {
// (*m_logger) << "readable: " << p->first->sender().as_string() << "\n"; // (*m_logger) << "readable: " << p->first->sender().as_string() << "\n";
p->second->receive_data(); p->second->receive_data();
} }
catch(network_error&) catch(network_error&)
@ -314,7 +313,6 @@ namespace libtorrent
} }
} }
// ************************ // ************************
// SEND SOCKETS // SEND SOCKETS
// ************************ // ************************
@ -350,8 +348,6 @@ namespace libtorrent
} }
} }
// ************************ // ************************
// ERROR SOCKETS // ERROR SOCKETS
// ************************ // ************************
@ -378,12 +374,10 @@ namespace libtorrent
} }
#endif #endif
boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer; boost::posix_time::time_duration d = boost::posix_time::second_clock::local_time() - timer;
if (d.seconds() < 1) continue; if (d.seconds() < 1) continue;
timer = boost::posix_time::second_clock::local_time(); timer = boost::posix_time::second_clock::local_time();
// ************************ // ************************
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND // THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
// ************************ // ************************
@ -470,6 +464,7 @@ namespace libtorrent
<< " b/s \n"; << " b/s \n";
} }
#endif #endif
} }
while (!m_tracker_manager.send_finished()) while (!m_tracker_manager.send_finished())