1 /* libundertow - undertow-download-bt.cpp
2 * Copyright (C) 2008 Michael Frank <msfrank@syntaxjockey.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #ifdef ENABLE_BITTORRENT
28 #include <boost/format.hpp>
29 #include <boost/date_time/posix_time/posix_time.hpp>
30 #include <libtorrent/entry.hpp>
31 #include <libtorrent/bencode.hpp>
32 #include <libtorrent/session.hpp>
33 #include <libtorrent/torrent.hpp>
35 #include "undertow-closure-private.h"
36 #include "undertow-db-private.h"
37 #include "undertow-download-private.h"
38 #include "undertow-error.h"
39 #include "undertow-http-private.h"
40 #include "undertow-logging.h"
41 #include "undertow-main-private.h"
43 /* in order to call this code from C, we need to declare it 'extern C'.
44 * also important to note that the extern C block should not enclose
45 * preprocessor includes, otherwise we get a ridiculously long string of
50 static libtorrent::session
*bt_session
= NULL
;
55 boost::filesystem::path::default_name_check(boost::filesystem::no_check
);
58 bt_session
= new libtorrent::session ();
59 bt_session
->listen_on(std::make_pair(6881, 6889));
60 bt_session
->set_severity_level (libtorrent::alert::debug
);
61 lut_log_debug ("bt: finished initialization");
64 catch (std::exception
& e
)
66 lut_log_error ("bt: caught exception: %s", e
.what());
77 lut_log_debug ("bt: cleanup complete");
82 lut_download_bt (lut_download_ctxt
*ctxt
)
89 /* grab the torrent info file */
90 lut_log_debug ("bt: downloading torrent info from %s", ctxt
->content_url
);
91 retval
= lut_http_get (ctxt
->content_url
, &buffer
, &buflen
, NULL
, NULL
, NULL
);
92 if (retval
!= LUT_OK
) {
93 lut_log_info ("bt: failed to download torrent info from %s: %s",
95 lut_strerror (retval
));
101 /* convert the data into an entry object by bdecode()ing it */
102 libtorrent::entry e
= libtorrent::bdecode(buffer
, buffer
+ buflen
);
103 libtorrent::torrent_handle handle
=
104 bt_session
->add_torrent(libtorrent::torrent_info(e
), "./");
105 libtorrent::torrent_info info
= handle
.get_torrent_info ();
106 lut_log_debug ("bt: downloading %s", handle
.name().c_str());
108 /* loop until either we have completed downloading or there was an error */
112 /* check for any alerts */
114 std::auto_ptr<libtorrent::alert> a = bt_sessionpop_alert ();
115 if (a.get () != NULL)
116 lut_log_debug ("bt: alert: %s", a->msg ());
118 /* get the torrent's current status */
119 libtorrent::torrent_status status
= handle
.status();
120 if (status
.state
== old_state
&& old_state
!= 4)
122 switch (status
.state
) {
124 lut_log_debug ("bt: queued for checking");
127 lut_log_debug ("bt: checking files");
130 lut_log_debug ("bt: connecting to tracker");
133 lut_log_debug ("bt: downloading metadata");
136 c
= lut_closure_new__sizet_sizet_float_float (ctxt
->on_progress
,
140 status
.download_rate
,
142 lut_main_process_closure (c
);
145 lut_log_debug ("bt: finished download");
148 lut_log_debug ("bt: seeding");
151 lut_log_debug ("bt: allocating space for download");
156 if (status
.state
== 5)
158 old_state
= status
.state
;
160 /* we don't want to busy loop, so we sleep for a second */
164 catch (std::exception
& e
)
166 lut_log_error ("bt: caught exception: %s", e
.what());
169 /* if successful, update the database */
170 if (ctxt
->error
== LUT_OK
) {
175 pthread_setcancelstate (PTHREAD_CANCEL_DISABLE
, NULL
);
177 db
= lut_db_begin_transaction ();
179 statement
= sqlite3_mprintf ("UPDATE downloads SET is_complete=1 WHERE file_path=%Q;",
181 sqlite_retval
= sqlite3_exec (db
, statement
, NULL
, NULL
, NULL
);
182 sqlite3_free (statement
);
183 if (sqlite_retval
!= SQLITE_OK
) {
184 lut_log_error ("failed to update downloads table: %s", sqlite3_errmsg (db
));
185 lut_db_abort_transaction ();
186 ctxt
->error
= LUT_ERROR_DB_FAILURE
;
189 lut_db_commit_transaction ();
193 } /* end of the extern "C" block */
195 /********************************************************************/
196 /* If bittorrent support is not enabled, we use these stubs instead */
197 /********************************************************************/
203 lut_bt_init (void) { return LUT_OK
; }
206 lut_bt_cleanup (void) { return LUT_OK
; }
209 lut_download_bt (lut_download_ctxt
*ctxt
)
211 /* maybe create a new error type LUT_ERROR_NET_NOT_IMPLEMENTED? */
212 ctxt
->error
= LUT_ERROR_NET_FAILURE
;