// -------------------------------------------------------------------------- //
//
void Test_Specswap::testAddCurve()
{
    // Setup a specswap object.
    int sample = 250;
    Mlrnd rand;
    std::string path("./testfiles/testlibLarge");
    Specswap ss(sample, rand, path);

    // Check that there are no curve data added.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ss.curve_data_.size()), 0 );

    // Setup input for adding a curve.
    std::string curve_name("bas");
    std::string filename("./testfiles/exafs_ref.data");
    double sigma = 0.0002;
    bool area_renorm = true;
    ss.add_curve(sigma, area_renorm, curve_name, filename);

    // Check that a scalar distribution has been added.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ss.curve_data_.size()), 1 );

    // Add another one.
    ss.add_curve(sigma, area_renorm, curve_name, filename);

    // Check.
    CPPUNIT_ASSERT_EQUAL( static_cast<int>(ss.curve_data_.size()), 2 );

    // Make sure we fail with an unrecognized curve.
    curve_name = "NOT_A_CURVENAME";
    //ss.add_curve(sigma, area_renorm, curve_name, filename);
    CPPUNIT_ASSERT_THROW( ss.add_curve(sigma, area_renorm, curve_name, filename), IOException );

    // Make sure we fail with a non existing reference file.
    curve_name = "bas";
    filename = "./testfiles/NO_SUCH_FILE";
    //ss.add_curve(sigma, area_renorm, curve_name, filename);
    CPPUNIT_ASSERT_THROW( ss.add_curve(sigma, area_renorm, curve_name, filename), IOException );

}
// -------------------------------------------------------------------------- //
//
void Test_Specswap::testAccept()
{
    // Setup a specswap object with many different data sets.
    std::string path("./testfiles/testlibLarge");
    int sample = 12;
    Mlrnd rand;
    rand.set_seed(39);
    Specswap ss1(sample, rand, path);

    // Mean scalar.
    std::string scalarname("VP-Volume");
    double target = 0.5;
    double sigma = 1.0;
    ss1.add_scalar_mean(scalarname, target, sigma);
    sigma = 0.0012;
    ss1.add_scalar_mean(scalarname, target, sigma);

    // Value scalar.
    scalarname = "VP-Area";
    double value_low = 0.5;
    double value_high = 1.0;
    double fraction = 0.6;
    sigma = 0.0001;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);
    fraction = 0.1;
    sigma = 0.0001;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);
    value_low = 0.0;
    value_high = 1.3;
    fraction = 0.99;
    sigma = 0.01;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);

    // Scalar distribution.
    scalarname = "VP-Volume";
    std::string filename("./testfiles/vvol_ref.data");
    sigma = 0.0002;
    ss1.add_scalar_distribution(scalarname, filename, sigma);
    sigma = 0.0099;
    ss1.add_scalar_distribution(scalarname, filename, sigma);

    // Curve.
    std::string curve_name("bas");
    filename = "./testfiles/exafs_ref.data";
    sigma = 0.0002;
    bool area_renorm = true;
    ss1.add_curve(sigma, area_renorm, curve_name, filename);
    area_renorm = false;
    ss1.add_curve(sigma, area_renorm, curve_name, filename);

    // Setup input for adding a pcf.
    double rmin = 0.0;
    double rmax = 5.0;
    double dr = 0.02;
    double numberdensity = 0.4;
    std::pair<double,double> fit_interval(1.3, 3.0);
    int nbins = 250;
    std::pair<int,int> partial(0,1);
    std::string ref_path("./testfiles/gr_ref.data");
    sigma = 0.01;
    ss1.add_pcf(rmin, rmax, dr, sigma, numberdensity, fit_interval, nbins, partial, ref_path);
    sigma = 0.0123;
    ss1.add_pcf(rmin, rmax, dr, sigma, numberdensity, fit_interval, nbins, partial, ref_path);

    // Setup.
    ss1.setup();
    // Move.
    ss1.move();

    // Check what slot and indices will be swapped.
    CPPUNIT_ASSERT_EQUAL( ss1.from_sample_, 583);
    CPPUNIT_ASSERT_EQUAL( ss1.from_basis_, 2354);
    CPPUNIT_ASSERT_EQUAL( ss1.slot_, 11);

    // Check that the sample set is correct.
    CPPUNIT_ASSERT_EQUAL( ss1.sampleset_.index_at(ss1.slot_), ss1.from_sample_);

    // Notify.
    ss1.notify();

    // Check the chi2 value.
    double diff = 7.2603029936e+08 - 6.5624713898e-04 - ss1.chi2_;
    CPPUNIT_ASSERT_DOUBLES_EQUAL( diff, 0.0, 1.0e-10 );

    // Check that the chi2_new value has been updated.
    diff = 7.4256423439e+08 + 1.9059181213e-03 - ss1.chi2_new_;
    CPPUNIT_ASSERT_DOUBLES_EQUAL( diff, 0.0, 1.0e-10 );

    // Call the accept and make sure Chi2 has been accepted.
    ss1.accept();
    CPPUNIT_ASSERT_DOUBLES_EQUAL( ss1.chi2_, ss1.chi2_new_, 1.0e-10 );

    // Check that the sample set is correct.
    CPPUNIT_ASSERT_EQUAL( ss1.sampleset_.index_at(ss1.slot_), ss1.from_basis_);
}
// -------------------------------------------------------------------------- //
//
void Test_Specswap::testNotify()
{
    // Setup a specswap object with many different data sets.
    std::string path("./testfiles/testlibLarge");
    int sample = 12;
    Mlrnd rand;
    rand.set_seed(39);
    Specswap ss1(sample, rand, path);

    // Mean scalar.
    std::string scalarname("VP-Volume");
    double target = 0.5;
    double sigma = 1.0;
    ss1.add_scalar_mean(scalarname, target, sigma);
    sigma = 0.0012;
    ss1.add_scalar_mean(scalarname, target, sigma);

    // Value scalar.
    scalarname = "VP-Area";
    double value_low = 0.5;
    double value_high = 1.0;
    double fraction = 0.6;
    sigma = 0.0001;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);
    fraction = 0.1;
    sigma = 0.0001;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);
    value_low = 0.0;
    value_high = 1.3;
    fraction = 0.99;
    sigma = 0.01;
    ss1.add_scalar_value(scalarname, value_low, value_high, fraction, sigma);

    // Scalar distribution.
    scalarname = "VP-Volume";
    std::string filename("./testfiles/vvol_ref.data");
    sigma = 0.0002;
    ss1.add_scalar_distribution(scalarname, filename, sigma);
    sigma = 0.0099;
    ss1.add_scalar_distribution(scalarname, filename, sigma);

    // Curve.
    std::string curve_name("bas");
    filename = "./testfiles/exafs_ref.data";
    sigma = 0.0002;
    bool area_renorm = true;
    ss1.add_curve(sigma, area_renorm, curve_name, filename);
    area_renorm = false;
    ss1.add_curve(sigma, area_renorm, curve_name, filename);

    // Setup input for adding a pcf.
    double rmin = 0.0;
    double rmax = 5.0;
    double dr = 0.02;
    double numberdensity = 0.4;
    std::pair<double,double> fit_interval(1.3, 3.0);
    int nbins = 250;
    std::pair<int,int> partial(0,1);
    std::string ref_path("./testfiles/gr_ref.data");
    sigma = 0.01;
    ss1.add_pcf(rmin, rmax, dr, sigma, numberdensity, fit_interval, nbins, partial, ref_path);
    sigma = 0.0123;
    ss1.add_pcf(rmin, rmax, dr, sigma, numberdensity, fit_interval, nbins, partial, ref_path);


    // Set the initial chi2_ value to some thing unreasonable.
    ss1.chi2_new_ = -1.123;
    // Call the setup function.
    ss1.from_sample_ = 0;
    ss1.from_basis_ = 12;
    ss1.setup();
    // Call notify.
    ss1.notify();

    // Check that the chi2 value has been updated.
    CPPUNIT_ASSERT_DOUBLES_EQUAL(735129583.538380026817, ss1.chi2_new_, 1.0e-8);
}
Exemple #4
0
/**
 * This is the main message reading loop.  Messages are read, validated,
 * decrypted if necessary, then passed to the appropriate routine for handling.
 */
