diff options
Diffstat (limited to '')
-rw-r--r-- | src/rgw/rgw_torrent.cc | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/rgw/rgw_torrent.cc b/src/rgw/rgw_torrent.cc new file mode 100644 index 000000000..e1a1417a5 --- /dev/null +++ b/src/rgw/rgw_torrent.cc @@ -0,0 +1,261 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#include <errno.h> +#include <stdlib.h> + +#include <sstream> + +#include "rgw_torrent.h" +#include "rgw_sal.h" +#include "rgw_sal_rados.h" +#include "include/str_list.h" +#include "include/rados/librados.hpp" + +#include "services/svc_sys_obj.h" + +#define dout_subsys ceph_subsys_rgw + +using namespace std; +using namespace librados; +using namespace boost; +using ceph::crypto::SHA1; + +seed::seed() +{ + seed::info.piece_length = 0; + seed::info.len = 0; + sha_len = 0; + is_torrent = false; +} + +seed::~seed() +{ + seed::info.sha1_bl.clear(); + bl.clear(); + s = NULL; + driver = NULL; +} + +void seed::init(req_state *_req, rgw::sal::Driver* _driver) +{ + s = _req; + driver = _driver; +} + +int seed::get_torrent_file(rgw::sal::Object* object, + uint64_t &total_len, + ceph::bufferlist &bl_data, + rgw_obj &obj) +{ + /* add other field if config is set */ + dencode.bencode_dict(bl); + set_announce(); + if (!comment.empty()) + { + dencode.bencode(COMMENT, comment, bl); + } + if (!create_by.empty()) + { + dencode.bencode(CREATED_BY, create_by, bl); + } + if (!encoding.empty()) + { + dencode.bencode(ENCODING, encoding, bl); + } + + string oid, key; + get_obj_bucket_and_oid_loc(obj, oid, key); + ldpp_dout(s, 20) << "NOTICE: head obj oid= " << oid << dendl; + + const set<string> obj_key{RGW_OBJ_TORRENT}; + map<string, bufferlist> m; + const int r = object->omap_get_vals_by_keys(s, oid, obj_key, &m); + if (r < 0) { + ldpp_dout(s, 0) << "ERROR: omap_get_vals_by_keys failed: " << r << dendl; + return r; + } + if (m.size() != 1) { + ldpp_dout(s, 0) << "ERROR: omap key " RGW_OBJ_TORRENT " not found" << dendl; + return -EINVAL; + } + bl.append(std::move(m.begin()->second)); + dencode.bencode_end(bl); + + bl_data = bl; + total_len = bl.length(); + return 0; +} + +bool seed::get_flag() +{ + return is_torrent; +} + +void seed::update(bufferlist &bl) +{ + if (!is_torrent) + { + return; + } + info.len += bl.length(); + sha1(&h, bl, bl.length()); +} + +int seed::complete(optional_yield y) +{ + uint64_t remain = info.len%info.piece_length; + uint8_t remain_len = ((remain > 0)? 1 : 0); + sha_len = (info.len/info.piece_length + remain_len)*CEPH_CRYPTO_SHA1_DIGESTSIZE; + + int ret = 0; + /* produce torrent data */ + do_encode(); + + /* save torrent data into OMAP */ + ret = save_torrent_file(y); + if (0 != ret) + { + ldpp_dout(s, 0) << "ERROR: failed to save_torrent_file() ret= "<< ret << dendl; + return ret; + } + + return 0; +} + +off_t seed::get_data_len() +{ + return info.len; +} + +void seed::set_create_date(ceph::real_time& value) +{ + utime_t date = ceph::real_clock::to_timespec(value); + create_date = date.sec(); +} + +void seed::set_info_pieces(char *buff) +{ + info.sha1_bl.append(buff, CEPH_CRYPTO_SHA1_DIGESTSIZE); +} + +void seed::set_info_name(const string& value) +{ + info.name = value; +} + +void seed::sha1(SHA1 *h, bufferlist &bl, off_t bl_len) +{ + off_t num = bl_len/info.piece_length; + off_t remain = 0; + remain = bl_len%info.piece_length; + + char *pstr = bl.c_str(); + char sha[25]; + + /* get sha1 */ + for (off_t i = 0; i < num; i++) + { + // FIPS zeroization audit 20191116: this memset is not intended to + // wipe out a secret after use. + memset(sha, 0x00, sizeof(sha)); + h->Update((unsigned char *)pstr, info.piece_length); + h->Final((unsigned char *)sha); + set_info_pieces(sha); + pstr += info.piece_length; + } + + /* process remain */ + if (0 != remain) + { + // FIPS zeroization audit 20191116: this memset is not intended to + // wipe out a secret after use. + memset(sha, 0x00, sizeof(sha)); + h->Update((unsigned char *)pstr, remain); + h->Final((unsigned char *)sha); + set_info_pieces(sha); + } + ::ceph::crypto::zeroize_for_security(sha, sizeof(sha)); +} + +int seed::get_params() +{ + is_torrent = true; + info.piece_length = g_conf()->rgw_torrent_sha_unit; + create_by = g_conf()->rgw_torrent_createby; + encoding = g_conf()->rgw_torrent_encoding; + origin = g_conf()->rgw_torrent_origin; + comment = g_conf()->rgw_torrent_comment; + announce = g_conf()->rgw_torrent_tracker; + + /* tracker and tracker list is empty, set announce to origin */ + if (announce.empty() && !origin.empty()) + { + announce = origin; + } + + return 0; +} + +void seed::set_announce() +{ + list<string> announce_list; // used to get announce list from conf + get_str_list(announce, ",", announce_list); + + if (announce_list.empty()) + { + ldpp_dout(s, 5) << "NOTICE: announce_list is empty " << dendl; + return; + } + + list<string>::iterator iter = announce_list.begin(); + dencode.bencode_key(ANNOUNCE, bl); + dencode.bencode_key((*iter), bl); + + dencode.bencode_key(ANNOUNCE_LIST, bl); + dencode.bencode_list(bl); + for (; iter != announce_list.end(); ++iter) + { + dencode.bencode_list(bl); + dencode.bencode_key((*iter), bl); + dencode.bencode_end(bl); + } + dencode.bencode_end(bl); +} + +void seed::do_encode() +{ + /*Only encode create_date and sha1 info*/ + /*Other field will be added if confi is set when run get torrent*/ + dencode.bencode(CREATION_DATE, create_date, bl); + + dencode.bencode_key(INFO_PIECES, bl); + dencode.bencode_dict(bl); + dencode.bencode(LENGTH, info.len, bl); + dencode.bencode(NAME, info.name, bl); + dencode.bencode(PIECE_LENGTH, info.piece_length, bl); + + char info_sha[100] = { 0 }; + sprintf(info_sha, "%" PRIu64, sha_len); + string sha_len_str = info_sha; + dencode.bencode_key(PIECES, bl); + bl.append(sha_len_str.c_str(), sha_len_str.length()); + bl.append(':'); + bl.append(info.sha1_bl.c_str(), sha_len); + dencode.bencode_end(bl); +} + +int seed::save_torrent_file(optional_yield y) +{ + int op_ret = 0; + string key = RGW_OBJ_TORRENT; + + op_ret = s->object->omap_set_val_by_key(s, key, bl, false, y); + if (op_ret < 0) + { + ldpp_dout(s, 0) << "ERROR: failed to omap_set() op_ret = " << op_ret << dendl; + return op_ret; + } + + return op_ret; +} |