1 /***************************************************************************
3 * Copyright (C) 2006 David Brodsky *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation and appearing *
8 * in the file LICENSE.GPL included in the packaging of this file. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * General Public License for more details. *
15 ***************************************************************************/
21 #include <tairon/core/config.h>
22 #include <tairon/core/exceptions.h>
23 #include <tairon/core/log.h>
24 #include <tairon/core/tinyxml.h>
26 #include "torrentmanager.h"
28 #include "core/bencode.h"
30 #include "torrentclient.h"
32 #define TAIRENT_VERSION "0.1"
34 static const char *binTable
= "0123456789abcdef";
42 TorrentManager
*TorrentManager::torrentManager
= 0;
44 /* {{{ TorrentManager::TorrentManager() */
45 TorrentManager::TorrentManager()
48 throw Tairon::Core::SingletonException("Cannot make another instance of Tairent::Main::TorrentManager");
53 torrentManager
= this;
57 /* {{{ TorrentManager::~TorrentManager() */
58 TorrentManager::~TorrentManager()
64 /* {{{ TorrentManager::binToHex(const String &) */
65 String
TorrentManager::binToHex(const String
&data
)
68 ret
.resize(data
.size() * 2);
70 for (unsigned int i
= 0; i
< data
.size(); ++i
) {
71 ret
[2 * i
] = binTable
[(data
[i
] & 0xf0) >> 4];
72 ret
[2 * i
+ 1] = binTable
[data
[i
] & 0x0f];
79 /* {{{ TorrentManager::destroy() */
80 void TorrentManager::destroy()
83 for (std::map
<String
, TorrentStruct
*>::const_iterator it
= torrents
.begin(); it
!= torrents
.end(); ++it
) {
84 delete it
->second
->client
;
85 delete it
->second
->storage
;
86 delete it
->second
->metaInfo
;
93 /* {{{ TorrentManager::getClient(const String &) */
94 TorrentClient
*TorrentManager::getClient(const String
&infoHash
)
96 if (torrents
.count(infoHash
)) {
97 TorrentStruct
*t
= torrents
[infoHash
];
101 // TODO: create client
104 return 0; // no client found
108 /* {{{ TorrentManager::getClientID() */
109 const String
&TorrentManager::getClientID()
115 /* {{{ TorrentManager::hexToBin(char) */
116 char TorrentManager::hexToBin(char c
)
118 if ((c
>= '0') && (c
<= '9'))
124 /* {{{ TorrentManager::hexToBin(const String &) */
125 String
TorrentManager::hexToBin(const String
&data
)
128 ret
.resize(data
.length() / 2);
131 const char *d
= data
;
133 ret
[i
++] = (hexToBin(*d
) << 4) | (hexToBin(*(d
+ 1)));
141 /* {{{ TorrentManager::loadMetaInfo(const String &) */
142 Tairent::Core::BEncode
*TorrentManager::loadMetaInfo(const String
&filename
)
144 std::ifstream
f(filename
, std::ios_base::in
);
146 WARNING((const char *) String("Cannot load informations from " + filename
));
150 Tairent::Core::BEncode
*ret
= new Tairent::Core::BEncode();
153 } catch (const Tairent::Core::BEncodeException
&e
) {
154 WARNING((const char *) String("Cannot load metainfo from " + filename
+ ": " + (const String
&) e
));
163 /* {{{ TorrentManager::loadTorrent(TiXmlNode *) */
164 void TorrentManager::loadTorrent(TiXmlNode
*t
)
166 TiXmlElement
*element
= t
->ToElement();
167 const char *data
= element
->Attribute("file");
171 INFO((const char *) String(String("Loading informations about ") + data
));
173 TorrentStruct
*torrent
= new TorrentStruct
;
175 torrent
->storage
= 0;
177 torrent
->torrentFile
= data
;
179 data
= element
->Attribute("complete");
180 if (data
&& (data
[0] == '1'))
181 torrent
->complete
= true;
183 torrent
->complete
= false;
185 torrent
->metaInfo
= loadMetaInfo(torrent
->torrentFile
);
186 if (!torrent
->metaInfo
)
189 data
= element
->Attribute("hash");
191 torrents
[hexToBin(data
)] = torrent
;
193 String hash
= (*torrent
->metaInfo
)["info"].computeSHA1();
194 torrents
[hash
] = torrent
;
197 // load storage, if available
198 for (TiXmlNode
*node
= element
->FirstChild(); node
; node
= node
->NextSibling()) {
199 if (node
->Type() != TiXmlNode::ELEMENT
)
201 if (node
->ValueStr() == "storage")
202 torrent
->storage
= new Storage((*torrent
->metaInfo
)["info"], node
);
207 /* {{{ TorrentManager::loadTorrents() */
208 void TorrentManager::loadTorrents()
210 TiXmlDocument document
;
212 if (!document
.LoadFile((*Tairon::Core::Config::self())["torrents-directory"] + "/torrents.xml"))
215 TiXmlElement
*root
= document
.RootElement();
219 if (root
->ValueStr() != "torrents") // invalid file
222 for (TiXmlNode
*node
= root
->FirstChild(); node
; node
= node
->NextSibling()) {
223 if (node
->Type() != TiXmlNode::ELEMENT
)
225 if (node
->ValueStr() == "torrent")
231 /* {{{ TorrentManager::makeClientID() */
232 void TorrentManager::makeClientID()
236 clientID
= "TA-" TAIRENT_VERSION
"-";
237 size_t len
= clientID
.length();
240 std::ifstream
f("/dev/urandom", std::ios_base::in
);
242 for (size_t i
= len
; i
< 20; ++i
)
243 clientID
[i
] = (char) f
.get();
245 } else { // cannot open /dev/urandom? fall back to standard random
247 for (size_t i
= len
; i
< 20; ++i
)
248 clientID
[i
] = random() % 256;
253 /* {{{ TorrentManager::save() */
254 void TorrentManager::save()
256 TiXmlDocument
document((*Tairon::Core::Config::self())["torrents-directory"] + "/torrents.xml");
258 TiXmlElement
*root
= new TiXmlElement("torrents");
259 document
.LinkEndChild(root
);
261 for (std::map
<String
, TorrentStruct
*>::const_iterator it
= torrents
.begin(); it
!= torrents
.end(); ++it
) {
262 TiXmlElement
*element
= new TiXmlElement("torrent");
263 element
->SetAttribute(String("hash"), binToHex(it
->first
));
264 element
->SetAttribute(String("file"), it
->second
->torrentFile
);
265 element
->LinkEndChild(it
->second
->client
->getStorage()->save());
266 root
->LinkEndChild(element
);
269 // TODO: error checking
274 /* {{{ TorrentManager::startTorrents() */
275 void TorrentManager::startTorrents()
277 for (std::map
<String
, TorrentStruct
*>::const_iterator it
= torrents
.begin(); it
!= torrents
.end(); ++it
) {
278 TorrentStruct
*t
= it
->second
;
282 if (!t
->metaInfo
) { // metainfo loading failed
283 WARNING((const char *) String("Cannot start torrent " + t
->torrentFile
));
287 if (!t
->storage
) // no fast resume date was loaded
288 INFO((const char *) String("No fast-resume data for torrent " + t
->torrentFile
));
290 t
->client
= new TorrentClient(t
, it
->first
, t
->storage
);
296 /* {{{ TorrentManager::stopTorrents() */
297 void TorrentManager::stopTorrents()
299 for (std::map
<String
, TorrentStruct
*>::const_iterator it
= torrents
.begin(); it
!= torrents
.end(); ++it
)
300 it
->second
->client
->stop();
306 }; // namespace Tairent
308 // vim: ai sw=4 ts=4 noet fdm=marker