void mainloop(void)
{
    struct uftp_h *header;
    struct group_list_t *group;
    unsigned char *buf, *decrypted, *message;
    char rxname[INET6_ADDRSTRLEN];
    unsigned int decryptlen, meslen;
    int packetlen, rval, i, ecn;
    uint8_t version, *func, tos;
    uint16_t txseq;
    union sockaddr_u src;
    struct timeval *tv, rxtime;
    double new_grtt;

    log2(0, 0, 0, "%s", VERSIONSTR);
    for (i = 0; i < key_count; i++) {
        if (privkey_type[i] == KEYBLOB_RSA) {
            log2(0, 0, 0, "Loaded %d bit RSA key with fingerprint %s",
                  RSA_keylen(privkey[i].rsa) * 8,
                  print_key_fingerprint(privkey[i], KEYBLOB_RSA));
        } else {
            log2(0, 0, 0, "Loaded ECDSA key with curve %s and fingerprint %s",
                  curve_name(get_EC_curve(privkey[i].ec)),
                  print_key_fingerprint(privkey[i], KEYBLOB_EC));
        }
    }

    buf = safe_calloc(MAXMTU, 1);
    decrypted = safe_calloc(MAXMTU, 1);
    header = (struct uftp_h *)buf;

    while (1) {
        tv = getrecenttimeout();
        if (tv) {
            log5(0, 0, 0, "read timeout: %d.%06d", tv->tv_sec, tv->tv_usec);
        }
        if (read_packet(listener, &src, buf, &packetlen,
                        MAXMTU, tv, &tos) <= 0) {
            continue;
        }
        gettimeofday(&rxtime, NULL);

        if ((rval = getnameinfo((struct sockaddr *)&src, family_len(src),
                rxname, sizeof(rxname), NULL, 0, NI_NUMERICHOST)) != 0) {
            log1(0, 0, 0, "getnameinfo failed: %s", gai_strerror(rval));
        }

        if (header->version == UFTP_VER_NUM) {
            version = header->version;
            group = find_group(ntohl(header->group_id), header->group_inst);
        } else {
            log1(0, 0, 0, "Invalid message from %s: not uftp packet "
                          "or invalid version", rxname);
            continue;
        }
        if (packetlen < sizeof(struct uftp_h) + 4) {
            log1(0, 0, 0, "Invalid packet size from %s: %d", rxname, packetlen);
            continue;
        }

        txseq = htons(header->seq);
        // A KEY_INFO or ABORT could come from a proxy, so don't check the seq
        // TODO: need to account for these in the loss history
        if ((group != NULL) && (header->func != KEYINFO) &&
                (header->func != ABORT)) {
            if ((int16_t)(group->max_txseq - txseq) > MAXMISORDER) {
                glog3(group, "seq out of range, dropping");
                continue;
            }
            if (group->cc_type != CC_NONE) {
                ecn = ((tos & 0x3) == 3);
                update_loss_history(group, txseq, packetlen, ecn);
            } else if ((int16_t)(txseq - group->max_txseq) > 0) {
                group->max_txseq = txseq;
            }
        }

        if ((header->func == ENCRYPTED) && (group != NULL) &&
                (group->keytype != KEY_NONE)) {
            if (group->phase == PHASE_REGISTERED) {
                glog1(group, "Got encrypted packet from %s "
                             "but keys not established", rxname);
            }

            if (!validate_and_decrypt(buf, packetlen, &decrypted, &decryptlen,
                    group->keytype, group->groupkey, group->groupsalt,
                    group->ivlen, group->hashtype, group->grouphmackey,
                    group->hmaclen, group->sigtype, group->keyextype,
                    group->server_pubkey, group->server_pubkeylen)) {
                glog1(group, "Rejecting message from %s: "
                             "decrypt/validate failed", rxname);
                continue;
            }
            func = (uint8_t *)decrypted;
            message = decrypted;
            meslen = decryptlen;
        } else {
            if ((group != NULL) && (group->keytype != KEY_NONE) &&
                    ((header->func == FILEINFO) || (header->func == FILESEG) ||
                     (header->func == DONE) || (header->func == DONE_CONF) ||
                     ((header->func == ABORT) &&
                         (group->phase != PHASE_REGISTERED)))) {
                glog1(group, "Rejecting %s message from %s: not encrypted",
                             func_name(header->func), rxname);
                continue;
            }
            func = (uint8_t *)&header->func;
            message = buf + sizeof(struct uftp_h);
            meslen = packetlen - sizeof(struct uftp_h);
        }

        if (group != NULL) {
            new_grtt = unquantize_grtt(header->grtt);
            if (fabs(new_grtt - group->grtt) > 0.001) {
                group->grtt = new_grtt;
                set_timeout(group, 1);
            }
            group->gsize = unquantize_gsize(header->gsize);
            glog5(group, "grtt: %.3f", group->grtt);
        }

        if (header->func == PROXY_KEY) {
            handle_proxy_key(&src, message, meslen);
            continue;
        }
        if (header->func == HB_RESP) {
            handle_hb_response(listener, &src, message, meslen, hb_hosts,
                               hbhost_count, privkey[0], privkey_type[0], uid);
            continue;
        }
        if (header->func == ANNOUNCE) {
            // Ignore any ANNOUNCE for a group we're already handling
            if (group == NULL) {
                handle_announce(&src, buf, packetlen, rxtime);
            } else if (group->phase == PHASE_MIDGROUP) {
                // Make sure we don't time out while waiting for other
                // clients to register with the server.
                set_timeout(group, 0);
            }
        } else {
            if (group == NULL) {
                // group / file ID not in list
                continue;
            }
            if (group->version != version) {
                glog1(group, "Version mismatch");
                continue;
            }
            if (group->src_id != header->src_id) {
                glog1(group, "Source ID mismatch");
                continue;
            }
            if (*func == ABORT) {
                handle_abort(group, message, meslen);
                continue;
            }
            switch (group->phase) {
            case PHASE_REGISTERED:
                if (group->keytype != KEY_NONE) {
                    if (*func == KEYINFO) {
                        handle_keyinfo(group, message, meslen, header->src_id);
                    } else {
                        glog1(group, "Expected KEYINFO, got %s",
                                     func_name(*func));
                    }
                } else if (group->keytype == KEY_NONE) {
                    if (*func == REG_CONF) {
                        handle_regconf(group, message, meslen);
                    } else if (*func == FILEINFO) {
                        handle_fileinfo(group, message, meslen, rxtime);
                    } else {
                        glog1(group, "Expected REG_CONF, got %s",
                                     func_name(*func));
                    }
                }
                break;
            case PHASE_MIDGROUP:
                if (*func == FILEINFO) {
                    handle_fileinfo(group, message, meslen, rxtime);
                } else if (*func == KEYINFO) {
                    handle_keyinfo(group, message, meslen, header->src_id);
                } else if (*func == DONE) {
                    handle_done(group, message, meslen);
                } else {
                    // Other clients may be still getting earlier files or
                    // setting up, so silently ignore anything unexpected
                    // and reset the timeout.
                    set_timeout(group, 0);
                }
                break;
            case PHASE_RECEIVING:
                if (*func == FILEINFO) {
                    handle_fileinfo(group, message, meslen, rxtime);
                } else if (*func == FILESEG) {
                    handle_fileseg(group, message, meslen, txseq);
                } else if (*func == DONE) {
                    handle_done(group, message, meslen);
                } else if (*func == CONG_CTRL) {
                    handle_cong_ctrl(group, message, meslen, rxtime);
                }
                break;
            case PHASE_COMPLETE:
                if (*func == DONE_CONF) {
                    handle_done_conf(group, message, meslen);
                }
                break;
            }
        }
    }
}