Example #1
0
void
to_bundles()
{

    int bytes, ret;
    dtn_reg_info_t reg_report; /* for reports, if reqd */
    dtn_reg_info_t reg_session; /* for session reg, if reqd */
	
    // initialize bundle spec
    memset(&bundle_spec, 0, sizeof(bundle_spec));
    parse_eid(handle, &bundle_spec.dest, arg_dest);
    parse_eid(handle, &bundle_spec.source, arg_source);

    if (arg_replyto == NULL) {
        dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);
    } else {
        parse_eid(handle, &bundle_spec.replyto, arg_replyto);
    }

    if (verbose) {
        print_eid(info, "source_eid", &bundle_spec.source);
        print_eid(info, "replyto_eid", &bundle_spec.replyto);
        print_eid(info, "dest_eid", &bundle_spec.dest);
    }

    if (wait_for_report) {
	// if we're given a regid, bind to it, otherwise make a
	// registration for incoming reports
        if (regid != DTN_REGID_NONE) {
            if (dtn_bind(handle, regid) != DTN_SUCCESS) {
                fprintf(stderr, "%s: error in bind (id=0x%x): %d (%s)\n",
                        progname, regid, ret, dtn_strerror(dtn_errno(handle)));
                exit(EXIT_FAILURE);
            }
        } else {
            memset(&reg_report, 0, sizeof(reg_report));
            dtn_copy_eid(&reg_report.endpoint, &bundle_spec.replyto);
            reg_report.flags = DTN_REG_DEFER;
            reg_report.expiration = REG_EXPIRE;
            make_registration(&reg_report);
        }
    }

    if (session_flags) {
        // make a publisher registration 
        memset(&reg_session, 0, sizeof(reg_session));
	dtn_copy_eid(&reg_session.endpoint, &bundle_spec.dest);
        reg_session.flags = DTN_SESSION_PUBLISH;
        reg_session.expiration = 0;
	make_registration(&reg_session);
    }
    
    // set the dtn options
    bundle_spec.expiration = expiration;
    
    if (delivery_receipts) {
        // set the delivery receipt option
        bundle_spec.dopts |= DOPTS_DELIVERY_RCPT;
    }

    if (forwarding_receipts) {
        // set the forward receipt option
        bundle_spec.dopts |= DOPTS_FORWARD_RCPT;
    }

    if (custody) {
        // request custody transfer
        bundle_spec.dopts |= DOPTS_CUSTODY;
    }

    if (custody_receipts) {
        // request custody transfer
        bundle_spec.dopts |= DOPTS_CUSTODY_RCPT;
    }

    if (receive_receipts) {
        // request receive receipt
        bundle_spec.dopts |= DOPTS_RECEIVE_RCPT;
    }

    if (sequence_id) {
        bundle_spec.sequence_id.data.data_val = sequence_id;
        bundle_spec.sequence_id.data.data_len = strlen(sequence_id);
    }

    if (obsoletes_id) {
        bundle_spec.obsoletes_id.data.data_val = obsoletes_id;
        bundle_spec.obsoletes_id.data.data_len = strlen(obsoletes_id);
    }

    if ((bytes = fill_payload(&primary_payload)) < 0) {
	fprintf(stderr, "%s: error reading bundle data\n",
	    progname);
	exit(EXIT_FAILURE);
    }

    memset(&bundle_id, 0, sizeof(bundle_id));
    if ((ret = dtn_send(handle, regid, &bundle_spec, &primary_payload,
                        &bundle_id)) != 0) {
	fprintf(stderr, "%s: error sending bundle: %d (%s)\n",
	    progname, ret, dtn_strerror(dtn_errno(handle)));
	exit(EXIT_FAILURE);
    }

    if (verbose)
        fprintf(info, "Read %d bytes from stdin and wrote to bundles\n",
		bytes);

    if (wait_for_report) {
	memset(&reply_spec, 0, sizeof(reply_spec));
	memset(&reply_payload, 0, sizeof(reply_payload));
	
	// now we block waiting for any replies
	if ((ret = dtn_recv(handle, &reply_spec,
			    DTN_PAYLOAD_MEM, &reply_payload, -1)) < 0) {
	    fprintf(stderr, "%s: error getting reply: %d (%s)\n",
		    progname, ret, dtn_strerror(dtn_errno(handle)));
	    exit(EXIT_FAILURE);
	}
	if (gettimeofday(&end, NULL) < 0) {
	    fprintf(stderr, "%s: gettimeofday(end) returned error %s\n",
		    progname, strerror(errno));
	    exit(EXIT_FAILURE);
	}
    
	if (verbose)
	    fprintf(info, "got %d byte report from [%s]: time=%.1f ms\n",
	       reply_payload.buf.buf_len,
	       reply_spec.source.uri,
	       ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
		(double)(end.tv_usec - start.tv_usec)/1000.0));
    }
}
Example #2
0
int
main(int argc, const char** argv)
{
    int i;
    int ret;
    dtn_handle_t handle;
    dtn_endpoint_id_t source_eid;
    dtn_reg_info_t reginfo;
    dtn_reg_id_t regid;
    dtn_bundle_spec_t ping_spec;
    dtn_bundle_spec_t reply_spec;
    dtn_bundle_payload_t ping_payload;
    ping_payload_t payload_contents;
    ping_payload_t recv_contents;
    dtn_bundle_payload_t reply_payload;
    dtn_bundle_status_report_t* sr_data;
    dtn_bundle_id_t bundle_id;
    int debug = 1;
    char demux[64];
    int dest_len = 0;
    struct timeval send_times[MAX_PINGS_IN_FLIGHT];
    dtn_timestamp_t creation_times[MAX_PINGS_IN_FLIGHT];
    struct timeval now, recv_start, recv_end;
    u_int32_t nonce;
    u_int32_t seqno = 0;
    int timeout;

    // force stdout to always be line buffered, even if output is
    // redirected to a pipe or file
    setvbuf(stdout, (char *)NULL, _IOLBF, 0);
    
    doOptions(argc, argv);

    memset(&ping_spec, 0, sizeof(ping_spec));

    gettimeofday(&now, 0);
    srand(now.tv_sec);
    nonce = rand();
    
    // open the ipc handle
    int err = dtn_open(&handle);
    if (err != DTN_SUCCESS) {
        fprintf(stderr, "fatal error opening dtn handle: %s\n",
                dtn_strerror(err));
        exit(1);
    }

    // make sure they supplied a valid destination eid or
    // "localhost", in which case we just use the local daemon
    if (strcmp(dest_eid_str, "localhost") == 0) {
        dtn_build_local_eid(handle, &ping_spec.dest, "ping");
        
    } else {
        if (dtn_parse_eid_string(&ping_spec.dest, dest_eid_str)) {
            fprintf(stderr, "invalid destination eid string '%s'\n",
                    dest_eid_str);
            exit(1);
        }
    }

    dest_len = strlen(ping_spec.dest.uri);
    if ((dest_len < 4) ||
        (strcmp(ping_spec.dest.uri + dest_len - 4, "ping") != 0))
    {
        fprintf(stderr, "\nWARNING: ping destination does not end in \"ping\"\n\n");
    }
    
    // if the user specified a source eid, register on it.
    // otherwise, build a local eid based on the configuration of
    // our dtn router plus the demux string
    snprintf(demux, sizeof(demux), "/ping.%d", getpid());
    if (source_eid_str[0] != '\0') {
        if (dtn_parse_eid_string(&source_eid, source_eid_str)) {
            fprintf(stderr, "invalid source eid string '%s'\n",
                    source_eid_str);
            exit(1);
        }
    } else {
        dtn_build_local_eid(handle, &source_eid, demux);
    }

    // set the source and replyto eids in the bundle spec
    if (debug) printf("source_eid [%s]\n", source_eid.uri);
    dtn_copy_eid(&ping_spec.source, &source_eid);
    dtn_copy_eid(&ping_spec.replyto, &source_eid);
    
    // now create a new registration based on the source
    memset(&reginfo, 0, sizeof(reginfo));
    dtn_copy_eid(&reginfo.endpoint, &source_eid);
    reginfo.flags = DTN_REG_DEFER;
    reginfo.regid = DTN_REGID_NONE;
    reginfo.expiration = 0;
    if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
        fprintf(stderr, "error creating registration: %d (%s)\n",
                ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }    
    if (debug) printf("dtn_register succeeded, regid %d\n", regid);

    // set the expiration time and request deletion status reports
    ping_spec.expiration = expiration;
    ping_spec.dopts = DOPTS_DELETE_RCPT;

    printf("PING [%s] (expiration %u)...\n", ping_spec.dest.uri, expiration);
    if (interval == 0) {
        printf("WARNING: zero second interval will result in flooding pings!!\n");
    }
    
    // loop, sending pings and polling for activity
    for (i = 0; count == 0 || i < count; ++i) {
        gettimeofday(&send_times[seqno], NULL);
        
        // fill in a short payload string, a nonce, and a sequence number
        // to verify the echo feature and make sure we're not getting
        // duplicate responses or ping responses from another app
        memcpy(&payload_contents.ping, PING_STR, 8);
        payload_contents.seqno = seqno;
        payload_contents.nonce = nonce;
        payload_contents.time = send_times[seqno].tv_sec;
        
        memset(&ping_payload, 0, sizeof(ping_payload));
        dtn_set_payload(&ping_payload, DTN_PAYLOAD_MEM,
                        (char*)&payload_contents, sizeof(payload_contents));
        
        memset(&bundle_id, 0, sizeof(bundle_id));
        if ((ret = dtn_send(handle, regid, &ping_spec, &ping_payload,
                            &bundle_id)) != 0) {
            fprintf(stderr, "error sending bundle: %d (%s)\n",
                    ret, dtn_strerror(dtn_errno(handle)));
            exit(1);
        }
        
        creation_times[seqno] = bundle_id.creation_ts;

        memset(&reply_spec, 0, sizeof(reply_spec));
        memset(&reply_payload, 0, sizeof(reply_payload));

        // now loop waiting for replies / status reports until it's
        // time to send again, adding twice the expiration time if we
        // just sent the last ping
        timeout = interval * 1000;
        if (i == count - 1)
            timeout += expiration * 2000;
        
        do {
            gettimeofday(&recv_start, 0);
            if ((ret = dtn_recv(handle, &reply_spec,
                                DTN_PAYLOAD_MEM, &reply_payload, timeout)) < 0)
            {
                if (dtn_errno(handle) == DTN_ETIMEOUT) {
                    break; // time to send again
                }
                
                fprintf(stderr, "error getting ping reply: %d (%s)\n",
                        ret, dtn_strerror(dtn_errno(handle)));
                exit(1);
            }
            gettimeofday(&recv_end, 0);
            
            if (reply_payload.status_report != NULL)
            {
                sr_data = reply_payload.status_report;
                if (sr_data->flags != STATUS_DELETED) {
                    fprintf(stderr, "(bad status report from %s: flags 0x%x)\n",
                            reply_spec.source.uri, sr_data->flags);
                    goto next;
                }

                // find the seqno corresponding to the original
                // transmission time in the status report
                int j = 0;
                for (j = 0; j < MAX_PINGS_IN_FLIGHT; ++j) {
                    if (creation_times[j].secs  ==
                            sr_data->bundle_id.creation_ts.secs &&
                        creation_times[j].seqno ==
                            sr_data->bundle_id.creation_ts.seqno)
                    {
                        printf("bundle deleted at [%s] (%s): seqno=%d, time=%ld ms\n",
                               reply_spec.source.uri,
                               dtn_status_report_reason_to_str(sr_data->reason),
                               j, TIMEVAL_DIFF_MSEC(recv_end, send_times[j]));
                        goto next;
                    }
                }

                printf("bundle deleted at [%s] (%s): ERROR: can't find seqno\n",
                       reply_spec.source.uri, 
                       dtn_status_report_reason_to_str(sr_data->reason));
            }
            else {
                if (reply_payload.buf.buf_len != sizeof(ping_payload_t))
                {
                    printf("%d bytes from [%s]: ERROR: length != %zu\n",
                           reply_payload.buf.buf_len,
                           reply_spec.source.uri,
                           sizeof(ping_payload_t));
                    goto next;
                }

                memcpy(&recv_contents, reply_payload.buf.buf_val,
                       sizeof(recv_contents));
                
                if (recv_contents.seqno > MAX_PINGS_IN_FLIGHT)
                {
                    printf("%d bytes from [%s]: ERROR: invalid seqno %d\n",
                           reply_payload.buf.buf_len,
                           reply_spec.source.uri,
                           recv_contents.seqno);
                    goto next;
                }

                if (recv_contents.nonce != nonce)
                {
                    printf("%d bytes from [%s]: ERROR: invalid nonce %u != %u\n",
                           reply_payload.buf.buf_len,
                           reply_spec.source.uri,
                           recv_contents.nonce, nonce);
                    goto next;
                }

                if (recv_contents.time != (u_int32_t)send_times[recv_contents.seqno].tv_sec)
                {
                    printf("%d bytes from [%s]: ERROR: time mismatch -- "
                           "seqno %u reply time %u != send time %lu\n",
                           reply_payload.buf.buf_len,
                           reply_spec.source.uri,
                           recv_contents.seqno,
                           recv_contents.time,
                           (long unsigned int)send_times[recv_contents.seqno].tv_sec);
                    goto next;
                }
                
                printf("%d bytes from [%s]: '%.*s' seqno=%d, time=%ld ms\n",
                       reply_payload.buf.buf_len,
                       reply_spec.source.uri,
                       (u_int)strlen(PING_STR),
                       reply_payload.buf.buf_val,
                       recv_contents.seqno,
                       TIMEVAL_DIFF_MSEC(recv_end,
                                         send_times[recv_contents.seqno]));
                fflush(stdout);
            }
next:
            dtn_free_payload(&reply_payload);
            timeout -= TIMEVAL_DIFF_MSEC(recv_end, recv_start);

            // once we get status from all the pings we're supposed to
            // send, we're done
            reply_count++;
            if (count != 0 && reply_count == count) {
                break;
            }

        } while (timeout > 0);
        
        seqno++;
        seqno %= MAX_PINGS_IN_FLIGHT;
    }

    dtn_close(handle);

    return 0;
}
Example #3
0
int
main(int argc, const char** argv)
{
    int ret;
    dtn_handle_t handle;
    dtn_endpoint_id_t source_eid;
    dtn_endpoint_id_t replyto_eid;
    dtn_reg_info_t reginfo;
    dtn_reg_id_t regid;
    dtn_bundle_spec_t ping_spec;
    dtn_bundle_spec_t reply_spec;
    dtn_bundle_payload_t ping_payload;
    ping_payload_t payload_contents;
    ping_payload_t recv_contents;
    dtn_bundle_payload_t reply_payload;
    dtn_bundle_status_report_t* sr_data;
    dtn_bundle_id_t bundle_id;
    int debug = 1;
    char demux[64];
    int dest_len = 0;
    struct timeval send_time, now;
    u_int32_t nonce;
    int done;
    time_t clock;
    struct tm* tm_buf;
    
    // force stdout to always be line buffered, even if output is
    // redirected to a pipe or file
    setvbuf(stdout, (char *)NULL, _IOLBF, 0);
    
    doOptions(argc, argv);

    memset(&ping_spec, 0, sizeof(ping_spec));

    gettimeofday(&now, 0);
    srand(now.tv_sec);
    nonce = rand();
    
    // open the ipc handle
    int err = 0;
    if (api_IP_set) err = dtn_open_with_IP(api_IP,api_port,&handle);
    else err = dtn_open(&handle);

    if (err != DTN_SUCCESS) {
        fprintf(stderr, "fatal error opening dtn handle: %s\n",
                dtn_strerror(err));
        exit(1);
    }

    // make sure they supplied a valid destination eid or
    // "localhost", in which case we just use the local daemon
    if (strcmp(dest_eid_str, "localhost") == 0) {
        dtn_build_local_eid(handle, &ping_spec.dest, "ping");
        
    } else {
        if (dtn_parse_eid_string(&ping_spec.dest, dest_eid_str)) {
            fprintf(stderr, "invalid destination eid string '%s'\n",
                    dest_eid_str);
            exit(1);
        }
    }

    dest_len = strlen(ping_spec.dest.uri);
    if ((dest_len < 4) ||
        (strcmp(ping_spec.dest.uri + dest_len - 4, "ping") != 0))
    {
        fprintf(stderr, "\nWARNING: ping destination does not end in \"ping\"\n\n");
    }
    
    // if the user specified a source eid, register on it.
    // otherwise, build a local eid based on the configuration of
    // our dtn router plus the demux string
    snprintf(demux, sizeof(demux), "/traceroute.%d", getpid());
    if (source_eid_str[0] != '\0') {
        if (dtn_parse_eid_string(&source_eid, source_eid_str)) {
            fprintf(stderr, "invalid source eid string '%s'\n",
                    source_eid_str);
            exit(1);
        }
    } else {
        dtn_build_local_eid(handle, &source_eid, demux);
    }

    if (debug) printf("source_eid [%s]\n", source_eid.uri);
    dtn_copy_eid(&ping_spec.source, &source_eid);
    
    // Make the replyto EID
    if ( replyto_eid_str[0]!=0 ) {
        if (dtn_parse_eid_string(&replyto_eid, replyto_eid_str)) {
            fprintf(stderr, "invalid replyto eid string '%s'\n",
                    replyto_eid_str);
            exit(1);
        }
        dtn_copy_eid(&ping_spec.replyto, &replyto_eid);
        printf("using user-supplied replyto\n");
    } else {
        dtn_copy_eid(&ping_spec.replyto, &source_eid);
        printf("using default replyto\n");
    }

    // now create a new registration based on the source
    // if the replyto EID is unspecified or the same as the
    // source EID then we'll get status reports, otherwise
    // they'll go somewhere else.
    memset(&reginfo, 0, sizeof(reginfo));
    dtn_copy_eid(&reginfo.endpoint, &source_eid);
    reginfo.flags = DTN_REG_DROP;
    reginfo.regid = DTN_REGID_NONE;
    reginfo.expiration = 0;
    if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
        fprintf(stderr, "error creating registration: %d (%s)\n",
                ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }    
    if (debug) printf("dtn_register succeeded, regid %d\n", regid);

    // set the expiration time and request a bunch of status reports
    ping_spec.expiration = expiration;
    ping_spec.dopts = DOPTS_DELETE_RCPT |
                      DOPTS_RECEIVE_RCPT |
                      DOPTS_FORWARD_RCPT |
                      DOPTS_DELIVERY_RCPT;

    // loop, sending pings and polling for activity
    gettimeofday(&send_time, NULL);
        
    // fill in a short payload string, a nonce, and a sequence number
    // to verify the echo feature and make sure we're not getting
    // duplicate responses or ping responses from another app
    memcpy(&payload_contents.ping, PING_STR, 8);
    payload_contents.seqno = 0;
    payload_contents.nonce = nonce;
    payload_contents.time  = send_time.tv_sec;
        
    memset(&ping_payload, 0, sizeof(ping_payload));
    dtn_set_payload(&ping_payload, DTN_PAYLOAD_MEM,
                    (char*)&payload_contents, sizeof(payload_contents));
        
    memset(&bundle_id, 0, sizeof(bundle_id));
    if ((ret = dtn_send(handle, regid, &ping_spec, &ping_payload, &bundle_id)) != 0) {
        fprintf(stderr, "error sending bundle: %d (%s)\n",
                ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }
        
    memset(&reply_spec, 0, sizeof(reply_spec));
    memset(&reply_payload, 0, sizeof(reply_payload));

    clock = time(&clock);
    tm_buf = gmtime(&clock);
    printf("%s: sent at %.*s UTC\n",
           ping_spec.source.uri, 24, asctime(tm_buf));
    
    // now loop waiting for replies / status reports until we're done
    done = 0;
    while (1) {
        int timeout = done ? wait_after_done * 1000 : -1;
        if ((ret = dtn_recv(handle, &reply_spec,
                            DTN_PAYLOAD_MEM, &reply_payload, timeout)) < 0)
        {
            if (done && dtn_errno(handle) == DTN_ETIMEOUT) {
                break;
            }
            fprintf(stderr, "error getting ping reply: %d (%s)\n",
                    ret, dtn_strerror(dtn_errno(handle)));
            exit(1);
        }

        gettimeofday(&now, 0);
            
        if (reply_payload.status_report != NULL)
        {
            sr_data = reply_payload.status_report;
            if (sr_data->flags & STATUS_RECEIVED)
            {
                clock = sr_data->receipt_ts.secs + DTNTIME_OFFSET;
                tm_buf = gmtime(&clock);
                printf("%s: received at %.*s UTC (%ld ms rtt)\n",
                       reply_spec.source.uri, 24, asctime(tm_buf),
                       TIMEVAL_DIFF_MSEC(now, send_time));
            }
            if (sr_data->flags & STATUS_FORWARDED)
            {
                clock = sr_data->forwarding_ts.secs + DTNTIME_OFFSET;
                tm_buf = gmtime(&clock);
                printf("%s: forwarded at %.*s UTC (%ld ms rtt)\n",
                       reply_spec.source.uri, 24, asctime(tm_buf),
                       TIMEVAL_DIFF_MSEC(now, send_time));
            }
            if (sr_data->flags & STATUS_DELIVERED)
            {
                clock = sr_data->delivery_ts.secs + DTNTIME_OFFSET;
                tm_buf = gmtime(&clock);
                printf("%s: delivered at %.*s UTC (%ld ms rtt)\n",
                       reply_spec.source.uri, 24, asctime(tm_buf),
                       TIMEVAL_DIFF_MSEC(now, send_time));
            }
            if (sr_data->flags & STATUS_DELETED)
            {
                clock = sr_data->deletion_ts.secs + DTNTIME_OFFSET;
                tm_buf = gmtime(&clock);
                printf("%s: deleted at %.*s UTC (%s) (%ld ms rtt)\n",
                       reply_spec.source.uri, 24, asctime(tm_buf),
                       dtn_status_report_reason_to_str(sr_data->reason),
                       TIMEVAL_DIFF_MSEC(now, send_time));
                break;
            }
        }
        else {
            if (reply_payload.buf.buf_len != sizeof(ping_payload_t))
            {
                printf("%d bytes from [%s]: ERROR: length != %zu\n",
                       reply_payload.buf.buf_len,
                       reply_spec.source.uri,
                       sizeof(ping_payload_t));
                break;
            }

            memcpy(&recv_contents, reply_payload.buf.buf_val,
                   sizeof(recv_contents));
                
            if (recv_contents.seqno != 0)
            {
                printf("%d bytes from [%s]: ERROR: invalid seqno %d\n",
                       reply_payload.buf.buf_len,
                       reply_spec.source.uri,
                       recv_contents.seqno);
                break;
            }

            if (recv_contents.nonce != nonce)
            {
                printf("%d bytes from [%s]: ERROR: invalid nonce %u != %u\n",
                       reply_payload.buf.buf_len,
                       reply_spec.source.uri,
                       recv_contents.nonce, nonce);
                break;
            }

            if ((int)recv_contents.time != (int)send_time.tv_sec)
            {
                printf("%d bytes from [%s]: ERROR: time mismatch %u != %lu\n",
                       reply_payload.buf.buf_len,
                       reply_spec.source.uri,
                       recv_contents.time,
                       (long unsigned int)send_time.tv_sec);
            }
                
            clock = reply_spec.creation_ts.secs + DTNTIME_OFFSET;
            tm_buf = gmtime(&clock);
            printf("%s: echo reply at %.*s UTC (%ld ms rtt)\n",
                   reply_spec.source.uri, 24, asctime(tm_buf),
                   TIMEVAL_DIFF_MSEC(now, send_time));
            done = 1;
        }
        
        dtn_free_payload(&reply_payload);
    }
    
    dtn_close(handle);
    
    return 0;
}
Example #4
0
int
main(int argc, char** argv)
{
    int ret;
    dtn_handle_t handle;
    dtn_reg_info_t reginfo;
    dtn_reg_id_t regid = DTN_REGID_NONE;
    dtn_bundle_spec_t bundle_spec;
    dtn_bundle_spec_t reply_spec;
    dtn_bundle_payload_t send_payload;
    dtn_bundle_payload_t reply_payload;
    dtn_bundle_id_t bundle_id;
    char demux[4096];
    struct timeval start, end;

/*     FILE * file; */
/*     //struct stat finfo; */
/*     char buffer[4096]; // max filesize to send is 4096 (temp) */
/*     int bufsize = 0; */

    // force stdout to always be line buffered, even if output is
    // redirected to a pipe or file
    setvbuf(stdout, (char *)NULL, _IOLBF, 0);
    
    parse_options(argc, argv);

    // open the ipc handle
    if (verbose) fprintf(stdout, "Opening connection to local DTN daemon\n");

    int err = 0;
    if (api_IP_set) err = dtn_open_with_IP(api_IP,api_port,&handle);
    else err = dtn_open(&handle);

    if (err != DTN_SUCCESS) {
        fprintf(stderr, "fatal error opening dtn handle: %s\n",
                dtn_strerror(err));
        exit(1);
    }


    // ----------------------------------------------------
    // initialize bundle spec with src/dest/replyto
    // ----------------------------------------------------

    // initialize bundle spec
    memset(&bundle_spec, 0, sizeof(bundle_spec));

    // destination host is specified at run time, demux is hardcoded
    sprintf(demux, "%s/dtncp/recv?file=%s", arg_dest, arg_target);
    parse_eid(handle, &bundle_spec.dest, demux);

    // source is local eid with file path as demux string
    sprintf(demux, "/dtncp/send?source=%s", data_source);
    parse_eid(handle, &bundle_spec.source, demux);

    if (verbose)
    {
        print_eid("source_eid", &bundle_spec.source);
        print_eid("dest_eid", &bundle_spec.dest);
    }

    // set the expiration time (one hour)
    bundle_spec.expiration = expiration_time;
    
    if (delivery_receipts)
    {
        // set the delivery receipt option
        bundle_spec.dopts |= DOPTS_DELIVERY_RCPT;
    }

    // fill in a payload
    memset(&send_payload, 0, sizeof(send_payload));

    dtn_set_payload(&send_payload, DTN_PAYLOAD_FILE,
        data_source, strlen(data_source));
     
    // send file and wait for reply

    // create a new dtn registration to receive bundle status reports
    memset(&reginfo, 0, sizeof(reginfo));
    dtn_copy_eid(&reginfo.endpoint, &bundle_spec.source);
    reginfo.flags = DTN_REG_DEFER;
    reginfo.regid = regid;
    reginfo.expiration = 0;
    if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
        fprintf(stderr, "error creating registration (id=%d): %d (%s)\n",
                regid, ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }
    
    if (verbose) printf("dtn_register succeeded, regid 0x%x\n", regid);

    gettimeofday(&start, NULL); // timer

    memset(&bundle_id, 0, sizeof(bundle_id));
                
    if ((ret = dtn_send(handle, regid, &bundle_spec, &send_payload,
                        &bundle_id)) != 0) {
        fprintf(stderr, "error sending file bundle: %d (%s)\n",
                ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }

    if (delivery_receipts)
      {
	memset(&reply_spec, 0, sizeof(reply_spec));
	memset(&reply_payload, 0, sizeof(reply_payload));
	
	// now we block waiting for the echo reply
	if ((ret = dtn_recv(handle, &reply_spec,
			    DTN_PAYLOAD_MEM, &reply_payload, -1)) < 0)
	  {
	    fprintf(stderr, "error getting reply: %d (%s)\n",
		    ret, dtn_strerror(dtn_errno(handle)));
	    exit(1);
	  }
	gettimeofday(&end, NULL);


	printf("file sent successfully to [%s]: time=%.1f ms\n",
	       reply_spec.source.uri,
	       ((double)(end.tv_sec - start.tv_sec) * 1000.0 + 
		(double)(end.tv_usec - start.tv_usec)/1000.0));
	
	dtn_free_payload(&reply_payload);
      } 
    else 
      {
	printf("file sent to [%s]\n",
	       bundle_spec.dest.uri);
      }

    dtn_close(handle);
    
    return 0;
}
int
reader_thread(void *p)
{

    // loop reading from motes, writing to directory

    static int tcnt=0;
    DATAPACKET *dataPacket;

    // dtn api variables
    int ret;
    dtn_handle_t handle;
    dtn_reg_info_t reginfo;
    dtn_reg_id_t regid = DTN_REGID_NONE;
    dtn_bundle_spec_t bundle_spec;
    dtn_bundle_payload_t send_payload;
    dtn_bundle_id_t bundle_id;
    char demux[4096];

    p = NULL;

    // open the ipc handle
    if (debug > 0) fprintf(stdout, "Opening connection to local DTN daemon\n");

    int err = 0;
    if (api_IP_set) err = dtn_open_with_IP(api_IP,api_port,&handle);
    else err = dtn_open(&handle);

    if (err != DTN_SUCCESS) {
        fprintf(stderr, "fatal error opening dtn handle: %s\n",
                dtn_strerror(err));
        exit(1);
    }

    // ----------------------------------------------------
    // initialize bundle spec with src/dest/replyto
    // ----------------------------------------------------

    // initialize bundle spec
    memset(&bundle_spec, 0, sizeof(bundle_spec));

    // destination host is specified at run time, demux is hardcoded
    sprintf(demux, "%s/dtnmoteproxy/recv", arg_dest);
    parse_eid(handle, &bundle_spec.dest, demux);

    // source is local eid with file path as demux string
    sprintf(demux, "/dtnmoteproxy/send");
    parse_eid(handle, &bundle_spec.source, demux);

    // reply to is the same as the source
    dtn_copy_eid(&bundle_spec.replyto, &bundle_spec.source);


    if (debug > 2)
    {
        print_eid("source_eid", &bundle_spec.source);
        print_eid("replyto_eid", &bundle_spec.replyto);
        print_eid("dest_eid", &bundle_spec.dest);
    }

    // set the return receipt option
    bundle_spec.dopts |= DOPTS_DELIVERY_RCPT;

    // send file and wait for reply

    // create a new dtn registration to receive bundle status reports
    memset(&reginfo, 0, sizeof(reginfo));
    dtn_copy_eid(&reginfo.endpoint, &bundle_spec.replyto);
    reginfo.flags = DTN_REG_DEFER;
    reginfo.regid = regid;
    reginfo.expiration = 0;
    if ((ret = dtn_register(handle, &reginfo, &regid)) != 0) {
        fprintf(stderr, "error creating registration (id=%d): %d (%s)\n",
                regid, ret, dtn_strerror(dtn_errno(handle)));
        exit(1);
    }

    if (debug > 3) printf("dtn_register succeeded, regid 0x%x\n", regid);

    while (1) {
        static unsigned char motedata[BUFSIZ];
        int length;
        int ret;

        if (debug > 1) fprintf(dout, "about to read from motes...\n");

        while((ret=read_packet((char *) motedata, (int *) &length))) {
            if(ret==DEBUG_PKT)
                continue;
            if (debug > 0) {
                fprintf(dout, "\nreader loop... got [%d] bytes from motes\n",
                        length);
                if (debug > 1) hexdump(motedata, length);
            }

            // the extra cast to void* is needed to circumvent gcc warnings
            // about unsafe casting
            dataPacket=(DATAPACKET *)((void*)motedata);

            // skip packets from base mote
            if(dataPacket->origin_mote_id == 0) continue;

            // set a default expiration time of one hour
            bundle_spec.expiration = 3600;

            // fill in a payload
            memset(&send_payload, 0, sizeof(send_payload));

            dtn_set_payload(&send_payload, DTN_PAYLOAD_MEM,
                            (char *) motedata, length);

            memset(&bundle_id, 0, sizeof(bundle_id));

            if ((ret = dtn_send(handle, regid, &bundle_spec, &send_payload,
                                &bundle_id)) != 0)
            {
                fprintf(stderr, "error sending bundle: %d (%s)\n",
                        ret, dtn_strerror(dtn_errno(handle)));
            }
            else fprintf(stderr, "motedata bundle sent");

            printf("Mote ID = %u\n",dataPacket->origin_mote_id);
            printf("Source Mote ID = %u\n",dataPacket->source_mote_id);
            printf("Hop Count = %u\n",dataPacket->hop_cnt);
            printf("Packet Type = %u\n",dataPacket->surge_pkt_type);
            printf("Parent Address = %u\n",dataPacket->surge_parent_addr);
            printf("Sequence Number = %u\n", (u_int)dataPacket->surge_seq_no);
            printf("Light = %u\n",dataPacket->light);
            printf("Temperature = %u\n\n",dataPacket->temp);

            tcnt=(tcnt+1)%10000;

        }
        if (debug > 0)
            fprintf(dout, "reader loop.... nothing to do? [shouldn't happen]\n");
    }

    // if this was ever changed to gracefully shutdown, it would be good to call:
    dtn_close(handle);

    return (1);
    // NOTREACHED
}