diff --git a/bindings/c/Jamfile b/bindings/c/Jamfile new file mode 100755 index 000000000..fd3db9885 --- /dev/null +++ b/bindings/c/Jamfile @@ -0,0 +1,38 @@ +use-project /torrent : ../.. ; + +rule libtorrent_linking ( properties * ) +{ + local result ; + + if gcc in $(properties) && shared in $(properties) + { + result += on ; + } + +# if gcc in $(properties) || darwin in $(properties) +# { +# result += hidden ; +# } + + return $(result) ; +} + +lib torrentc-rasterbar + + : # sources + library.cpp + + : # requirements + @libtorrent_linking + /torrent//torrent/static + . + + : # default build + static + + : # usage-requirements + . +; + +exe simple_client : simple_client.c torrentc-rasterbar ; + diff --git a/bindings/c/library.cpp b/bindings/c/library.cpp new file mode 100644 index 000000000..33288d7ba --- /dev/null +++ b/bindings/c/library.cpp @@ -0,0 +1,419 @@ +/* + +Copyright (c) 2009, 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 "libtorrent/session.hpp" +#include "libtorrent/magnet_uri.hpp" +#include "libtorrent/torrent_handle.hpp" +#include + +#include + +namespace +{ + std::vector handles; + + int find_handle(libtorrent::torrent_handle h) + { + std::vector::const_iterator i + = std::find(handles.begin(), handles.end(), h); + if (i == handles.end()) return -1; + return i - handles.begin(); + } + + libtorrent::torrent_handle get_handle(int i) + { + if (i < 0 || i >= int(handles.size())) return libtorrent::torrent_handle(); + return handles[i]; + } + + int add_handle(libtorrent::torrent_handle const& h) + { + std::vector::iterator i = std::find_if(handles.begin() + , handles.end(), !boost::bind(&libtorrent::torrent_handle::is_valid, _1)); + if (i != handles.end()) + { + *i = h; + return i - handles.begin(); + } + + handles.push_back(h); + return handles.size() - 1; + } +} + +extern "C" +{ + +TORRENT_EXPORT void* create_session(int tag, ...) +{ + using namespace libtorrent; + + va_list lp; + va_start(lp, tag); + + fingerprint fing("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0); + std::pair listen_range(-1, -1); + char const* listen_interface = "0.0.0.0"; + int flags = session::start_default_features | session::add_default_plugins; + int alert_mask = alert::error_notification; + + while (tag != TAG_END) + { + switch (tag) + { + case SES_FINGERPRINT: + { + char const* f = va_arg(lp, char const*); + fing.name[0] = f[0]; + fing.name[1] = f[1]; + break; + } + case SES_LISTENPORT: + listen_range.first = va_arg(lp, int); + break; + case SES_LISTENPORT_END: + listen_range.second = va_arg(lp, int); + break; + case SES_VERSION_MAJOR: + fing.major_version = va_arg(lp, int); + break; + case SES_VERSION_MINOR: + fing.minor_version = va_arg(lp, int); + break; + case SES_VERSION_TINY: + fing.revision_version = va_arg(lp, int); + break; + case SES_VERSION_TAG: + fing.tag_version = va_arg(lp, int); + break; + case SES_FLAGS: + flags = va_arg(lp, int); + break; + case SES_ALERT_MASK: + alert_mask = va_arg(lp, int); + break; + case SES_LISTEN_INTERFACE: + listen_interface = va_arg(lp, char const*); + break; + default: + // skip unknown tags + va_arg(lp, void*); + break; + } + + tag = va_arg(lp, int); + } + + if (listen_range.first != -1 && (listen_range.second == -1 + || listen_range.second < listen_range.first)) + listen_range.second = listen_range.first; + + return new (std::nothrow) session(fing, listen_range, listen_interface, flags, alert_mask); +} + +TORRENT_EXPORT void close_session(void* ses) +{ + delete (libtorrent::session*)ses; +} + +TORRENT_EXPORT int add_torrent(void* ses, int tag, ...) +{ + using namespace libtorrent; + + va_list lp; + va_start(lp, tag); + session* s = (session*)ses; + add_torrent_params params; + + char const* torrent_data = 0; + int torrent_size = 0; + + char const* resume_data = 0; + int resume_size = 0; + + char const* magnet_url = 0; + + error_code ec; + + while (tag != TAG_END) + { + switch (tag) + { + case TOR_FILENAME: + params.ti = new (std::nothrow) torrent_info(va_arg(lp, char const*), ec); + break; + case TOR_TORRENT: + torrent_data = va_arg(lp, char const*); + break; + case TOR_TORRENT_SIZE: + torrent_size = va_arg(lp, int); + break; + case TOR_INFOHASH: + params.ti = new (std::nothrow) torrent_info(sha1_hash(va_arg(lp, char const*))); + break; + case TOR_INFOHASH_HEX: + { + sha1_hash ih; + from_hex(va_arg(lp, char const*), 40, (char*)&ih[0]); + params.ti = new (std::nothrow) torrent_info(ih); + break; + } + case TOR_MAGNETLINK: + magnet_url = va_arg(lp, char const*); + break; + case TOR_TRACKER_URL: + params.tracker_url = va_arg(lp, char const*); + break; + case TOR_RESUME_DATA: + resume_data = va_arg(lp, char const*); + break; + case TOR_RESUME_DATA_SIZE: + resume_size = va_arg(lp, int); + break; + case TOR_SAVE_PATH: + params.save_path = va_arg(lp, char const*); + break; + case TOR_NAME: + params.name = va_arg(lp, char const*); + break; + case TOR_PAUSED: + params.paused = va_arg(lp, int) != 0; + break; + case TOR_AUTO_MANAGED: + params.auto_managed = va_arg(lp, int) != 0; + break; + case TOR_DUPLICATE_IS_ERROR: + params.duplicate_is_error = va_arg(lp, int) != 0; + break; + case TOR_USER_DATA: + params.userdata = va_arg(lp, void*); + break; + case TOR_SEED_MODE: + params.seed_mode = va_arg(lp, int) != 0; + break; + case TOR_OVERRIDE_RESUME_DATA: + params.override_resume_data = va_arg(lp, int) != 0; + break; + case TOR_STORAGE_MODE: + params.storage_mode = (libtorrent::storage_mode_t)va_arg(lp, int); + break; + default: + // ignore unknown tags + va_arg(lp, void*); + break; + } + + tag = va_arg(lp, int); + } + + if (!params.ti && torrent_data && torrent_size) + params.ti = new (std::nothrow) torrent_info(torrent_data, torrent_size); + + std::vector rd; + if (resume_data && resume_size) + { + rd.assign(resume_data, resume_data + resume_size); + params.resume_data = &rd; + } + torrent_handle h; + if (!params.ti && magnet_url) + { + h = add_magnet_uri(*s, magnet_url, params, ec); + } + else + { + h = s->add_torrent(params, ec); + } + + if (!h.is_valid()) + { + return -1; + } + + int i = find_handle(h); + if (i == -1) i = add_handle(h); + + return i; +} + +void remove_torrent(void* ses, int tor, int flags) +{ + using namespace libtorrent; + torrent_handle h = get_handle(tor); + if (!h.is_valid()) return; + + session* s = (session*)ses; + s->remove_torrent(h, flags); +} + +int set_session_settings(void* ses, int tag, ...) +{ + using namespace libtorrent; + + session* s = (session*)ses; + + va_list lp; + va_start(lp, tag); + + while (tag != TAG_END) + { + switch (tag) + { + case SET_UPLOAD_RATE_LIMIT: + s->set_upload_rate_limit(va_arg(lp, int)); + break; + case SET_DOWNLOAD_RATE_LIMIT: + s->set_download_rate_limit(va_arg(lp, int)); + break; + case SET_MAX_UPLOAD_SLOTS: + s->set_max_uploads(va_arg(lp, int)); + break; + case SET_MAX_CONNECTIONS: + s->set_max_connections(va_arg(lp, int)); + break; + case SET_HALF_OPEN_LIMIT: + s->set_max_half_open_connections(va_arg(lp, int)); + break; + default: + // ignore unknown tags + va_arg(lp, void*); + break; + } + + tag = va_arg(lp, int); + } + return 0; +} + +int get_torrent_status(int tor, torrent_status* s, int struct_size) +{ + using namespace libtorrent; + torrent_handle h = get_handle(tor); + if (!h.is_valid()) return -1; + + libtorrent::torrent_status ts = h.status(); + + if (struct_size != sizeof(::torrent_status)) return -1; + + s->state = (state_t)ts.state; + s->paused = ts.paused; + s->progress = ts.progress; + strncpy(s->error, ts.error.c_str(), 1025); + s->next_announce = ts.next_announce.total_seconds(); + s->announce_interval = ts.announce_interval.total_seconds(); + strncpy(s->current_tracker, ts.current_tracker.c_str(), 512); + s->total_download = ts.total_download = ts.total_download = ts.total_download; + s->total_upload = ts.total_upload = ts.total_upload = ts.total_upload; + s->total_payload_download = ts.total_payload_download; + s->total_payload_upload = ts.total_payload_upload; + s->total_failed_bytes = ts.total_failed_bytes; + s->total_redundant_bytes = ts.total_redundant_bytes; + s->download_rate = ts.download_rate; + s->upload_rate = ts.upload_rate; + s->download_payload_rate = ts.download_payload_rate; + s->upload_payload_rate = ts.upload_payload_rate; + s->num_seeds = ts.num_seeds; + s->num_peers = ts.num_peers; + s->num_complete = ts.num_complete; + s->num_incomplete = ts.num_incomplete; + s->list_seeds = ts.list_seeds; + s->list_peers = ts.list_peers; + s->connect_candidates = ts.connect_candidates; + s->num_pieces = ts.num_pieces; + s->total_done = ts.total_done; + s->total_wanted_done = ts.total_wanted_done; + s->total_wanted = ts.total_wanted; + s->distributed_copies = ts.distributed_copies; + s->block_size = ts.block_size; + s->num_uploads = ts.num_uploads; + s->num_connections = ts.num_connections; + s->uploads_limit = ts.uploads_limit; + s->connections_limit = ts.connections_limit; +// s->storage_mode = (storage_mode_t)ts.storage_mode; + s->up_bandwidth_queue = ts.up_bandwidth_queue; + s->down_bandwidth_queue = ts.down_bandwidth_queue; + s->all_time_upload = ts.all_time_upload; + s->all_time_download = ts.all_time_download; + s->active_time = ts.active_time; + s->seeding_time = ts.seeding_time; + s->seed_rank = ts.seed_rank; + s->last_scrape = ts.last_scrape; + s->has_incoming = ts.has_incoming; + s->sparse_regions = ts.sparse_regions; + s->seed_mode = ts.seed_mode; + return 0; +} + +int set_torrent_settings(int tor, int tag, ...) +{ + using namespace libtorrent; + torrent_handle h = get_handle(tor); + if (!h.is_valid()) return -1; + + va_list lp; + va_start(lp, tag); + + while (tag != TAG_END) + { + switch (tag) + { + case SET_UPLOAD_RATE_LIMIT: + h.set_upload_limit(va_arg(lp, int)); + break; + case SET_DOWNLOAD_RATE_LIMIT: + h.set_download_limit(va_arg(lp, int)); + break; + case SET_MAX_UPLOAD_SLOTS: + h.set_max_uploads(va_arg(lp, int)); + break; + case SET_MAX_CONNECTIONS: + h.set_max_connections(va_arg(lp, int)); + break; + case SET_SEQUENTIAL_DOWNLOAD: + h.set_sequential_download(va_arg(lp, int) != 0); + break; + case SET_SUPER_SEEDING: + h.super_seeding(va_arg(lp, int) != 0); + break; + default: + // ignore unknown tags + va_arg(lp, void*); + break; + } + + tag = va_arg(lp, int); + } + return 0; +} + +} // extern "C" + diff --git a/bindings/c/libtorrent.h b/bindings/c/libtorrent.h new file mode 100644 index 000000000..a6ef5e1ab --- /dev/null +++ b/bindings/c/libtorrent.h @@ -0,0 +1,183 @@ +/* + +Copyright (c) 2009, 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. + +*/ + +#ifndef LIBTORRENT_H +#define LIBTORRENT_H + +enum tags +{ + SES_FINGERPRINT, + SES_LISTENPORT, + SES_LISTENPORT_END, + SES_VERSION_MAJOR, + SES_VERSION_MINOR, + SES_VERSION_TINY, + SES_VERSION_TAG, + SES_FLAGS, + SES_ALERT_MASK, + SES_LISTEN_INTERFACE, + + // === add_torrent tags === + + // identifying the torrent to add + TOR_FILENAME = 0x100, + TOR_TORRENT, + TOR_TORRENT_SIZE, + TOR_INFOHASH, + TOR_INFOHASH_HEX, + TOR_MAGNETLINK, + + TOR_TRACKER_URL, + TOR_RESUME_DATA, + TOR_RESUME_DATA_SIZE, + TOR_SAVE_PATH, + TOR_NAME, + TOR_PAUSED, + TOR_AUTO_MANAGED, + TOR_DUPLICATE_IS_ERROR, + TOR_USER_DATA, + TOR_SEED_MODE, + TOR_OVERRIDE_RESUME_DATA, + TOR_STORAGE_MODE, + + SET_UPLOAD_RATE_LIMIT = 0x200, + SET_DOWNLOAD_RATE_LIMIT, + SET_MAX_UPLOAD_SLOTS, + SET_MAX_CONNECTIONS, + SET_SEQUENTIAL_DOWNLOAD, // torrent only + SET_SUPER_SEEDING, // torrent only + SET_HALF_OPEN_LIMIT, // session only + + + + TAG_END = 0x7fffffff +}; + +enum storage_mode_t +{ + storage_mode_allocate = 0, + storage_mode_sparse, + storage_mode_compact +}; + +enum state_t +{ + queued_for_checking, + checking_files, + downloading_metadata, + downloading, + finished, + seeding, + allocating, + checking_resume_data +}; + +struct torrent_status +{ + enum state_t state; + int paused; + float progress; + char error[1024]; + int next_announce; + int announce_interval; + char current_tracker[512]; + long long total_download; + long long total_upload; + long long total_payload_download; + long long total_payload_upload; + long long total_failed_bytes; + long long total_redundant_bytes; + float download_rate; + float upload_rate; + float download_payload_rate; + float upload_payload_rate; + int num_seeds; + int num_peers; + int num_complete; + int num_incomplete; + int list_seeds; + int list_peers; + int connect_candidates; + + // what to do? +// bitfield pieces; + + int num_pieces; + long long total_done; + long long total_wanted_done; + long long total_wanted; + float distributed_copies; + int block_size; + int num_uploads; + int num_connections; + int uploads_limit; + int connections_limit; +// enum storage_mode_t storage_mode; + int up_bandwidth_queue; + int down_bandwidth_queue; + long long all_time_upload; + long long all_time_download; + int active_time; + int seeding_time; + int seed_rank; + int last_scrape; + int has_incoming; + int sparse_regions; + int seed_mode; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +// use SES_* tags in tag list +void* create_session(int first_tag, ...); +void close_session(void* ses); + +// use TOR_* tags in tag list +int add_torrent(void* ses, int first_tag, ...); +void remove_torrent(void* ses, int tor, int flags); +// use SET_* tags in tag list +int set_session_settings(void* ses, int first_tag, ...); + +int get_torrent_status(int tor, struct torrent_status* s, int struct_size); + +// use SET_* tags in tag list +int set_torrent_settings(int tor, int first_tag, ...); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/bindings/c/simple_client.c b/bindings/c/simple_client.c new file mode 100644 index 000000000..ee4f094b8 --- /dev/null +++ b/bindings/c/simple_client.c @@ -0,0 +1,116 @@ +/* + +Copyright (c) 2009, 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 +#include +#include +#include +#include + +int quit = 0; + +void stop(int signal) +{ + quit = 1; +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "usage: ./simple_client torrent-file\n"); + return 1; + } + + int ret = 0; + void* ses = create_session( + SES_LISTENPORT, 6881, + SES_LISTENPORT_END, 6889, + TAG_END); + + int t = add_torrent(ses, + TOR_FILENAME, argv[1], + TOR_SAVE_PATH, "./", + TAG_END); + + if (t < 0) + { + fprintf(stderr, "Failed to add torrent\n"); + ret = 1; + goto exit; + } + + struct torrent_status st; + + printf("press ctrl-C to stop\n"); + + signal(SIGINT, &stop); + signal(SIGABRT, &stop); + signal(SIGQUIT, &stop); + + while (quit == 0) + { + char const* message = ""; + + char const* state[] = {"queued", "checking", "downloading metadata" + , "downloading", "finished", "seeding", "allocating" + , "checking_resume_data"}; + + if (get_torrent_status(t, &st, sizeof(st)) < 0) break; + printf("\r%3.f%% %d kB (%5.f kB/s) up: %d kB (%5.f kB/s) peers: %d '%s' %s " + , (double)st.progress * 100. + , (int)(st.total_payload_download / 1000) + , (double)st.download_payload_rate / 1000. + , (int)(st.total_payload_upload / 1000) + , (double)st.upload_payload_rate / 1000. + , st.num_peers + , state[st.state] + , message); + + + if (strlen(st.error) > 0) + { + fprintf(stderr, "\nERROR: %s\n", st.error); + break; + } + + fflush(stdout); + usleep(1000000); + } + printf("\nclosing\n"); + +exit: + + close_session(ses); + return ret; +} +