Ticket #925: main.cc

File main.cc, 5.1 KB (added by deepgreen, 4 years ago)
Line 
1// Under the GPL with OpenSSL exception, see the libtorrent license.
2// This program is pretty minimal, but shows most of the steps
3// required to download a torrent.
4
5#include <cerrno>
6#include <iostream>
7#include <fstream>
8#include <sstream>
9#include <stdexcept>
10#include <signal.h>
11#include <unistd.h>
12#include <sys/time.h>
13#include <torrent/object_stream.h>
14#include <torrent/object.h>
15#include <torrent/torrent.h>
16#include <torrent/http.h>
17#include <torrent/poll_select.h>
18#include <torrent/connection_manager.h>
19#include <sigc++/bind.h>
20#include <sigc++/hide.h>
21
22#include "curl_get.h"
23#include "curl_stack.h"
24
25bool doShutdown = false;
26
27void
28chunk_passed(torrent::Download d) {
29  //std::cout << d.name() << ' ' << d.chunks_done() << '/' << d.chunks_total() << std::endl;
30}
31
32void
33finished_download(torrent::Download d) {
34  std::cout << "Finished: " << d.name() << std::endl;
35
36  d.stop();
37
38  // torrent::Download::close() closes the tracker manager, so it
39  // won't send the STOPPED message. Do this later.
40  //d.close();
41
42  //torrent::ConnectionManager::listen_close();
43  torrent::connection_manager()->listen_close();
44
45  // Do a quick shutdown without cleaning up or sending messages to
46  // the trackers.
47  doShutdown = true;
48}
49
50void
51hash_check_done(torrent::Download d) {
52  std::cout << "Hash check completed." << std::endl;
53  d.start();
54  chunk_passed(d);
55}
56
57void
58http_done(torrent::Http* curlGet) {
59  curlGet->close();
60  std::cout << "Finished http download." << std::endl << std::flush;
61
62  torrent::Object *obj=new torrent::Object();
63 
64  *(curlGet->stream()) >> * obj;
65
66  //torrent::Download d = torrent::download_add(curlGet->stream());
67  torrent::Download d = torrent::download_add(obj);
68
69  //d.signal_hash_done(sigc::bind(sigc::ptr_fun(&hash_check_done), d));
70  d.signal_download_done(sigc::bind(sigc::ptr_fun(&finished_download), d));
71  //d.signal_chunk_passed(sigc::hide(sigc::bind(sigc::ptr_fun(&chunk_passed), d)));
72  d.signal_chunk_passed(sigc::hide(sigc::bind(sigc::ptr_fun(&hash_check_done), d)));
73  d.open();
74  d.hash_check(false);
75}
76
77void
78http_failed(const std::string& msg, torrent::Http* curlGet) {
79  std::cout << "Failed http download: " << msg << "." << std::endl << std::flush;
80}
81
82int
83main(int argc, char** argv) {
84  try {
85    if (argc != 2)
86      throw std::runtime_error("Wrong number of arguments.");
87   
88    // Network connections can throw SIGPIPE, so it is best to ignore it.
89    signal(SIGPIPE, SIG_IGN);
90
91    // 512 max open sockets, just a random number. A real client
92    // checks sysconf(OC_OPEN_MAX). libTorrent uses this to allocate a
93    // resonable amount of file descriptors for open files, network
94    // connections and some for the client to use.
95    //
96    // See torrent::initialize for the ratios.
97    torrent::PollSelect* pollSelect = torrent::PollSelect::create(512);
98
99    core::CurlStack::global_init();
100    core::CurlStack curlStack;
101
102    // 'torrent::Http::set_factory(...)' must be set to a slot that
103    //
104    // will create an object that handle http downloads. This is used
105    // for tracker requests.
106    torrent::Http::set_factory(curlStack.get_http_factory());
107    torrent::Http* curlGet = torrent::Http::call_factory();
108
109    torrent::initialize(pollSelect);
110
111    // Fix the bug caused by not calling this?
112    if (!torrent::connection_manager()->listen_open(10000, 14000))
113      throw std::runtime_error("Could not open a listening port.");
114
115    std::stringstream httpDownload;
116
117    curlGet->signal_done().connect(sigc::bind(sigc::ptr_fun(&http_done), curlGet));
118    curlGet->signal_failed().connect(sigc::bind(sigc::ptr_fun(&http_failed), curlGet));
119    curlGet->set_url(argv[1]);
120    curlGet->set_stream(&httpDownload);
121    curlGet->start();
122
123    std::cout << "Starting download." << std::endl;
124
125    fd_set readSet;
126    fd_set writeSet;
127    fd_set errorSet;
128
129    // Shutdown should wait for torrent::is_inactive to return true,
130    // with a resonable timeout. This will make sure trackers receive
131    // the STOPPED message.
132
133    while (!doShutdown) {
134      FD_ZERO(&readSet);
135      FD_ZERO(&writeSet);
136      FD_ZERO(&errorSet);
137
138      unsigned int maxFd = pollSelect->fdset(&readSet, &writeSet, &errorSet);
139
140      if (curlStack.is_busy())
141        maxFd = std::max(maxFd, curlStack.fdset(&readSet, &writeSet, &errorSet));
142
143      int64_t t = std::min<int64_t>(1000000, torrent::next_timeout());
144      timeval timeout = { t / 1000000, t % 1000000 };
145
146      if (select(maxFd + 1, &readSet, &writeSet, &errorSet, &timeout) == -1 &&
147          errno != EINTR)
148        throw std::runtime_error("Error polling.");
149
150      if (curlStack.is_busy())
151        curlStack.perform();
152
153      // 'torrent::perform()' updates the cached time and runs any
154      // scheduled tasks. We call it again to remove any task that
155      // might have immediate timeout or that have timed out during
156      // the call to 'pollSelect::perform(...)'.
157      torrent::perform();
158      pollSelect->perform(&readSet, &writeSet, &errorSet);
159      torrent::perform();
160    }
161
162    // Cleanup is for the weak.
163    torrent::cleanup();
164
165    core::CurlStack::global_cleanup();
166    delete pollSelect;
167
168  } catch (std::exception& e) {
169    std::cout << "Caught: " << e.what() << std::endl;
170  }
171 
172  return 0;
173}