# Check the digest debug("Calculated digest: %s; Name digest: %s" % (digest, ni_url.get_digest())) if (digest != ni_url.get_digest()): if verbose: print("Warning: Digest of %s did not verify" % ni_url.get_url()) if not lax: os.remove(file_name) sys.exit(-30) faulty = True # OK.. got the response - finish with daemon break elif dtnapi.dtn_errno(dtn_handle) != dtnapi.DTN_ETIMEOUT: if verbose: print(dtnapi.dtn_strerror(dtnapi.dtn_errno(dtn_handle))) sys.exit(-21) else: if verbose: print("dtn_recv timed out without receiving response bundle") sys.exit(1) dtnapi.dtn_close(dtn_handle) debug("get_via_dtn completed") return (json_dict, got_content, faulty) #-------------------------------------------------------------------------------# def py_nigetalt():
def publish_with_dtn(ni_name, destination, authority, hash_alg, ext_json, locs, scheme, full_put, file_name, rform, verbose): """ @brief Action a NetInf publish request using the HTTP convergence layer @param ni_name NIname object instance or None - ni URI to publish if given on comand line - otherwise will be constructed @param destination string netloc (FQDN or IP address with optional port) indicating where to send publish request @param authority string netloc component to insert into ni name (may be "") @param hash_alg string name of hash algorithm used for ni URI @param ext_json dictionary additional information to send with request if any in the form of a JSON dictionary or None @param locs list of strings with locators to publish - maybe None @param scheme URI scheme used for ni URI @param full_put boolean True if the file_name with the content was given @param file_name string name of file to publish or None if only doing metadata @param rform string request format of response @param verbose bolean indicates how much error message output is produced @return 2-tuple - target - string the actual ni name published payload - string - the response received on publication """ debug("Publishing via: %s" % destination) # Handle full_put = True cases - we have a file with the octets in it if full_put: if ni_name is None: # Make a ni_name template from specified components ni_name = NIname((scheme, authority, "/%s" % hash_alg)) # Construct the digest from the file name and the template rv = NIproc.makenif(ni_name, file_name) if rv != ni_errs.niSUCCESS: raise PublishFailure("Unable to construct digest of file %s: %s" % (file_name, ni_errs_txt[rv]), -20) else: # Check the ni_name and the file match rv = Niproc.checknif(ni_name, file_name) if rv != ni_errs.niSUCCESS: raise PublishFailure("Digest of file %s does not match ni_name %s: %s" % (file_name, ni_name.get_url(), ni_errs_txt[rv]), -21) # Guess the mimetype of the file m = magic.Magic(mime=True) ctype = m.from_file(file_name) debug("Content-Type: %s" % ctype) if ctype is None: # Guessing didn't work - default ctype = "application/octet-stream" else: ctype = None target = ni_name.get_canonical_ni_url() debug("Using URI string: %s" % target) # Add extra items to ext_json to pass across as metadata ext_json["ni"] = target if ctype is not None: ext_json["ct"] = ctype if authority != "": ext_json["http_auth"] = authority # Send at most two locators as a list if (locs is not None): ext_json["loclist"] = locs[:2] ext_json["fullPut"] = full_put ext_json["rform"] = rform # Create a connection to the DTN daemon dtn_handle = dtnapi.dtn_open() if dtn_handle == -1: raise PublishFailure("Error: unable to open connection with DTN daemon", -22) # Generate EID + service tag for service to be accessed via DTN if destination is None: remote_service_eid = \ dtnapi.dtn_build_local_eid(dtn_handle, "netinfproto/service/publish") i = remote_service_eid.find("/netinfproto") destination = remote_service_eid[:i] else: remote_service_eid = destination + "/netinfproto/service/publish" # Add destination to locs if it isn't there already if locs is None: locs = [] if destination not in locs: locs.append(destination) # Generate the EID and service tag for this service local_service_eid = dtnapi.dtn_build_local_eid(dtn_handle, "netinfproto/app/response") debug("Local Service EID: %s" % local_service_eid) debug("Remote Service EID: %s" % remote_service_eid) # Check if service_eid registration exists and register if not # Otherwise bind to the existing registration regid = dtnapi.dtn_find_registration(dtn_handle, local_service_eid) if (regid == -1): # Need to register the EID.. make it permanent with 'DEFER' # characteristics so that bundles are saved if they arrive # while the handler is inactive # Expire the registration an hour in the future exp = 60 * 60 # The registration is immediately active passive = False # We don't want to execute a script script = "" regid = dtnapi.dtn_register(dtn_handle, local_service_eid, dtnapi.DTN_REG_DEFER, exp, passive, script) else: dtnapi.dtn_bind(dtn_handle, regid) # Build the bundle to send # First a suitable BPQ block bpq = BPQ() bpq.set_bpq_kind(BPQ.BPQ_BLOCK_KIND_PUBLISH) bpq.set_matching_rule(BPQ.BPQ_MATCHING_RULE_EXACT) bpq.set_src_eid(local_service_eid) sent_msgid = str(random.randint(1, 32000)) bpq.set_bpq_id(sent_msgid) bpq.set_bpq_val(target) bpq.clear_frag_desc() # Build an extension blocks structure to hold the block ext_blocks = dtnapi.dtn_extension_block_list(1) # Construct the extension block bpq_block = dtnapi.dtn_extension_block() bpq_block.type = QUERY_EXTENSION_BLOCK bpq_block.flags = 0 bpq_block.data = bpq.build_for_net() ext_blocks.blocks.append(bpq_block) # Build an extension blocks structure to hold the block meta_blocks = dtnapi.dtn_extension_block_list(2) # Build a metadata block for JSON data md = Metadata() md.set_ontology(Metadata.ONTOLOGY_JSON) md.set_ontology_data(json.dumps(ext_json)) json_block = dtnapi.dtn_extension_block() json_block.type = METADATA_BLOCK json_block.flags = 0 json_block.data = md.build_for_net() meta_blocks.blocks.append(json_block) # Set up payload and placeholder if needed if full_put: # No placeholder required (obviously!) pt = dtnapi.DTN_PAYLOAD_FILE pv = file_name else: # DTN bundle always has a payload - distinguish # zero length file form no content available # Payload is the empty string sent via memory pt = dtnapi.DTN_PAYLOAD_MEM pv = "" # Add a payload placeholder metablock md = Metadata() md.set_ontology(Metadata.ONTOLOGY_PAYLOAD_PLACEHOLDER) md.set_ontology_data("No content supplied") pp_block = dtnapi.dtn_extension_block() pp_block.type = METADATA_BLOCK pp_block.flags = 0 pp_block.data = md.build_for_net() meta_blocks.blocks.append(pp_block) # We want delivery reports and publication reports # (and maybe deletion reports?) dopts = dtnapi.DOPTS_DELIVERY_RCPT | dtnapi.DOPTS_PUBLICATION_RCPT # - Send with normal priority. pri = dtnapi.COS_NORMAL # NetInf bundles should last a while.. exp = (24 *60 * 60) # Send the bundle bundle_id = dtnapi.dtn_send(dtn_handle, regid, local_service_eid, remote_service_eid, local_service_eid, pri, dopts, exp, pt, pv, ext_blocks, meta_blocks, "", "") if bundle_id == None: raise PublishFailure("dtn_send failed - %s" % dtnapi.dtn_strerror(dtnapi.dtn_errno(dtn_handle)), -23) # Wait for a reponse - maybe also some reports while(True): # NOTE: BUG in dtnapi - timeout is in msecs recv_timeout = 2000 * 60 bpq_bundle = dtnapi.dtn_recv(dtn_handle, dtnapi.DTN_PAYLOAD_FILE, recv_timeout) # If bpq_bundle is None then either the dtn_recv timed out or # there was some other error. if bpq_bundle != None: # Filter out report bundles if bpq_bundle.status_report != None: debug("Received status report") if bpq_bundle.status_report.flags == dtnapi.STATUS_DELIVERED: if verbose: print("Received delivery report re from %s sent %d seq %d" % (bpq_bundle.status_report.bundle_id.source, bpq_bundle.status_report.bundle_id.creation_secs, bpq_bundle.status_report.bundle_id.creation_seqno)) elif bpq_bundle.status_report.flags == dtnapi.STATUS_DELETED: if verbose: print("Received deletion report re from %s sent %d seq %d" % (bpq_bundle.status_report.bundle_id.source, bpq_bundle.status_report.bundle_id.creation_secs, bpq_bundle.status_report.bundle_id.creation_seqno)) elif bpq_bundle.status_report.flags == dtnapi.STATUS_PUBLISHED: if verbose: print("Received publication report re from %s sent %d seq %d" % (bpq_bundle.status_report.bundle_id.source, bpq_bundle.status_report.bundle_id.creation_secs, bpq_bundle.status_report.bundle_id.creation_seqno)) else: if verbose: print("Received unexpected report: Flags: %d" % bpq_bundle.status_report.flags) # Wait for more status reports and incoming response continue # Check the payload really is in a file if not bpq_bundle.payload_file: raise PublishFailure("Received bundle payload not in file - " "ignoring bundle", -24) # Have to delete this file before an error exit or if empty pfn = bpq_bundle.payload l = len(pfn) if pfn[l-1] == "\x00": pfn = pfn[:-1] debug("Got incoming bundle with response in file %s" % pfn) # Does the bundle have a BPQ block bpq_data = None if bpq_bundle.extension_cnt == 0: os.remove(pfn) raise PublishFailure("Error: Received bundle with no " "extension block.", -25) for blk in bpq_bundle.extension_blks: if blk.type == QUERY_EXTENSION_BLOCK: bpq_data = BPQ() if not bpq_data.init_from_net(blk.data): os.remove(pfn) raise PublishFailure("Error: Bad BPQ block received", -26) if bpq_data is None: os.remove(pfn) raise PublishFailure("Error: Received bundle with no BPQ block " "in extension blocks", -27) debug(bpq_data) # OK.. got the response - finish with daemon break elif dtnapi.dtn_errno(dtn_handle) != dtnapi.DTN_ETIMEOUT: raise PublishFailure(dtnapi.dtn_strerror(dtnapi.dtn_errno(dtn_handle)), -28) else: raise PublishFailure("dtn_recv timed out without receiving " "response bundle", 1) dtnapi.dtn_close(dtn_handle) # Check the BPQ data is right bpq.set_bpq_kind(BPQ.BPQ_BLOCK_KIND_PUBLISH) bpq.set_matching_rule(BPQ.BPQ_MATCHING_RULE_EXACT) if bpq_data.bpq_kind != BPQ.BPQ_BLOCK_KIND_PUBLISH: raise PublishFailure("Returned BPQ block is not PUBLISH kind: %d" % bpq_data.bpq_kind, -29) if bpq_data.matching_rule != BPQ.BPQ_MATCHING_RULE_NEVER: raise PublishFailure("Returned BPQ block does not have NEVER matching rule: %d" % bpq_data.matching_rule, -30) if bpq_data.bpq_id != sent_msgid: raise PublishFailure("Returned BPQ block has unmatched msgis %s vs %s" % (bpq_data.bpq_id, sent_msgid), -31) # Verify the format of the response (a bit) try: pfd = open(pfn, "rb") payload = pfd.read() pfd.close() os.remove(pfn) except Exception, e: raise PublishFailure("Failed to read response from payload file %s" % pfn, -32)