#include #include #include #include "rgw_torrent.h" #include "include/str_list.h" #include "include/rados/librados.hpp" #define dout_subsys ceph_subsys_rgw using namespace std; using ceph::crypto::MD5; 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; store = NULL; } void seed::init(struct req_state *p_req, RGWRados *p_store) { s = p_req; store = p_store; } int seed::get_torrent_file(RGWRados::Object::Read &read_op, 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; map m; set obj_key; get_obj_bucket_and_oid_loc(obj, oid, key); ldout(s->cct, 0) << "NOTICE: head obj oid= " << oid << dendl; obj_key.insert(RGW_OBJ_TORRENT); const int op_ret = read_op.state.io_ctx.omap_get_vals_by_keys(oid, obj_key, &m); if (op_ret < 0) { ldout(s->cct, 0) << "ERROR: failed to omap_get_vals_by_keys op_ret = " << op_ret << dendl; return op_ret; } map::iterator iter; for (iter = m.begin(); iter != m.end(); ++iter) { bufferlist bl_tmp = iter->second; char *pbuff = bl_tmp.c_str(); bl.append(pbuff, bl_tmp.length()); } 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() { 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(); if (0 != ret) { ldout(s->cct, 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++) { memset(sha, 0x00, sizeof(sha)); h->Update((byte *)pstr, info.piece_length); h->Final((byte *)sha); set_info_pieces(sha); pstr += info.piece_length; } /* process remain */ if (0 != remain) { memset(sha, 0x00, sizeof(sha)); h->Update((byte *)pstr, remain); h->Final((byte *)sha); set_info_pieces(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 announce_list; // used to get announce list from conf get_str_list(announce, ",", announce_list); if (announce_list.empty()) { ldout(s->cct, 5) << "NOTICE: announce_list is empty " << dendl; return; } list::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() { int op_ret = 0; string key = RGW_OBJ_TORRENT; rgw_obj obj(s->bucket, s->object.name); rgw_raw_obj raw_obj; store->obj_to_raw(s->bucket_info.placement_rule, obj, &raw_obj); op_ret = store->omap_set(raw_obj, key, bl); if (op_ret < 0) { ldout(s->cct, 0) << "ERROR: failed to omap_set() op_ret = " << op_ret << dendl; return op_ret; } return op_ret; }