* fixed all headers to use extern "C" so C/C++ linking will work properly
[libundertow.git] / src / undertow-download-bt.cpp
blob413ac5e3e05221f4d9f92f8978dad32eb5a3af4a
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.
20 #include "config.h"
22 #ifdef ENABLE_BITTORRENT
24 #include <iostream>
25 #include <fstream>
26 #include <iterator>
27 #include <exception>
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
46 * compiler errors.
48 extern "C" {
50 static libtorrent::session *bt_session = NULL;
52 int
53 lut_bt_init (void)
55 boost::filesystem::path::default_name_check(boost::filesystem::no_check);
56 try
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");
62 return 0;
64 catch (std::exception& e)
66 lut_log_error ("bt: caught exception: %s", e.what());
67 return -1;
71 int
72 lut_bt_cleanup (void)
74 if (bt_session)
75 delete bt_session;
76 bt_session = NULL;
77 lut_log_debug ("bt: cleanup complete");
78 return 0;
81 void
82 lut_download_bt (lut_download_ctxt *ctxt)
84 char *buffer = NULL;
85 size_t buflen = 0;
86 lut_errno retval;
87 int old_state = -1;
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",
94 ctxt->content_url,
95 lut_strerror (retval));
96 ctxt->error = retval;
97 return;
100 try {
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 */
109 while (1) {
110 lut_closure *c;
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)
121 continue;
122 switch (status.state) {
123 case 0:
124 lut_log_debug ("bt: queued for checking");
125 break;
126 case 1:
127 lut_log_debug ("bt: checking files");
128 break;
129 case 2:
130 lut_log_debug ("bt: connecting to tracker");
131 break;
132 case 3:
133 lut_log_debug ("bt: downloading metadata");
134 break;
135 case 4:
136 c = lut_closure_new__sizet_sizet_float_float (ctxt->on_progress,
137 info.total_size (),
138 status.total_done,
139 0.0,
140 status.download_rate,
141 ctxt->data);
142 lut_main_process_closure (c);
143 break;
144 case 5:
145 lut_log_debug ("bt: finished download");
146 break;
147 case 6:
148 lut_log_debug ("bt: seeding");
149 break;
150 case 7:
151 lut_log_debug ("bt: allocating space for download");
152 break;
153 default:
154 break;
156 if (status.state == 5)
157 break;
158 old_state = status.state;
160 /* we don't want to busy loop, so we sleep for a second */
161 sleep (1);
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) {
171 sqlite3 *db;
172 char *statement;
173 int sqlite_retval;
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;",
180 ctxt->file_path);
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;
188 else
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 /********************************************************************/
198 #else
200 extern "C" {
202 lut_errno
203 lut_bt_init (void) { return LUT_OK; }
205 lut_errno
206 lut_bt_cleanup (void) { return LUT_OK; }
208 void
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;
216 #endif