<commit_before>/*******************************************************************************
 * Copyright (c) 2015 Wojciech Migda
 * All rights reserved
 * Distributed under the terms of the GNU LGPL v3
 *******************************************************************************
 *
 * Filename: TripSafetyFactors.hpp
 *
 * Description:
 *      TripSafetyFactors class
 *
 * Authors:
 *          Wojciech Migda (wm)
 *
 *******************************************************************************
 * History:
 * --------
 * Date         Who  Ticket     Description
 * ----------   ---  ---------  ------------------------------------------------
 * 2015-01-27   wm              Initial version
 *
 ******************************************************************************/

#ifndef TRIPSAFETYFACTORS_HPP_
#define TRIPSAFETYFACTORS_HPP_

#include "array2d.hpp"
#include "logreg.hpp"
#include "num.hpp"

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iterator>

typedef double real_type;

std::vector<int> do_log_reg(
    num::array2d<real_type> && i_X_train,
    std::valarray<real_type> && i_y_train,
    num::array2d<real_type> && i_X_test
)
{
    std::vector<int> result(i_X_test.shape().first);

    const num::size_type NUM_FEAT{i_X_train.shape().second + 1};

    // let's map input features onto what we'll work with
    num::array2d<real_type> X_train =
        num::ones<real_type>(num::shape_type{i_X_train.shape().first, NUM_FEAT});

    X_train[X_train.columns(1, X_train.shape().second - 1)] =
        i_X_train[i_X_train.columns(0, i_X_train.shape().second - 1)];

    // same with test features
    num::array2d<real_type> X_test =
        num::ones<real_type>(num::shape_type{i_X_test.shape().first, NUM_FEAT});

    X_test[X_test.columns(1, X_test.shape().second - 1)] =
        i_X_test[i_X_test.columns(0, i_X_test.shape().second - 1)];

    std::valarray<real_type> y_train = i_y_train.apply([](real_type v){return v > 1.0 ? 1.0 : v;});

    std::valarray<real_type> theta(0.0, X_train.shape().second);

    {
        // testing
        for (num::size_type c{1}; c < X_train.shape().second; ++c)
        {
            const std::valarray<real_type> & col = X_train[X_train.column(c)];
            const std::valarray<real_type> & colt = X_test[X_test.column(c)];

            const real_type mu = num::mean<real_type>(col);
            const real_type dev = num::std<real_type>(col);

            X_train[X_train.column(c)] = col - mu;
            X_train[X_train.column(c)] = col / dev;

            X_test[X_test.column(c)] = colt - mu;
            X_test[X_test.column(c)] = colt / dev;
        }
    }

    num::LogisticRegression<real_type> logRegClassifier(
        num::LogisticRegression<real_type>::array_type{X_train},
        num::LogisticRegression<real_type>::vector_type{y_train},
        num::LogisticRegression<real_type>::vector_type{theta},
        0.03,
        200
    );

    auto fit_theta = logRegClassifier.fit();

//    std::copy(std::begin(fit_theta), std::end(fit_theta), std::ostream_iterator<real_type>(std::cerr, "\n"));

    auto pred = logRegClassifier.predict(X_test, fit_theta, false);
//    std::copy(std::begin(pred), std::end(pred), std::ostream_iterator<real_type>(std::cerr, "\n"));
    std::cerr << "pred.max() " << pred.max() << std::endl;
    {
        std::vector<std::pair<num::size_type, real_type>> zipped;
        zipped.reserve(pred.size());

        for (num::size_type idx = 0; idx < pred.size(); ++idx)
        {
            zipped.push_back(std::pair<num::size_type, real_type>(idx + 1, pred[idx]));
        }
        std::sort(zipped.begin(), zipped.end(),
            [](const std::pair<num::size_type, real_type> & p, const std::pair<num::size_type, real_type> & q)
            {
                return p.second > q.second;
            }
        );
        std::transform(zipped.cbegin(), zipped.cend(), result.begin(),
            [](const std::pair<num::size_type, real_type> & p)
            {
                return (int)p.first;
            }
        );
    }

    return result;
}

struct TripSafetyFactors
{
    std::vector<int> predict(
        std::vector<std::string> i_train_data,
        std::vector<std::string> i_test_data) const;
};

std::vector<int>
TripSafetyFactors::predict(
    std::vector<std::string> i_train_data,
    std::vector<std::string> i_test_data) const
{
    enum col : num::size_type
    {
        ID,
        SOURCE,
        DIST,
        CYCLES,
        COMPLEXITY,
        CARGO,
        STOPS,
        START_DAY,
        START_MONTH,
        START_DAY_OF_MONTH,
        START_DAY_OF_WEEK,
        START_TIME,
        DAYS,
        PILOT,
        PILOT2,
        PILOT_EXP,
        PILOT_VISITS_PREV,
        PILOT_HOURS_PREV,
        PILOT_DUTY_HOURS_PREV,
        PILOT_DIST_PREV,
        ROUTE_RISK_1,
        ROUTE_RISK_2,
        WEATHER,
        VISIBILITY,
        TRAF0,
        TRAF1,
        TRAF2,
        TRAF3,
        TRAF4,
        /////////////
        ACCEL_CNT,
        DECEL_CNT,
        SPEED_CNT,
        STABILITY_CNT,
        EVT_CNT
    };
    const num::size_type TRAIN_ROWS{i_train_data.size()};
    constexpr num::size_type TRAIN_COLS{34};

    const num::size_type TEST_ROWS{i_test_data.size()};
    constexpr num::size_type TEST_COLS{29};

    const num::shape_type TRAIN_SHAPE{TRAIN_ROWS, TRAIN_COLS};
    const num::shape_type TEST_SHAPE{TEST_ROWS, TEST_COLS};

    std::vector<int> result(TEST_ROWS);

    //////////////
    std::iota(result.begin(), result.end(), 1);
    std::random_shuffle(result.begin(), result.end());
    //////////////

    auto time_xlt = [](const char * str) -> real_type
    {
        char * next;
        long int result = std::strtol(str, &next, 10) * 60;
        if (*next == ':')
        {
            result += std::strtol(next + 1, nullptr, 10);
        }
        return result;
    };
    num::array2d<real_type> train_data =
        num::loadtxt(
            std::move(i_train_data),
            std::move(
                num::loadtxtCfg<real_type>()
                .delimiter(',')
                .converters(num::loadtxtCfg<real_type>::converters_type{{col::START_TIME, time_xlt}})
            )
        );
    std::cerr << train_data.shape() << std::endl;

    num::array2d<real_type> test_data =
        num::loadtxt(
            std::move(i_test_data),
            std::move(
                num::loadtxtCfg<real_type>()
                .delimiter(',')
                .converters(num::loadtxtCfg<real_type>::converters_type{{col::START_TIME, time_xlt}})
            )
        );
    std::cerr << test_data.shape() << std::endl;

    num::array2d<real_type> X_train_data(num::shape_type{train_data.shape().first, col::TRAF4 - col::SOURCE + 1}, 0.0);
    X_train_data[X_train_data.columns(0, X_train_data.shape().second - 1)] =
        train_data[train_data.columns(col::SOURCE, col::TRAF4)];

    std::valarray<real_type> y_train_data = train_data[train_data.column(col::EVT_CNT)];

    num::array2d<real_type> X_test_data(num::shape_type{test_data.shape().first, test_data.shape().second - 1}, 0.0);
    X_test_data[X_test_data.columns(0, X_test_data.shape().second - 1)] =
        test_data[test_data.columns(col::SOURCE, col::TRAF4)];

    result = do_log_reg(std::move(X_train_data), std::move(y_train_data), std::move(X_test_data));

//    void foo();
//    foo();

    return result;
}

//#include <functional>
//#include "fmincg.hpp"
//#include <iterator>
//#include <fstream>
//void foo()
//{
//    typedef double real;
//    std::vector<std::string> Xtxt;
//    std::vector<std::string> ytxt;
//    {
//        std::ifstream fcsv("xxx.txt");
//
//        for (std::string line; std::getline(fcsv, line);)
//        {
//            Xtxt.push_back(line);
//        }
//        fcsv.close();
//    }
//    {
//        std::ifstream fcsv("xxy.txt");
//
//        for (std::string line; std::getline(fcsv, line);)
//        {
//            ytxt.push_back(line);
//        }
//        fcsv.close();
//    }
//    num::array2d<real> X =
//        num::loadtxt(
//            std::move(Xtxt),
//            std::move(
//                num::loadtxtCfg<real>()
//                .delimiter(',')
//            )
//        );
//    std::cerr << X.shape() << std::endl;
//    num::array2d<real> ym =
//        num::loadtxt(
//            std::move(ytxt),
//            std::move(
//                num::loadtxtCfg<real>()
//                .delimiter(',')
//            )
//        );
//    std::cerr << ym.shape() << std::endl;
//    std::valarray<real> y = ym[ym.column(0)];
//
//    std::valarray<real> theta(0.0, X.shape().second);
//
//    num::LogisticRegression<real> logRegClassifier(
//        num::LogisticRegression<real>::array_type{X},
//        num::LogisticRegression<real>::vector_type{y},
//        num::LogisticRegression<real>::vector_type{theta},
//        1.0,
//        400
//    );
//
//    auto fit_theta = logRegClassifier.fit();
//    std::copy(std::begin(fit_theta), std::end(fit_theta), std::ostream_iterator<real>(std::cerr, "\n"));
//
//    auto prediction = logRegClassifier.predict(X, fit_theta);
//    std::copy(std::begin(prediction), std::end(prediction), std::ostream_iterator<real>(std::cerr, "\n"));
//
//    return;
//}

#endif /* TRIPSAFETYFACTORS_HPP_ */
<commit_msg>feature remapping and code decluttering<commit_after>/*******************************************************************************
 * Copyright (c) 2015 Wojciech Migda
 * All rights reserved
 * Distributed under the terms of the GNU LGPL v3
 *******************************************************************************
 *
 * Filename: TripSafetyFactors.hpp
 *
 * Description:
 *      TripSafetyFactors class
 *
 * Authors:
 *          Wojciech Migda (wm)
 *
 *******************************************************************************
 * History:
 * --------
 * Date         Who  Ticket     Description
 * ----------   ---  ---------  ------------------------------------------------
 * 2015-01-27   wm              Initial version
 *
 ******************************************************************************/

#ifndef TRIPSAFETYFACTORS_HPP_
#define TRIPSAFETYFACTORS_HPP_

#include "array2d.hpp"
#include "logreg.hpp"
#include "num.hpp"

#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <iterator>
#include <map>

typedef double real_type;

std::map<real_type, real_type>
map_event_density(
    const std::valarray<real_type> & feat,
    const std::valarray<real_type> & y
)
{
    std::map<real_type, std::pair<num::size_type, num::size_type>> event_count;

    assert(feat.size() == y.size());

    for (num::size_type r{0}; r < feat.size(); ++r)
    {
        event_count[feat[r]].first++;
        event_count[feat[r]].second += y[r];
    }

    std::map<real_type, real_type> result;

    for (auto count : event_count)
    {
        result[count.first] = (real_type)count.second.second / count.second.first;
    }

    return result;
}

std::vector<int> do_log_reg(
    num::array2d<real_type> && i_X_train,
    std::valarray<real_type> && i_y_train,
    num::array2d<real_type> && i_X_test
)
{
    typedef num::array2d<real_type> array_type;
    typedef std::valarray<real_type> vector_type;

    const num::size_type NUM_FEAT{i_X_train.shape().second + 1};

    // let's map input training features onto what we'll work with
    // first column will be 1s for the intercept
    array_type X_train = num::ones<real_type>({i_X_train.shape().first, NUM_FEAT});

    // the rest will be copied from i_X_train
    // X_train[:, 1:] = i_X_train[:, :]
    X_train[X_train.columns(1, -1)] = i_X_train[i_X_train.columns(0, -1)];

    // same with test features
    array_type X_test = num::ones<real_type>({i_X_test.shape().first, NUM_FEAT});

    // X_test[:, 1:] = i_X_test[:, :]
    X_test[X_test.columns(1, -1)] = i_X_test[i_X_test.columns(0, -1)];

    // we got train and test features mapped

    // lets keep columnd indices under control
    enum col : num::size_type
    {
        INTERCEPT,
        SOURCE, // *
        DIST,
        CYCLES,
        COMPLEXITY,
        CARGO, // *
        STOPS,
        START_DAY,
        START_MONTH,
        START_DAY_OF_MONTH,
        START_DAY_OF_WEEK,
        START_TIME,
        DAYS,
        PILOT, // *
        PILOT2, // *
        PILOT_EXP,
        PILOT_VISITS_PREV,
        PILOT_HOURS_PREV,
        PILOT_DUTY_HOURS_PREV,
        PILOT_DIST_PREV,
        ROUTE_RISK_1,
        ROUTE_RISK_2,
        WEATHER, // *
        VISIBILITY,
        TRAF0,
        TRAF1,
        TRAF2,
        TRAF3,
        TRAF4,
    };

    // There are some features (marked with asterix above) which do not have
    // a meaning in a monotonic domain. Let's do the following experiment:
    // for each of those features map to each occuring value a pair of values -
    // a number of occurences and a sum of events,
    // then we remap the original values to event density

    for (auto COLUMN :
        std::initializer_list<int>
        {
            col::SOURCE,
            col::CARGO,
            col::PILOT,
            col::PILOT2,

//            col::START_DAY, // ---
            col::START_MONTH, // +++
//            col::START_DAY_OF_MONTH, // ---
//            col::START_DAY_OF_WEEK, // ---
//            col::WEATHER
        }
    )
    {
        auto event_density = map_event_density(X_train[X_train.column(COLUMN)], i_y_train);
        std::cerr << "event density size: " << event_density.size() << std::endl;

        vector_type mapped_train_col = X_train[X_train.column(COLUMN)];
        std::transform(std::begin(mapped_train_col), std::end(mapped_train_col), std::begin(mapped_train_col),
            [&event_density](const real_type & x) -> real_type
            {
                return event_density[x];
            }
        );
        X_train[X_train.column(COLUMN)] = mapped_train_col;

        vector_type mapped_test_col = X_test[X_test.column(COLUMN)];
        std::transform(std::begin(mapped_test_col), std::end(mapped_test_col), std::begin(mapped_test_col),
            [&event_density](const real_type & x) -> real_type
            {
                return event_density[x];
            }
        );
        X_test[X_test.column(COLUMN)] = mapped_test_col;
    }

    vector_type y_train = i_y_train.apply([](real_type v){return v > 1.0 ? 1.0 : v;});

    vector_type theta(0.0, X_train.shape().second);

    // standardization
    for (num::size_type c{1}; c < X_train.shape().second; ++c)
    {
        const vector_type & col = X_train[X_train.column(c)];
        const vector_type & colt = X_test[X_test.column(c)];

        const real_type mu = num::mean<real_type>(col);
        const real_type dev = num::std<real_type>(col);

        X_train[X_train.column(c)] = col - mu;
        X_train[X_train.column(c)] = col / dev;

        X_test[X_test.column(c)] = colt - mu;
        X_test[X_test.column(c)] = colt / dev;
    }

    num::LogisticRegression<real_type> logRegClassifier(
        num::LogisticRegression<real_type>::array_type{X_train},
        num::LogisticRegression<real_type>::vector_type{y_train},
        num::LogisticRegression<real_type>::vector_type{theta},
        0.03,
        200
    );

    auto fit_theta = logRegClassifier.fit();

//    std::copy(std::begin(fit_theta), std::end(fit_theta), std::ostream_iterator<real_type>(std::cerr, "\n"));

    auto pred = logRegClassifier.predict(X_test, fit_theta, false);
//    std::copy(std::begin(pred), std::end(pred), std::ostream_iterator<real_type>(std::cerr, "\n"));
    std::cerr << "pred.max() " << pred.max() << std::endl;

    std::vector<int> result(i_X_test.shape().first);

    std::vector<std::pair<num::size_type, real_type>> zipped;
    zipped.reserve(pred.size());

    for (num::size_type idx = 0; idx < pred.size(); ++idx)
    {
        zipped.push_back(std::pair<num::size_type, real_type>(idx + 1, pred[idx]));
    }
    std::sort(zipped.begin(), zipped.end(),
        [](const std::pair<num::size_type, real_type> & p, const std::pair<num::size_type, real_type> & q)
        {
        return p.second > q.second;
        }
    );
    std::transform(zipped.cbegin(), zipped.cend(), result.begin(),
        [](const std::pair<num::size_type, real_type> & p)
        {
        return (int)p.first;
        }
    );

    return result;
}

struct TripSafetyFactors
{
    std::vector<int> predict(
        std::vector<std::string> i_train_data,
        std::vector<std::string> i_test_data) const;
};

std::vector<int>
TripSafetyFactors::predict(
    std::vector<std::string> i_train_data,
    std::vector<std::string> i_test_data) const
{
    enum col : num::size_type
    {
        ID,
        SOURCE,
        DIST,
        CYCLES,
        COMPLEXITY,
        CARGO,
        STOPS,
        START_DAY,
        START_MONTH,
        START_DAY_OF_MONTH,
        START_DAY_OF_WEEK,
        START_TIME,
        DAYS,
        PILOT,
        PILOT2,
        PILOT_EXP,
        PILOT_VISITS_PREV,
        PILOT_HOURS_PREV,
        PILOT_DUTY_HOURS_PREV,
        PILOT_DIST_PREV,
        ROUTE_RISK_1,
        ROUTE_RISK_2,
        WEATHER,
        VISIBILITY,
        TRAF0,
        TRAF1,
        TRAF2,
        TRAF3,
        TRAF4,
        /////////////
        ACCEL_CNT,
        DECEL_CNT,
        SPEED_CNT,
        STABILITY_CNT,
        EVT_CNT
    };

    typedef num::array2d<real_type> array_type;
    typedef std::valarray<real_type> vector_type;

    const num::size_type TRAIN_ROWS{i_train_data.size()};
    constexpr num::size_type TRAIN_COLS{34};

    const num::size_type TEST_ROWS{i_test_data.size()};
    constexpr num::size_type TEST_COLS{29};

    const num::shape_type TRAIN_SHAPE{TRAIN_ROWS, TRAIN_COLS};
    const num::shape_type TEST_SHAPE{TEST_ROWS, TEST_COLS};

    ////////////////////////////////////////////////////////////////////////////

    auto time_xlt = [](const char * str) -> real_type
    {
        char * next;
        long int result = std::strtol(str, &next, 10) * 60;
        if (*next == ':')
        {
            result += std::strtol(next + 1, nullptr, 10);
        }
        return result;
    };
    array_type train_data =
        num::loadtxt(
            std::move(i_train_data),
            std::move(
                num::loadtxtCfg<real_type>()
                .delimiter(',')
                .converters({{col::START_TIME, time_xlt}})
            )
        );
    std::cerr << train_data.shape() << std::endl;

    array_type test_data =
        num::loadtxt(
            std::move(i_test_data),
            std::move(
                num::loadtxtCfg<real_type>()
                .delimiter(',')
                .converters({{col::START_TIME, time_xlt}})
            )
        );
    std::cerr << test_data.shape() << std::endl;

    ////////////////////////////////////////////////////////////////////////////

    array_type X_train_data({train_data.shape().first, col::TRAF4 - col::SOURCE + 1}, 0.0);

    X_train_data[X_train_data.columns(0, -1)] = train_data[train_data.columns(col::SOURCE, col::TRAF4)];

    vector_type y_train_data = train_data[train_data.column(col::EVT_CNT)];

    array_type X_test_data({test_data.shape().first, test_data.shape().second - 1}, 0.0);

    X_test_data[X_test_data.columns(0, -1)] = test_data[test_data.columns(col::SOURCE, col::TRAF4)];

    ////////////////////////////////////////////////////////////////////////////

    std::vector<int> result(TEST_ROWS);

    result = do_log_reg(std::move(X_train_data), std::move(y_train_data), std::move(X_test_data));

    return result;
}

//#include <functional>
//#include "fmincg.hpp"
//#include <iterator>
//#include <fstream>
//void foo()
//{
//    typedef double real;
//    std::vector<std::string> Xtxt;
//    std::vector<std::string> ytxt;
//    {
//        std::ifstream fcsv("xxx.txt");
//
//        for (std::string line; std::getline(fcsv, line);)
//        {
//            Xtxt.push_back(line);
//        }
//        fcsv.close();
//    }
//    {
//        std::ifstream fcsv("xxy.txt");
//
//        for (std::string line; std::getline(fcsv, line);)
//        {
//            ytxt.push_back(line);
//        }
//        fcsv.close();
//    }
//    num::array2d<real> X =
//        num::loadtxt(
//            std::move(Xtxt),
//            std::move(
//                num::loadtxtCfg<real>()
//                .delimiter(',')
//            )
//        );
//    std::cerr << X.shape() << std::endl;
//    num::array2d<real> ym =
//        num::loadtxt(
//            std::move(ytxt),
//            std::move(
//                num::loadtxtCfg<real>()
//                .delimiter(',')
//            )
//        );
//    std::cerr << ym.shape() << std::endl;
//    std::valarray<real> y = ym[ym.column(0)];
//
//    std::valarray<real> theta(0.0, X.shape().second);
//
//    num::LogisticRegression<real> logRegClassifier(
//        num::LogisticRegression<real>::array_type{X},
//        num::LogisticRegression<real>::vector_type{y},
//        num::LogisticRegression<real>::vector_type{theta},
//        1.0,
//        400
//    );
//
//    auto fit_theta = logRegClassifier.fit();
//    std::copy(std::begin(fit_theta), std::end(fit_theta), std::ostream_iterator<real>(std::cerr, "\n"));
//
//    auto prediction = logRegClassifier.predict(X, fit_theta);
//    std::copy(std::begin(prediction), std::end(prediction), std::ostream_iterator<real>(std::cerr, "\n"));
//
//    return;
//}

#endif /* TRIPSAFETYFACTORS_HPP_ */
<|endoftext|>


<commit_before>#include "Sound.h"
#include <alure/alure.h>
#include <map>
#include "ResourceManager.h"
#include <assert.h>
#include "Engine/Logging.h"

namespace Sound
{

const int CHUNK_LENGTH = 16386;

typedef std::map<std::string, ALuint> BufferMap;
BufferMap sounds;

int soundSourceCount;
ALuint* soundSources;
ALuint musicSource;
ALuint musicBufs[2];
alureStream* currentMusicStream = NULL;
std::string currentMusicName = "";
int soundSourceIndex = 0;

void DieUnpleasantly()
{
	StopMusic();
	alureShutdownDevice();
}

ALubyte* GetSoundData(const std::string& path, size_t& length)
{
	SDL_RWops* rwops = ResourceManager::OpenFile(path + ".aiff");
	if (!rwops)
		rwops = ResourceManager::OpenFile(path + ".ogg");
	if (!rwops)
	{
		length = 0;
		return NULL;
	}
	return (ALubyte*)ResourceManager::ReadFull(&length, rwops, 1);
}

static ALuint GetSound(const std::string& name)
{
	BufferMap::iterator iter = sounds.find(name);
	if (iter != sounds.end())
		return iter->second;
	size_t length;
	ALubyte* data = GetSoundData("Sounds/" + name, length);
	ALuint buf = alureCreateBufferFromMemory(data, length);
	free(data);
	sounds.insert(std::make_pair(name, buf));
	return buf;
}

void Init(int frequency, int resolution, int sources)
{
	(void)resolution;
	--sources; // one spare source for music
	ALCint attribs[] = {
		ALC_FREQUENCY, frequency,
		ALC_MONO_SOURCES, sources,
		ALC_STEREO_SOURCES, 1,
		0
	};
	alureInitDevice(NULL, attribs);
	soundSources = new ALuint[sources];
	alGenSources(sources, soundSources);
	alGenSources(1, &musicSource);
	//alGenBuffers(2, musicBufs);
	soundSourceCount = sources;
	atexit(DieUnpleasantly);
}

static ALuint GetFreeSource()
{
	int idx = soundSourceIndex++;
	soundSourceIndex = soundSourceIndex % soundSourceCount;
	return soundSources[idx];
}

void Preload(const std::string& name)
{
	GetSound(name);
}

void PlaySound(const std::string& name, float gain)
{
	ALuint buf    = GetSound(name);
	ALuint source = GetFreeSource();
	alSourcei(source, AL_BUFFER, buf);
	alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
	alSourcef(source, AL_GAIN, gain);
	alSourcePlay(source);
}

void PlaySoundPositional(const std::string& name, vec2 pos, float gain)
{
	ALfloat fpos[] = {pos.X(), pos.Y(), 0.0f};
	ALuint buf    = GetSound(name);
	ALuint source = GetFreeSource();
	alSourcei(source, AL_BUFFER, buf);
	alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
	alSourcefv(source, AL_POSITION, fpos);
	alSourcef(source, AL_GAIN, gain);
	alSourcePlay(source);
}

static ALfloat forientation[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

void SetListener(vec2 pos, vec2 vel)
{
	ALfloat fpos[] = {pos.X(), pos.Y(), 0.0f};
	ALfloat fvel[] = {vel.X(), vel.Y(), 0.0f};
	alListenerfv(AL_POSITION, fpos);
	alListenerfv(AL_VELOCITY, fvel);
	if (vel.ModulusSquared() > 0.2f)
	{
		forientation[0] = fvel[0];
		forientation[1] = fvel[1];
	}
	alListenerfv(AL_ORIENTATION, forientation);
}

static void MusicEndCallback(void* ud, ALuint source)
{
	alureDestroyStream(currentMusicStream, 2, musicBufs);
	currentMusicStream = NULL;
	currentMusicName = "";
	free(ud);
}

void PlayMusic(const std::string& name)
{
	if (currentMusicStream)
		alureStopSource(musicSource, AL_TRUE);
	size_t length;
	ALubyte* data = GetSoundData("Music/" + name, length);
	currentMusicName = name;
	currentMusicStream = alureCreateStreamFromStaticMemory(data, length, CHUNK_LENGTH, 2, musicBufs);
	alurePlaySourceStream(musicSource, currentMusicStream, 2, 1, MusicEndCallback, data);
	LOG("Sound", LOG_MESSAGE, "Music: %s", name.c_str());
	if (!data)
		LOG("Sound", LOG_WARNING, "failed to find music");
}

void StopMusic()
{
	if (!currentMusicStream)
		return;
	alureStopSource(musicSource, AL_TRUE);
}

std::string MusicName()
{
	return "";
}

float MusicVolume()
{
	ALfloat rv;
	alGetSourcefv(musicSource, AL_GAIN, &rv);
	return rv;
}

void SetMusicVolume(float mvol)
{
	alSourcef(musicSource, AL_GAIN, mvol);
}

float SoundVolume()
{
	return 1.0f;
}

void SetSoundVolume(float mvol)
{
}

}
<commit_msg>Fixed positional sound.<commit_after>#include "Sound.h"
#include <alure/alure.h>
#include <map>
#include "ResourceManager.h"
#include <assert.h>
#include "Engine/Logging.h"

namespace Sound
{

const int CHUNK_LENGTH = 16386;

typedef std::map<std::string, ALuint> BufferMap;
BufferMap sounds;

int soundSourceCount;
ALuint* soundSources;
ALuint musicSource;
ALuint musicBufs[2];
alureStream* currentMusicStream = NULL;
std::string currentMusicName = "";
int soundSourceIndex = 0;

void DieUnpleasantly()
{
	StopMusic();
	alureShutdownDevice();
}

ALubyte* GetSoundData(const std::string& path, size_t& length)
{
	SDL_RWops* rwops = ResourceManager::OpenFile(path + ".aiff");
	if (!rwops)
		rwops = ResourceManager::OpenFile(path + ".ogg");
	if (!rwops)
	{
		length = 0;
		return NULL;
	}
	return (ALubyte*)ResourceManager::ReadFull(&length, rwops, 1);
}

static ALuint GetSound(const std::string& name)
{
	BufferMap::iterator iter = sounds.find(name);
	if (iter != sounds.end())
		return iter->second;
	size_t length;
	ALubyte* data = GetSoundData("Sounds/" + name, length);
	ALuint buf = alureCreateBufferFromMemory(data, length);
	free(data);
	sounds.insert(std::make_pair(name, buf));
	return buf;
}

void Init(int frequency, int resolution, int sources)
{
	(void)resolution;
	--sources; // one spare source for music
	ALCint attribs[] = {
		ALC_FREQUENCY, frequency,
		ALC_MONO_SOURCES, sources,
		ALC_STEREO_SOURCES, 1,
		0
	};
	alureInitDevice(NULL, attribs);
	soundSources = new ALuint[sources];
	alGenSources(sources, soundSources);
	alGenSources(1, &musicSource);
	//alGenBuffers(2, musicBufs);
	soundSourceCount = sources;
	atexit(DieUnpleasantly);
	alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
	alSpeedOfSound(1400.0);
	alDopplerFactor(0.7);
}

static ALuint GetFreeSource()
{
	int idx = soundSourceIndex++;
	soundSourceIndex = soundSourceIndex % soundSourceCount;
	return soundSources[idx];
}

void Preload(const std::string& name)
{
	GetSound(name);
}

void PlaySound(const std::string& name, float gain)
{
	ALuint buf    = GetSound(name);
	ALuint source = GetFreeSource();
	alSourcei(source, AL_BUFFER, buf);
	alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
	alSourcef(source, AL_GAIN, gain);
	alSourcePlay(source);
}

void PlaySoundPositional(const std::string& name, vec2 pos, float gain)
{
	ALfloat fpos[] = {pos.X(), pos.Y(), 0.0f};
	ALuint buf    = GetSound(name);
	ALuint source = GetFreeSource();
	alSourcei(source, AL_BUFFER, buf);
	alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
	alSourcefv(source, AL_POSITION, fpos);
	alSourcef(source, AL_REFERENCE_DISTANCE, 50.0);
	alSourcef(source, AL_GAIN, gain);
	alSourcePlay(source);
}

static ALfloat forientation[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

void SetListener(vec2 pos, vec2 vel)
{
	ALfloat fpos[] = {pos.X(), pos.Y(), 0.0f};
	ALfloat fvel[] = {vel.X(), vel.Y(), 0.0f};
	alListenerfv(AL_POSITION, fpos);
	alListenerfv(AL_VELOCITY, fvel);
	if (vel.ModulusSquared() > 0.2f)
	{
		forientation[0] = fvel[0];
		forientation[1] = fvel[1];
	}
	alListenerfv(AL_ORIENTATION, forientation);
}

static void MusicEndCallback(void* ud, ALuint source)
{
	alureDestroyStream(currentMusicStream, 2, musicBufs);
	currentMusicStream = NULL;
	currentMusicName = "";
	free(ud);
}

void PlayMusic(const std::string& name)
{
	if (currentMusicStream)
		alureStopSource(musicSource, AL_TRUE);
	size_t length;
	ALubyte* data = GetSoundData("Music/" + name, length);
	currentMusicName = name;
	currentMusicStream = alureCreateStreamFromStaticMemory(data, length, CHUNK_LENGTH, 2, musicBufs);
	alurePlaySourceStream(musicSource, currentMusicStream, 2, 1, MusicEndCallback, data);
	LOG("Sound", LOG_MESSAGE, "Music: %s", name.c_str());
	if (!data)
		LOG("Sound", LOG_WARNING, "failed to find music");
}

void StopMusic()
{
	if (!currentMusicStream)
		return;
	alureStopSource(musicSource, AL_TRUE);
}

std::string MusicName()
{
	return "";
}

float MusicVolume()
{
	ALfloat rv;
	alGetSourcefv(musicSource, AL_GAIN, &rv);
	return rv;
}

void SetMusicVolume(float mvol)
{
	alSourcef(musicSource, AL_GAIN, mvol);
}

float SoundVolume()
{
	return 1.0f;
}

void SetSoundVolume(float mvol)
{
}

}
<|endoftext|>


<commit_before><commit_msg>Interrupts: enable interrupt mask<commit_after><|endoftext|>


<commit_before>/*
 * ===============================================================
 *    Description:  Implementation of hyper_stub_base.
 *
 *        Created:  2014-02-26 15:28:58
 *
 *         Author:  Ayush Dubey, dubey@cs.cornell.edu
 *
 * Copyright (C) 2013-2014, Cornell University, see the LICENSE
 *                     file for licensing agreement
 * ===============================================================
 */

#include "common/hyper_stub_base.h"

// call hyperdex function h using key hndl, attributes cl_attr, and then loop for response
void
hyper_stub_base :: hyper_call_and_loop(hyper_func h, const char *space,
    uint64_t key, hyperdex_client_attribute *cl_attr, size_t num_attrs)
{
    hyperdex_client_returncode status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));
    int64_t hdex_id = (cl.*h)(space, (const char*)key_buf.get(), sizeof(int64_t), cl_attr, num_attrs, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex function failed, op id = " << hdex_id << ", status = " << status << std::endl;
        return;
    }
    hdex_id = cl.loop(-1, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
    }
}

// call hyperdex map function h using key hndl, attributes cl_attr, and then loop for response
void
hyper_stub_base :: hypermap_call_and_loop(hyper_map_func h, const char *space,
    uint64_t key, hyperdex_client_map_attribute *map_attr, size_t num_attrs)
{
    hyperdex_client_returncode status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));
    int64_t hdex_id = (cl.*h)(space, (const char*)key_buf.get(), sizeof(int64_t), map_attr, num_attrs, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex map function failed, op id = " << hdex_id << ", status = " << status << std::endl;
        return;
    }
    hdex_id = cl.loop(-1, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
    }
}

// multiple hyperdex calls
void
hyper_stub_base :: hyper_multiple_call_and_loop(std::vector<hyper_func> &funcs,
    std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<hyperdex_client_attribute*> &attrs,
    std::vector<size_t> &num_attrs)
{
    std::vector<const char*> map_spaces;
    std::vector<hyper_map_func> map_funcs;
    std::vector<uint64_t> map_keys;
    std::vector<hyperdex_client_map_attribute*> map_attrs;
    std::vector<size_t> map_num_attrs;
    hyper_multiple_call_and_loop(funcs, spaces, keys, attrs, num_attrs,
        map_funcs, map_spaces, map_keys, map_attrs, map_num_attrs);
}

void
hyper_stub_base :: hyper_multiple_call_and_loop(std::vector<hyper_func> &funcs,
    std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<hyperdex_client_attribute*> &attrs,
    std::vector<size_t> &num_attrs,
    std::vector<hyper_map_func> &map_funcs,
    std::vector<const char*> &map_spaces,
    std::vector<uint64_t> &map_keys,
    std::vector<hyperdex_client_map_attribute*> &map_attrs,
    std::vector<size_t> &map_num_attrs)
{
    uint64_t num_calls = funcs.size();
    assert(num_calls == spaces.size());
    assert(num_calls == keys.size());
    assert(num_calls == num_attrs.size());
    assert(num_calls == attrs.size());

    uint64_t map_num_calls = map_funcs.size();
    assert(map_num_calls == map_spaces.size());
    assert(map_num_calls == map_keys.size());
    assert(map_num_calls == map_num_attrs.size());
    assert(map_num_calls == map_attrs.size());

    hyperdex_client_returncode status;
    int hdex_id;

    uint64_t i = 0;
    for (; i < num_calls; i++) {
        hdex_id = (cl.*funcs[i])(spaces[i], (const char*)&keys[i], sizeof(int64_t), attrs[i], num_attrs[i], &status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex function failed, op id = " << hdex_id << ", status = " << status << std::endl;
            break;
        }
    }
    for (uint64_t j = 0; j < map_num_calls; j++, i++) {
        hdex_id = (cl.*map_funcs[j])(map_spaces[j], (const char*)&map_keys[j], sizeof(int64_t), map_attrs[j], map_num_attrs[j], &status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex map function failed, op id = " << hdex_id << ", status = " << status << std::endl;
            return;
        }
    }
    for (; i > 0; i--) {
        hdex_id = cl.loop(-1, &status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
        }
    }
}

void
hyper_stub_base :: hyper_get_and_loop(const char *space, uint64_t key,
    const hyperdex_client_attribute **cl_attr, size_t *num_attrs)
{
    hyperdex_client_returncode status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));
    int64_t hdex_id = cl.get(space, (const char*)key_buf.get(), sizeof(int64_t), &status, cl_attr, num_attrs);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << status << std::endl;
        return;
    }
    hdex_id = cl.loop(-1, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
    }
}

void
hyper_stub_base :: hyper_multiple_get_and_loop(std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<const hyperdex_client_attribute**> &cl_attrs,
    std::vector<size_t*> &num_attrs)
{
    uint64_t num_calls = spaces.size();
    assert(num_calls == keys.size());
    assert(num_calls == num_attrs.size());
    assert(num_calls == cl_attrs.size());

    hyperdex_client_returncode status;
    int64_t hdex_id;

    uint64_t i = 0;
    for (; i < num_calls; i++) {
        hdex_id = cl.get(spaces[i], (const char*)&keys[i], sizeof(int64_t), &status, cl_attrs[i], num_attrs[i]);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << status << std::endl;
            break;
        }
    }
    for (; i > 0; i--) {
        hdex_id = cl.loop(-1, &status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
            continue;
        }
    }
}

// delete the given key
void
hyper_stub_base :: hyper_del_and_loop(const char *space, uint64_t key)
{
    hyperdex_client_returncode status;
    int64_t hdex_id = cl.del(space, (const char*)&key, sizeof(int64_t), &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << status << std::endl;
        return;
    }
    hdex_id = cl.loop(-1, &status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << status << std::endl;
    }
}

// store the given unordered_map<int, int> as a HYPERDATATYPE_MAP_INT64_INT64
void
hyper_stub_base :: prepare_buffer(const std::unordered_map<uint64_t, uint64_t> &map, std::unique_ptr<char> &ret_buf, uint64_t &buf_sz)
{
    buf_sz = map.size() * (sizeof(int64_t) + sizeof(int64_t));
    char *buf = (char*)malloc(buf_sz);
    ret_buf.reset(buf);

    for (auto &p: map) {
        buf = e::pack64le(p.first, buf);
        buf = e::pack64le(p.second, buf);
    }
}

// unpack the HYPERDATATYPE_MAP_INT64_INT64 in to an unordered_map<int, int>
void
hyper_stub_base :: unpack_buffer(const char *buf, uint64_t buf_sz, std::unordered_map<uint64_t, uint64_t> &map)
{
    uint64_t num_entries = buf_sz / (sizeof(int64_t) + sizeof(int64_t));
    map.reserve(num_entries);
    uint64_t key, val;

    for (uint64_t i = 0; i < num_entries; i++) {
        buf = e::unpack64le(buf, &key);
        buf = e::unpack64le(buf, &val);
        map.emplace(key, val);
    }
}

// store the given unordered_set as a HYPERDATATYPE_SET_INT64
void
hyper_stub_base :: prepare_buffer(const std::unordered_set<uint64_t> &set, std::unique_ptr<char> &ret_buf, uint64_t &buf_sz)
{
    buf_sz = sizeof(uint64_t) * set.size();
    std::set<uint64_t> sorted;
    for (uint64_t x: set) {
        sorted.emplace(x);
    }

    char *buf = (char*)malloc(buf_sz);
    ret_buf.reset(buf);
    // now iterate in sorted order
    for (uint64_t x: sorted) {
        buf = e::pack64le(x, buf);
    }
}

// unpack the HYPERDATATYPE_SET_INT64 in to an unordered_set
void
hyper_stub_base :: unpack_buffer(const char *buf, uint64_t buf_sz, std::unordered_set<uint64_t> &set)
{
    uint64_t set_sz = buf_sz / sizeof(uint64_t);
    uint64_t next;
    set.reserve(set_sz);

    for (uint64_t i = 0; i < set_sz; i++) {
        buf = e::unpack64le(buf, &next);
        set.emplace(next);
    }
}
<commit_msg>returncode bug fix in hyper_stub<commit_after>/*
 * ===============================================================
 *    Description:  Implementation of hyper_stub_base.
 *
 *        Created:  2014-02-26 15:28:58
 *
 *         Author:  Ayush Dubey, dubey@cs.cornell.edu
 *
 * Copyright (C) 2013-2014, Cornell University, see the LICENSE
 *                     file for licensing agreement
 * ===============================================================
 */

#include "common/hyper_stub_base.h"

// call hyperdex function h using key hndl, attributes cl_attr, and then loop for response
void
hyper_stub_base :: hyper_call_and_loop(hyper_func h, const char *space,
    uint64_t key, hyperdex_client_attribute *cl_attr, size_t num_attrs)
{
    hyperdex_client_returncode call_status, loop_status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));

    int64_t hdex_id = (cl.*h)(space, (const char*)key_buf.get(), sizeof(int64_t), cl_attr, num_attrs, &call_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex function failed, op id = " << hdex_id << ", status = " << call_status << std::endl;
        return;
    }

    hdex_id = cl.loop(-1, &loop_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
    }

    if (loop_status != HYPERDEX_CLIENT_SUCCESS || call_status != HYPERDEX_CLIENT_SUCCESS) {
        WDEBUG << "hyperdex error"
               << ", call status: " << call_status
               << ", loop status: " << loop_status << std::endl;
        WDEBUG << "error message: " << cl.error_message() << std::endl;
        WDEBUG << "error loc: " << cl.error_location() << std::endl;
    }
}

// call hyperdex map function h using key hndl, attributes cl_attr, and then loop for response
void
hyper_stub_base :: hypermap_call_and_loop(hyper_map_func h, const char *space,
    uint64_t key, hyperdex_client_map_attribute *map_attr, size_t num_attrs)
{
    hyperdex_client_returncode call_status, loop_status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));

    int64_t hdex_id = (cl.*h)(space, (const char*)key_buf.get(), sizeof(int64_t), map_attr, num_attrs, &call_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex map function failed, op id = " << hdex_id << ", status = " << call_status << std::endl;
        return;
    }

    hdex_id = cl.loop(-1, &loop_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
    }

    if (loop_status != HYPERDEX_CLIENT_SUCCESS || call_status != HYPERDEX_CLIENT_SUCCESS) {
        WDEBUG << "hyperdex error"
               << ", call status: " << call_status
               << ", loop status: " << loop_status << std::endl;
        WDEBUG << "error message: " << cl.error_message() << std::endl;
        WDEBUG << "error loc: " << cl.error_location() << std::endl;
    }
}

// multiple hyperdex calls
void
hyper_stub_base :: hyper_multiple_call_and_loop(std::vector<hyper_func> &funcs,
    std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<hyperdex_client_attribute*> &attrs,
    std::vector<size_t> &num_attrs)
{
    std::vector<const char*> map_spaces;
    std::vector<hyper_map_func> map_funcs;
    std::vector<uint64_t> map_keys;
    std::vector<hyperdex_client_map_attribute*> map_attrs;
    std::vector<size_t> map_num_attrs;
    hyper_multiple_call_and_loop(funcs, spaces, keys, attrs, num_attrs,
        map_funcs, map_spaces, map_keys, map_attrs, map_num_attrs);
}

void
hyper_stub_base :: hyper_multiple_call_and_loop(std::vector<hyper_func> &funcs,
    std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<hyperdex_client_attribute*> &attrs,
    std::vector<size_t> &num_attrs,
    std::vector<hyper_map_func> &map_funcs,
    std::vector<const char*> &map_spaces,
    std::vector<uint64_t> &map_keys,
    std::vector<hyperdex_client_map_attribute*> &map_attrs,
    std::vector<size_t> &map_num_attrs)
{
    uint64_t num_calls = funcs.size();
    assert(num_calls == spaces.size());
    assert(num_calls == keys.size());
    assert(num_calls == num_attrs.size());
    assert(num_calls == attrs.size());

    uint64_t map_num_calls = map_funcs.size();
    assert(map_num_calls == map_spaces.size());
    assert(map_num_calls == map_keys.size());
    assert(map_num_calls == map_num_attrs.size());
    assert(map_num_calls == map_attrs.size());

    hyperdex_client_returncode call_status[num_calls+map_num_calls];
    int hdex_id;

    uint64_t i = 0;
    for (; i < num_calls; i++) {
        hdex_id = (cl.*funcs[i])(spaces[i], (const char*)&keys[i], sizeof(int64_t), attrs[i], num_attrs[i], call_status+i);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex function failed, op id = " << hdex_id << ", status = " << call_status[i] << std::endl;
            break;
        }
    }

    for (uint64_t j = 0; j < map_num_calls; j++, i++) {
        hdex_id = (cl.*map_funcs[j])(map_spaces[j], (const char*)&map_keys[j], sizeof(int64_t), map_attrs[j], map_num_attrs[j], call_status+i);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex map function failed, op id = " << hdex_id << ", status = " << call_status[i] << std::endl;
            return;
        }
    }

    hyperdex_client_returncode loop_status;
    for (; i > 0; i--) {
        hdex_id = cl.loop(-1, &loop_status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
        }

        if (loop_status != HYPERDEX_CLIENT_SUCCESS || call_status[i] != HYPERDEX_CLIENT_SUCCESS) {
            WDEBUG << "hyperdex error at call " << i
                   << ", call status: " << call_status
                   << ", loop status: " << loop_status << std::endl;
            WDEBUG << "error message: " << cl.error_message() << std::endl;
            WDEBUG << "error loc: " << cl.error_location() << std::endl;
        }
    }
}

void
hyper_stub_base :: hyper_get_and_loop(const char *space, uint64_t key,
    const hyperdex_client_attribute **cl_attr, size_t *num_attrs)
{
    hyperdex_client_returncode get_status, loop_status;
    std::unique_ptr<int64_t> key_buf(new int64_t(key));

    int64_t hdex_id = cl.get(space, (const char*)key_buf.get(), sizeof(int64_t), &get_status, cl_attr, num_attrs);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << get_status << std::endl;
        return;
    }

    hdex_id = cl.loop(-1, &loop_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
    }

    if (loop_status != HYPERDEX_CLIENT_SUCCESS || get_status != HYPERDEX_CLIENT_SUCCESS) {
        WDEBUG << "hyperdex error"
               << ", call status: " << get_status
               << ", loop status: " << loop_status << std::endl;
        WDEBUG << "error message: " << cl.error_message() << std::endl;
        WDEBUG << "error loc: " << cl.error_location() << std::endl;
    }
}

void
hyper_stub_base :: hyper_multiple_get_and_loop(std::vector<const char*> &spaces,
    std::vector<uint64_t> &keys,
    std::vector<const hyperdex_client_attribute**> &cl_attrs,
    std::vector<size_t*> &num_attrs)
{
    uint64_t num_calls = spaces.size();
    assert(num_calls == keys.size());
    assert(num_calls == num_attrs.size());
    assert(num_calls == cl_attrs.size());

    hyperdex_client_returncode get_status[num_calls];
    int64_t hdex_id;

    uint64_t i = 0;
    for (; i < num_calls; i++) {
        hdex_id = cl.get(spaces[i], (const char*)&keys[i], sizeof(int64_t), get_status+i, cl_attrs[i], num_attrs[i]);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << get_status[i] << std::endl;
            break;
        }
    }

    hyperdex_client_returncode loop_status;
    for (; i > 0; i--) {
        hdex_id = cl.loop(-1, &loop_status);
        if (hdex_id < 0) {
            WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
            continue;
        }

        if (loop_status != HYPERDEX_CLIENT_SUCCESS || get_status[i] != HYPERDEX_CLIENT_SUCCESS) {
            WDEBUG << "hyperdex error"
                   << ", call status: " << get_status[i]
                   << ", loop status: " << loop_status << std::endl;
            WDEBUG << "error message: " << cl.error_message() << std::endl;
            WDEBUG << "error loc: " << cl.error_location() << std::endl;
        }
    }
}

// delete the given key
void
hyper_stub_base :: hyper_del_and_loop(const char *space, uint64_t key)
{
    hyperdex_client_returncode del_status, loop_status;
    int64_t hdex_id = cl.del(space, (const char*)&key, sizeof(int64_t), &del_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex get failed, op id = " << hdex_id << ", status = " << del_status << std::endl;
        return;
    }

    hdex_id = cl.loop(-1, &loop_status);
    if (hdex_id < 0) {
        WDEBUG << "Hyperdex loop failed, op id = " << hdex_id << ", status = " << loop_status << std::endl;
    }

    if (loop_status != HYPERDEX_CLIENT_SUCCESS || del_status != HYPERDEX_CLIENT_SUCCESS) {
        WDEBUG << "hyperdex error"
               << ", call status: " << del_status
               << ", loop status: " << loop_status << std::endl;
        WDEBUG << "error message: " << cl.error_message() << std::endl;
        WDEBUG << "error loc: " << cl.error_location() << std::endl;
    }
}

// store the given unordered_map<int, int> as a HYPERDATATYPE_MAP_INT64_INT64
void
hyper_stub_base :: prepare_buffer(const std::unordered_map<uint64_t, uint64_t> &map, std::unique_ptr<char> &ret_buf, uint64_t &buf_sz)
{
    buf_sz = map.size() * (sizeof(int64_t) + sizeof(int64_t));
    char *buf = (char*)malloc(buf_sz);
    ret_buf.reset(buf);

    for (auto &p: map) {
        buf = e::pack64le(p.first, buf);
        buf = e::pack64le(p.second, buf);
    }
}

// unpack the HYPERDATATYPE_MAP_INT64_INT64 in to an unordered_map<int, int>
void
hyper_stub_base :: unpack_buffer(const char *buf, uint64_t buf_sz, std::unordered_map<uint64_t, uint64_t> &map)
{
    uint64_t num_entries = buf_sz / (sizeof(int64_t) + sizeof(int64_t));
    map.reserve(num_entries);
    uint64_t key, val;

    for (uint64_t i = 0; i < num_entries; i++) {
        buf = e::unpack64le(buf, &key);
        buf = e::unpack64le(buf, &val);
        map.emplace(key, val);
    }
}

// store the given unordered_set as a HYPERDATATYPE_SET_INT64
void
hyper_stub_base :: prepare_buffer(const std::unordered_set<uint64_t> &set, std::unique_ptr<char> &ret_buf, uint64_t &buf_sz)
{
    buf_sz = sizeof(uint64_t) * set.size();
    std::set<uint64_t> sorted;
    for (uint64_t x: set) {
        sorted.emplace(x);
    }

    char *buf = (char*)malloc(buf_sz);
    ret_buf.reset(buf);
    // now iterate in sorted order
    for (uint64_t x: sorted) {
        buf = e::pack64le(x, buf);
    }
}

// unpack the HYPERDATATYPE_SET_INT64 in to an unordered_set
void
hyper_stub_base :: unpack_buffer(const char *buf, uint64_t buf_sz, std::unordered_set<uint64_t> &set)
{
    uint64_t set_sz = buf_sz / sizeof(uint64_t);
    uint64_t next;
    set.reserve(set_sz);

    for (uint64_t i = 0; i < set_sz; i++) {
        buf = e::unpack64le(buf, &next);
        set.emplace(next);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Hottinger Baldwin Messtechnik
// Distributed under MIT license
// See file LICENSE provided

#include <cstring>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>

#include <unistd.h>

#include <errno.h>
#include <syslog.h>
#include <poll.h>

#include "hbm/communication/socketnonblocking.h"

/// Maximum time to wait for connecting
const time_t TIMEOUT_CONNECT_S = 5;

hbm::communication::SocketNonblocking::SocketNonblocking(sys::EventLoop &eventLoop)
	: m_fd(-1)
	, m_bufferedReader()
	, m_eventLoop(eventLoop)
	, m_dataHandler()
{
}

hbm::communication::SocketNonblocking::SocketNonblocking(int fd, sys::EventLoop &eventLoop, DataCb_t dataHandler)
	: m_fd(fd)
	, m_bufferedReader()
	, m_eventLoop(eventLoop)
	, m_dataHandler(dataHandler)
{
	if (setSocketOptions()<0) {
		throw std::runtime_error("error setting socket options");
	}

	m_eventLoop.addEvent(m_fd, std::bind(&SocketNonblocking::process, this));
}

hbm::communication::SocketNonblocking::~SocketNonblocking()
{
	disconnect();
}

int hbm::communication::SocketNonblocking::setSocketOptions()
{
	int opt = 1;

	// turn off Nagle algorithm
	if (setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error turning off nagle algorithm");
		return -1;
	}

	opt = 12;
	// the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe;
	// after the connection is marked to need keepalive, this counter is not used any further
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPIDLE, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPIDLE");
		return -1;
}

	opt = 3;
	// the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPINTVL, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPINTVL");
		return -1;
	}

	opt = 2;
	// the number of unacknowledged probes to send before considering the connection dead and notifying the application layer
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPCNT, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPCNT");
		return -1;
	}

	opt = 1;
	if (setsockopt(m_fd, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option SO_KEEPALIVE");
		return -1;
	}

	return 0;
}

int hbm::communication::SocketNonblocking::connect(const std::string &address, const std::string& port, DataCb_t dataHandler)
{
	struct addrinfo hints;
	struct addrinfo* pResult = NULL;

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

	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 6; // Ip V6!

	if( getaddrinfo(address.c_str(), port.c_str(), &hints, &pResult)!=0 ) {
		return -1;
	}
	int retVal = connect(pResult->ai_family, pResult->ai_addr, pResult->ai_addrlen, dataHandler);

	freeaddrinfo( pResult );

	return retVal;
}

int hbm::communication::SocketNonblocking::connect(int domain, const struct sockaddr* pSockAddr, socklen_t len, DataCb_t dataHandler)
{
	m_fd = ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
	if (m_fd==-1) {
		return -1;
	}

	if (setSocketOptions()<0) {
		return -1;
	}

	int err = ::connect(m_fd, pSockAddr, len);
	if (err==0) {
		return 0;
	}

	// success if errno equals EINPROGRESS
	if(errno != EINPROGRESS) {
		syslog(LOG_ERR, "failed to connect errno=%d '%s'", errno, strerror(errno));
		return -1;
	}
	struct pollfd pfd;
	pfd.fd = m_fd;
	pfd.events = POLLOUT;
	do {
		err = poll(&pfd, 1, TIMEOUT_CONNECT_S*1000);
	} while((err==-1) && (errno==EINTR) );
	if(err!=1) {
		return -1;
	}

	int value;
	len = sizeof(value);
	getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &value, &len);
	if(value!=0) {
		return -1;
	}

	m_dataHandler = dataHandler;
	m_eventLoop.addEvent(m_fd, std::bind(&SocketNonblocking::process, this));

	return 0;
}

int hbm::communication::SocketNonblocking::process()
{
	if (m_dataHandler) {
		return m_dataHandler(this);
	} else {
		return -1;
	}
}

ssize_t hbm::communication::SocketNonblocking::receive(void* pBlock, size_t size)
{
	return m_bufferedReader.recv(m_fd, pBlock, size, 0);
}

ssize_t hbm::communication::SocketNonblocking::receiveComplete(void* pBlock, size_t size, int msTimeout)
{
	ssize_t retVal;
	unsigned char* pPos = reinterpret_cast < unsigned char* > (pBlock);
	size_t sizeLeft = size;
	while(sizeLeft) {
		retVal = m_bufferedReader.recv(m_fd, pPos, sizeLeft, 0);
		if(retVal>0) {
			sizeLeft -= retVal;
			pPos += retVal;
		} else if(retVal==0) {
			return size-sizeLeft;
		} else {
			if(errno==EWOULDBLOCK || errno==EAGAIN) {
				// wait for socket to become readable.
				struct pollfd pfd;
				pfd.fd = m_fd;
				pfd.events = POLLIN;
				int nfds;
				do {
					nfds = poll(&pfd, 1, msTimeout);
				} while((nfds==-1) && (errno==EINTR));
				if(nfds!=1) {
					return -1;
				}
			} else {
				syslog(LOG_ERR, "%s: recv failed '%s'", __FUNCTION__, strerror(errno));
				return -1;
			}
		}
	}
	return size;
}

ssize_t hbm::communication::SocketNonblocking::sendBlock(const void* pBlock, size_t size, bool more)
{
	const uint8_t* pDat = reinterpret_cast<const uint8_t*>(pBlock);
	size_t BytesLeft = size;
	ssize_t numBytes;
	ssize_t retVal = size;

	struct pollfd pfd;
	pfd.fd = m_fd;
	pfd.events = POLLOUT;

	int flags = 0;
	if(more) {
		flags |= MSG_MORE;
	}
	int err;

	while (BytesLeft > 0) {
		numBytes = send(m_fd, pDat, BytesLeft, flags);
		if(numBytes>0) {
			pDat += numBytes;
			BytesLeft -= numBytes;
		} else if(numBytes==0) {
			// connection lost...
			BytesLeft = 0;
			retVal = -1;
		} else {
			// <0
			if(errno==EWOULDBLOCK || errno==EAGAIN) {
				// wait for socket to become writable.
				do {
					err = poll(&pfd, 1, -1);
				} while((err==-1) && (errno==EINTR));
				if(err!=1) {
					BytesLeft = 0;
					retVal = -1;
				}
			} else {
				// a real error happened!
				BytesLeft = 0;
				retVal = -1;
			}
		}
	}
	return retVal;
}

bool hbm::communication::SocketNonblocking::checkSockAddr(const struct ::sockaddr* pCheckSockAddr, socklen_t checkSockAddrLen) const
{
	struct sockaddr sockAddr;
	socklen_t addrLen = sizeof(sockaddr_in);

	char checkHost[256] = "";
	char ckeckService[8] = "";

	char host[256] = "";
	char service[8] = "";
	int err = getnameinfo(pCheckSockAddr, checkSockAddrLen, checkHost, sizeof(checkHost), ckeckService, sizeof(ckeckService), NI_NUMERICHOST | NI_NUMERICSERV);
	if (err != 0) {
		syslog(LOG_ERR, "%s: error from getnameinfo", __FUNCTION__);
		return false;
	}

	if (getpeername(m_fd, &sockAddr, &addrLen)!=0) {
		return false;
	}

	if (getnameinfo(&sockAddr, addrLen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV)!=0) {
		return false;
	}

	if(
		 (strcmp(host, checkHost)==0) &&
		 (strcmp(service, ckeckService)==0)
		 )
	{
		return true;
	}
	return false;
}

void hbm::communication::SocketNonblocking::disconnect()
{
	m_eventLoop.eraseEvent(m_fd);
	shutdown(m_fd, SHUT_RDWR);
	::close(m_fd);
	m_fd = -1;
}

bool hbm::communication::SocketNonblocking::isFirewire() const
{
	bool retVal = false;

	struct ifreq ifr;
	memset(&ifr, 0, sizeof(struct ifreq));

	if ((::ioctl(m_fd, SIOCGIFHWADDR, (caddr_t)&ifr, sizeof(struct ifreq))) >= 0) {
		if (ifr.ifr_hwaddr.sa_family == ARPHRD_IEEE1394) {
			retVal = true;
		}
	}
	return retVal;
}
<commit_msg>fix: add event in all cases of success<commit_after>// Copyright 2014 Hottinger Baldwin Messtechnik
// Distributed under MIT license
// See file LICENSE provided

#include <cstring>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>

#include <unistd.h>

#include <errno.h>
#include <syslog.h>
#include <poll.h>

#include "hbm/communication/socketnonblocking.h"

/// Maximum time to wait for connecting
const time_t TIMEOUT_CONNECT_S = 5;

hbm::communication::SocketNonblocking::SocketNonblocking(sys::EventLoop &eventLoop)
	: m_fd(-1)
	, m_bufferedReader()
	, m_eventLoop(eventLoop)
	, m_dataHandler()
{
}

hbm::communication::SocketNonblocking::SocketNonblocking(int fd, sys::EventLoop &eventLoop, DataCb_t dataHandler)
	: m_fd(fd)
	, m_bufferedReader()
	, m_eventLoop(eventLoop)
	, m_dataHandler(dataHandler)
{
	if (setSocketOptions()<0) {
		throw std::runtime_error("error setting socket options");
	}

	m_eventLoop.addEvent(m_fd, std::bind(&SocketNonblocking::process, this));
}

hbm::communication::SocketNonblocking::~SocketNonblocking()
{
	disconnect();
}

int hbm::communication::SocketNonblocking::setSocketOptions()
{
	int opt = 1;

	// turn off Nagle algorithm
	if (setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error turning off nagle algorithm");
		return -1;
	}

	opt = 12;
	// the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe;
	// after the connection is marked to need keepalive, this counter is not used any further
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPIDLE, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPIDLE");
		return -1;
}

	opt = 3;
	// the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPINTVL, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPINTVL");
		return -1;
	}

	opt = 2;
	// the number of unacknowledged probes to send before considering the connection dead and notifying the application layer
	if (setsockopt(m_fd, SOL_TCP, TCP_KEEPCNT, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option TCP_KEEPCNT");
		return -1;
	}

	opt = 1;
	if (setsockopt(m_fd, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<char*>(&opt), sizeof(opt))==-1) {
		syslog(LOG_ERR, "error setting socket option SO_KEEPALIVE");
		return -1;
	}

	return 0;
}

int hbm::communication::SocketNonblocking::connect(const std::string &address, const std::string& port, DataCb_t dataHandler)
{
	struct addrinfo hints;
	struct addrinfo* pResult = NULL;

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

	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 6; // Ip V6!

	if( getaddrinfo(address.c_str(), port.c_str(), &hints, &pResult)!=0 ) {
		return -1;
	}
	int retVal = connect(pResult->ai_family, pResult->ai_addr, pResult->ai_addrlen, dataHandler);

	freeaddrinfo( pResult );

	return retVal;
}

int hbm::communication::SocketNonblocking::connect(int domain, const struct sockaddr* pSockAddr, socklen_t len, DataCb_t dataHandler)
{
	m_fd = ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
	if (m_fd==-1) {
		return -1;
	}

	if (setSocketOptions()<0) {
		return -1;
	}

	int err = ::connect(m_fd, pSockAddr, len);
	if (err==-1) {
		// success if errno equals EINPROGRESS
		if(errno != EINPROGRESS) {
			syslog(LOG_ERR, "failed to connect errno=%d '%s'", errno, strerror(errno));
			return -1;
		}
		struct pollfd pfd;
		pfd.fd = m_fd;
		pfd.events = POLLOUT;
		do {
			err = poll(&pfd, 1, TIMEOUT_CONNECT_S*1000);
		} while((err==-1) && (errno==EINTR) );
		if(err!=1) {
			return -1;
		}

		int value;
		len = sizeof(value);
		getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &value, &len);
		if(value!=0) {
			return -1;
		}
	}

	m_dataHandler = dataHandler;
	m_eventLoop.addEvent(m_fd, std::bind(&SocketNonblocking::process, this));

	return 0;
}

int hbm::communication::SocketNonblocking::process()
{
	if (m_dataHandler) {
		return m_dataHandler(this);
	} else {
		return -1;
	}
}

ssize_t hbm::communication::SocketNonblocking::receive(void* pBlock, size_t size)
{
	return m_bufferedReader.recv(m_fd, pBlock, size, 0);
}

ssize_t hbm::communication::SocketNonblocking::receiveComplete(void* pBlock, size_t size, int msTimeout)
{
	ssize_t retVal;
	unsigned char* pPos = reinterpret_cast < unsigned char* > (pBlock);
	size_t sizeLeft = size;
	while(sizeLeft) {
		retVal = m_bufferedReader.recv(m_fd, pPos, sizeLeft, 0);
		if(retVal>0) {
			sizeLeft -= retVal;
			pPos += retVal;
		} else if(retVal==0) {
			return size-sizeLeft;
		} else {
			if(errno==EWOULDBLOCK || errno==EAGAIN) {
				// wait for socket to become readable.
				struct pollfd pfd;
				pfd.fd = m_fd;
				pfd.events = POLLIN;
				int nfds;
				do {
					nfds = poll(&pfd, 1, msTimeout);
				} while((nfds==-1) && (errno==EINTR));
				if(nfds!=1) {
					return -1;
				}
			} else {
				syslog(LOG_ERR, "%s: recv failed '%s'", __FUNCTION__, strerror(errno));
				return -1;
			}
		}
	}
	return size;
}

ssize_t hbm::communication::SocketNonblocking::sendBlock(const void* pBlock, size_t size, bool more)
{
	const uint8_t* pDat = reinterpret_cast<const uint8_t*>(pBlock);
	size_t BytesLeft = size;
	ssize_t numBytes;
	ssize_t retVal = size;

	struct pollfd pfd;
	pfd.fd = m_fd;
	pfd.events = POLLOUT;

	int flags = 0;
	if(more) {
		flags |= MSG_MORE;
	}
	int err;

	while (BytesLeft > 0) {
		numBytes = send(m_fd, pDat, BytesLeft, flags);
		if(numBytes>0) {
			pDat += numBytes;
			BytesLeft -= numBytes;
		} else if(numBytes==0) {
			// connection lost...
			BytesLeft = 0;
			retVal = -1;
		} else {
			// <0
			if(errno==EWOULDBLOCK || errno==EAGAIN) {
				// wait for socket to become writable.
				do {
					err = poll(&pfd, 1, -1);
				} while((err==-1) && (errno==EINTR));
				if(err!=1) {
					BytesLeft = 0;
					retVal = -1;
				}
			} else {
				// a real error happened!
				BytesLeft = 0;
				retVal = -1;
			}
		}
	}
	return retVal;
}

bool hbm::communication::SocketNonblocking::checkSockAddr(const struct ::sockaddr* pCheckSockAddr, socklen_t checkSockAddrLen) const
{
	struct sockaddr sockAddr;
	socklen_t addrLen = sizeof(sockaddr_in);

	char checkHost[256] = "";
	char ckeckService[8] = "";

	char host[256] = "";
	char service[8] = "";
	int err = getnameinfo(pCheckSockAddr, checkSockAddrLen, checkHost, sizeof(checkHost), ckeckService, sizeof(ckeckService), NI_NUMERICHOST | NI_NUMERICSERV);
	if (err != 0) {
		syslog(LOG_ERR, "%s: error from getnameinfo", __FUNCTION__);
		return false;
	}

	if (getpeername(m_fd, &sockAddr, &addrLen)!=0) {
		return false;
	}

	if (getnameinfo(&sockAddr, addrLen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV)!=0) {
		return false;
	}

	if(
		 (strcmp(host, checkHost)==0) &&
		 (strcmp(service, ckeckService)==0)
		 )
	{
		return true;
	}
	return false;
}

void hbm::communication::SocketNonblocking::disconnect()
{
	m_eventLoop.eraseEvent(m_fd);
	shutdown(m_fd, SHUT_RDWR);
	::close(m_fd);
	m_fd = -1;
}

bool hbm::communication::SocketNonblocking::isFirewire() const
{
	bool retVal = false;

	struct ifreq ifr;
	memset(&ifr, 0, sizeof(struct ifreq));

	if ((::ioctl(m_fd, SIOCGIFHWADDR, (caddr_t)&ifr, sizeof(struct ifreq))) >= 0) {
		if (ifr.ifr_hwaddr.sa_family == ARPHRD_IEEE1394) {
			retVal = true;
		}
	}
	return retVal;
}
<|endoftext|>


<commit_before>/*******************************************************************************
*    ALMA - Atacama Large Millimiter Array
*    (c) European Southern Observatory, 2002
*    Copyright by ESO (in the framework of the ALMA collaboration),
*    All rights reserved
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation; either
*    version 2.1 of the License, or (at your option) any later version.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public
*    License along with this library; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: baciCORBA.cpp,v 1.96 2005/08/23 15:35:26 vwang Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* gchiozzi 2001-12-20 Added getPOAManager() and getPOARoot() methods.
* msekoran  2001/02/17  created
* msekoran  2001/05/21  fixed destroy bug
* msekoran  2001/08/26  added InitCORBA, DoneCORBA for BACI modular tests
*/

#include <vltPort.h>
#include "logging.h"
#include "baciCORBA.h"

BACI_CORBA * BACI_CORBA::instance_mp = 0;

BACI_CORBA::BACI_CORBA(CORBA::ORB_ptr orb_m,
		       PortableServer::POAManager_ptr poaManager_m,
		       PortableServer::POA_ptr poaRoot_m,
		       PortableServer::POA_ptr poaPersistent_m,
		       PortableServer::POA_ptr poaTransient_m)
{
  this->orb_m = CORBA::ORB::_duplicate(orb_m);
  this->poaManager_m = PortableServer::POAManager::_duplicate(poaManager_m);
  this->poaRoot_m = PortableServer::POA::_duplicate(poaRoot_m);
  this->poaPersistent_m = PortableServer::POA::_duplicate(poaPersistent_m);
  this->poaTransient_m = PortableServer::POA::_duplicate(poaTransient_m);
}

BACI_CORBA::~BACI_CORBA()
{
}

BACI_CORBA *
BACI_CORBA::getInstance()
{
  return instance_mp;
}

BACI_CORBA *
BACI_CORBA::createInstance(CORBA::ORB_ptr orb_m,
			   PortableServer::POAManager_ptr poaManager_m,
			   PortableServer::POA_ptr poaRoot_m,
			   PortableServer::POA_ptr poaPersistent_m,
			   PortableServer::POA_ptr poaTransient_m)
{
  if (instance_mp==0)
      {
      instance_mp = new BACI_CORBA(orb_m, poaManager_m, poaRoot_m, poaPersistent_m, poaTransient_m);
      }
  return instance_mp;
}

void
BACI_CORBA::destroyInstance()
{
  if (instance_mp!=0)
    {
      delete instance_mp;
      instance_mp = 0;
    }
}

CORBA::ORB_ptr
BACI_CORBA::getORB()
{
    if (instance_mp!=0)
	{
	return instance_mp->orb_m.ptr();
	}
    else
	{
	return CORBA::ORB::_nil();
	}
}

PortableServer::POAManager_ptr
BACI_CORBA::getPOAManager()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaManager_m.ptr();
	}
    else
	{
	return PortableServer::POAManager::_nil();
	}
}

PortableServer::POA_ptr
BACI_CORBA::getPOARoot()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaRoot_m.ptr();
	}
    else
	{
	return PortableServer::POA::_nil();
	}
}

PortableServer::POA_ptr
BACI_CORBA::getPOA()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaPersistent_m.ptr();
	}
    else
	{
	return PortableServer::POA::_nil();
	}
}

CORBA::Object_ptr
BACI_CORBA::ActivateCORBAObject(PortableServer::Servant srvnt, const char * name)
{

  if (instance_mp==0 ||
      instance_mp->poaPersistent_m.ptr() == PortableServer::POA::_nil())
      {
      return CORBA::Object::_nil();
      }

  try
    {
      PortableServer::ObjectId_var id =
	PortableServer::string_to_ObjectId(name);
      instance_mp->poaPersistent_m->activate_object_with_id(id.in(), srvnt);
      CORBA::Object_var obj = instance_mp->poaPersistent_m->servant_to_reference(srvnt);
      return obj._retn();
    }
  catch(...)
    {
    ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::ActivateCORBAObject",
	    (LM_ERROR, "Failed to activate CORBA object"));
    }

  return CORBA::Object::_nil();
}

bool
BACI_CORBA::DestroyCORBAObject(CORBA::Object_ptr obj)
{

  if (instance_mp==0 ||
      instance_mp->poaPersistent_m.ptr() == PortableServer::POA::_nil())
      {
      return false;
      }

  try
    {
      PortableServer::ObjectId_var id =
	instance_mp->poaPersistent_m->reference_to_id(obj);
      instance_mp->poaPersistent_m->deactivate_object(id.in());
      return true;
    }
  catch(...)
    {
      ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyCORBAObject",
	      (LM_ERROR, "Failed to deactivate CORBA object"));
    }

  return false;
}

bool
BACI_CORBA::DestroyCORBAObject(PortableServer::Servant srvnt)
{
    if (instance_mp==0 ||
	instance_mp->poaPersistent_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaPersistent_m->servant_to_id(srvnt);
	instance_mp->poaPersistent_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyCORBAObject (servant)",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}

    return false;
}

bool
BACI_CORBA::DestroyTransientCORBAObject(CORBA::Object_ptr obj)
{
    if (instance_mp==0 ||
	instance_mp->poaTransient_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaTransient_m->reference_to_id(obj);
	instance_mp->poaTransient_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyTransientCORBAObject",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}
  return false;
}

bool
BACI_CORBA::DestroyTransientCORBAObject(PortableServer::Servant srvnt)
{
    if (instance_mp==0 ||
	instance_mp->poaTransient_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaTransient_m->servant_to_id(srvnt);

	instance_mp->poaTransient_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyTransientCORBAObject (servant)",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}

    return false;
}

bool BACI_CORBA::InitCORBA(int argc, char* argv[])
{
  try
      {
      // Initialize the ORB.
      CORBA::ORB_var orb_m = CORBA::ORB_init(argc, argv, "TAO");

      if(orb_m.ptr() == CORBA::ORB::_nil())
	{
	return false;
	}

      //
      // Initialize POAs.
      //

      // Get the Root POA.
      CORBA::Object_var objRootPOA =
	  orb_m->resolve_initial_references("RootPOA");

      PortableServer::POA_var poaRoot_m = PortableServer::POA::_narrow(objRootPOA.in());

      if(poaRoot_m.ptr() == PortableServer::POA::_nil())
	  {
	  return false;
	  }

      // Get the manager of the root POA to apply to the child POAs.
      PortableServer::POAManager_var poaManager =
	  poaRoot_m->the_POAManager();

      //
      // Prepare policies our POAs will be using.
      //

      // @@ Unavoidable memory leak here if the POA has been improperly set
      //    up, eg. by a -ORBEndpoint command-line option that does not
      //    correspond to the local host.
      PortableServer::IdAssignmentPolicy_var userIdPolicy =
	  poaRoot_m->create_id_assignment_policy(PortableServer::USER_ID);
      PortableServer::LifespanPolicy_var persistentPolicy =
	  poaRoot_m->create_lifespan_policy(PortableServer::PERSISTENT);

      CORBA::PolicyList policies;

      //Create the transiet poa which has no policies
      PortableServer::POA_var poaTransient_m = poaRoot_m->create_POA("TransientPOA",
								      poaManager.in(),
								      policies);

      policies.length(2);

      policies[0] = PortableServer::LifespanPolicy::_duplicate(persistentPolicy.in());
      policies[1] = PortableServer::IdAssignmentPolicy::_duplicate(userIdPolicy.in());

      PortableServer::POA_var poaPersistent_m = poaRoot_m->create_POA("PersistentPOA",
								      poaManager.in(),
								      policies);

      // We're done using the policies.
      userIdPolicy->destroy();
      persistentPolicy->destroy();

      // POA Manager can start processing incoming requests.
      poaManager->activate();

      // create BACI_CORBA
      BACI_CORBA::createInstance(orb_m.ptr(), poaManager.ptr(),
				 poaRoot_m.ptr(), poaPersistent_m.ptr(), poaTransient_m.ptr());

      }
  catch(...)
      {
      ACS_LOG(0, "baci::BACI_CORBA::InitCORBA", (LM_ERROR, "Unexpected CORBA exception"));
      return false;
      }

  ACS_DEBUG("baci::BACI_CORBA::InitCORBA", "CORBA initialized successfully");
  return true;
}

bool BACI_CORBA::DoneCORBA()
{

  if (instance_mp==0)
      {
      return false;
      }

  try
      {
      // copy of ptrs
      PortableServer::POA_var poaRoot = PortableServer::POA::_duplicate(BACI_CORBA::getInstance()->getPOA());
//      PortableServer::POAManager_var poaManager = PortableServer::POAManager::_duplicate(BACI_CORBA::getInstance()->getPOAManager());
      CORBA::ORB_var orb = CORBA::ORB::_duplicate(BACI_CORBA::getInstance()->getORB());
/*
      if(poaManager.ptr()!=PortableServer::POAManager::_nil())
	{
	  poaManager->deactivate(1, 1);
	}

      ACS_DEBUG("baci::BACI_CORBA::InitCORBA", "POA deactivated (with ehterealization).");
*/
      if(poaRoot.ptr()!=PortableServer::POA::_nil())
	  {
	  poaRoot->destroy(1, 1);
	  }

      if(orb.ptr()!=CORBA::ORB::_nil())
	  {
	  orb->destroy();
	  }

      // delete instance
      BACI_CORBA::destroyInstance();
      }
  catch(...)
    {
      ACS_LOG(0, "baci:BACI_CORBA::DoneCORBA", (LM_ERROR, "Unexpected exception occured"));
      return false;
    }

  return true;
}

<commit_msg>Replaced non portable comparing with _nil() with CORBA::is_nil(x)<commit_after>/*******************************************************************************
*    ALMA - Atacama Large Millimiter Array
*    (c) European Southern Observatory, 2002
*    Copyright by ESO (in the framework of the ALMA collaboration),
*    All rights reserved
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation; either
*    version 2.1 of the License, or (at your option) any later version.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public
*    License along with this library; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
* "@(#) $Id: baciCORBA.cpp,v 1.97 2008/07/14 12:01:37 bjeram Exp $"
*
* who       when      what
* --------  --------  ----------------------------------------------
* gchiozzi 2001-12-20 Added getPOAManager() and getPOARoot() methods.
* msekoran  2001/02/17  created
* msekoran  2001/05/21  fixed destroy bug
* msekoran  2001/08/26  added InitCORBA, DoneCORBA for BACI modular tests
*/

#include <vltPort.h>
#include "logging.h"
#include "baciCORBA.h"

BACI_CORBA * BACI_CORBA::instance_mp = 0;

BACI_CORBA::BACI_CORBA(CORBA::ORB_ptr orb_m,
		       PortableServer::POAManager_ptr poaManager_m,
		       PortableServer::POA_ptr poaRoot_m,
		       PortableServer::POA_ptr poaPersistent_m,
		       PortableServer::POA_ptr poaTransient_m)
{
  this->orb_m = CORBA::ORB::_duplicate(orb_m);
  this->poaManager_m = PortableServer::POAManager::_duplicate(poaManager_m);
  this->poaRoot_m = PortableServer::POA::_duplicate(poaRoot_m);
  this->poaPersistent_m = PortableServer::POA::_duplicate(poaPersistent_m);
  this->poaTransient_m = PortableServer::POA::_duplicate(poaTransient_m);
}

BACI_CORBA::~BACI_CORBA()
{
}

BACI_CORBA *
BACI_CORBA::getInstance()
{
  return instance_mp;
}

BACI_CORBA *
BACI_CORBA::createInstance(CORBA::ORB_ptr orb_m,
			   PortableServer::POAManager_ptr poaManager_m,
			   PortableServer::POA_ptr poaRoot_m,
			   PortableServer::POA_ptr poaPersistent_m,
			   PortableServer::POA_ptr poaTransient_m)
{
  if (instance_mp==0)
      {
      instance_mp = new BACI_CORBA(orb_m, poaManager_m, poaRoot_m, poaPersistent_m, poaTransient_m);
      }
  return instance_mp;
}

void
BACI_CORBA::destroyInstance()
{
  if (instance_mp!=0)
    {
      delete instance_mp;
      instance_mp = 0;
    }
}

CORBA::ORB_ptr
BACI_CORBA::getORB()
{
    if (instance_mp!=0)
	{
	return instance_mp->orb_m.ptr();
	}
    else
	{
	return CORBA::ORB::_nil();
	}
}

PortableServer::POAManager_ptr
BACI_CORBA::getPOAManager()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaManager_m.ptr();
	}
    else
	{
	return PortableServer::POAManager::_nil();
	}
}

PortableServer::POA_ptr
BACI_CORBA::getPOARoot()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaRoot_m.ptr();
	}
    else
	{
	return PortableServer::POA::_nil();
	}
}

PortableServer::POA_ptr
BACI_CORBA::getPOA()
{
    if (instance_mp!=0)
	{
	return instance_mp->poaPersistent_m.ptr();
	}
    else
	{
	return PortableServer::POA::_nil();
	}
}

CORBA::Object_ptr
BACI_CORBA::ActivateCORBAObject(PortableServer::Servant srvnt, const char * name)
{

  if (instance_mp==0 ||
      CORBA::is_nil(instance_mp->poaPersistent_m.ptr()) )
      {
      return CORBA::Object::_nil();
      }

  try
    {
      PortableServer::ObjectId_var id =
	PortableServer::string_to_ObjectId(name);
      instance_mp->poaPersistent_m->activate_object_with_id(id.in(), srvnt);
      CORBA::Object_var obj = instance_mp->poaPersistent_m->servant_to_reference(srvnt);
      return obj._retn();
    }
  catch(...)
    {
    ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::ActivateCORBAObject",
	    (LM_ERROR, "Failed to activate CORBA object"));
    }

  return CORBA::Object::_nil();
}

bool
BACI_CORBA::DestroyCORBAObject(CORBA::Object_ptr obj)
{

  if (instance_mp==0 ||
      instance_mp->poaPersistent_m.ptr() == PortableServer::POA::_nil())
      {
      return false;
      }

  try
    {
      PortableServer::ObjectId_var id =
	instance_mp->poaPersistent_m->reference_to_id(obj);
      instance_mp->poaPersistent_m->deactivate_object(id.in());
      return true;
    }
  catch(...)
    {
      ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyCORBAObject",
	      (LM_ERROR, "Failed to deactivate CORBA object"));
    }

  return false;
}

bool
BACI_CORBA::DestroyCORBAObject(PortableServer::Servant srvnt)
{
    if (instance_mp==0 ||
	instance_mp->poaPersistent_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaPersistent_m->servant_to_id(srvnt);
	instance_mp->poaPersistent_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyCORBAObject (servant)",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}

    return false;
}

bool
BACI_CORBA::DestroyTransientCORBAObject(CORBA::Object_ptr obj)
{
    if (instance_mp==0 ||
	instance_mp->poaTransient_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaTransient_m->reference_to_id(obj);
	instance_mp->poaTransient_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyTransientCORBAObject",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}
  return false;
}

bool
BACI_CORBA::DestroyTransientCORBAObject(PortableServer::Servant srvnt)
{
    if (instance_mp==0 ||
	instance_mp->poaTransient_m.ptr() == PortableServer::POA::_nil())
	{
	return false;
	}

    try
	{
	PortableServer::ObjectId_var id =
	    instance_mp->poaTransient_m->servant_to_id(srvnt);

	instance_mp->poaTransient_m->deactivate_object(id.in());
	return true;
	}
    catch(...)
	{
	ACS_LOG(LM_RUNTIME_CONTEXT, "BACI_CORBA::DestroyTransientCORBAObject (servant)",
		(LM_ERROR, "Failed to deactivate CORBA object"));
	}

    return false;
}

bool BACI_CORBA::InitCORBA(int argc, char* argv[])
{
  try
      {
      // Initialize the ORB.
      CORBA::ORB_var orb_m = CORBA::ORB_init(argc, argv, "TAO");

      if(orb_m.ptr() == CORBA::ORB::_nil())
	{
	return false;
	}

      //
      // Initialize POAs.
      //

      // Get the Root POA.
      CORBA::Object_var objRootPOA =
	  orb_m->resolve_initial_references("RootPOA");

      PortableServer::POA_var poaRoot_m = PortableServer::POA::_narrow(objRootPOA.in());

      if(poaRoot_m.ptr() == PortableServer::POA::_nil())
	  {
	  return false;
	  }

      // Get the manager of the root POA to apply to the child POAs.
      PortableServer::POAManager_var poaManager =
	  poaRoot_m->the_POAManager();

      //
      // Prepare policies our POAs will be using.
      //

      // @@ Unavoidable memory leak here if the POA has been improperly set
      //    up, eg. by a -ORBEndpoint command-line option that does not
      //    correspond to the local host.
      PortableServer::IdAssignmentPolicy_var userIdPolicy =
	  poaRoot_m->create_id_assignment_policy(PortableServer::USER_ID);
      PortableServer::LifespanPolicy_var persistentPolicy =
	  poaRoot_m->create_lifespan_policy(PortableServer::PERSISTENT);

      CORBA::PolicyList policies;

      //Create the transiet poa which has no policies
      PortableServer::POA_var poaTransient_m = poaRoot_m->create_POA("TransientPOA",
								      poaManager.in(),
								      policies);

      policies.length(2);

      policies[0] = PortableServer::LifespanPolicy::_duplicate(persistentPolicy.in());
      policies[1] = PortableServer::IdAssignmentPolicy::_duplicate(userIdPolicy.in());

      PortableServer::POA_var poaPersistent_m = poaRoot_m->create_POA("PersistentPOA",
								      poaManager.in(),
								      policies);

      // We're done using the policies.
      userIdPolicy->destroy();
      persistentPolicy->destroy();

      // POA Manager can start processing incoming requests.
      poaManager->activate();

      // create BACI_CORBA
      BACI_CORBA::createInstance(orb_m.ptr(), poaManager.ptr(),
				 poaRoot_m.ptr(), poaPersistent_m.ptr(), poaTransient_m.ptr());

      }
  catch(...)
      {
      ACS_LOG(0, "baci::BACI_CORBA::InitCORBA", (LM_ERROR, "Unexpected CORBA exception"));
      return false;
      }

  ACS_DEBUG("baci::BACI_CORBA::InitCORBA", "CORBA initialized successfully");
  return true;
}

bool BACI_CORBA::DoneCORBA()
{

  if (instance_mp==0)
      {
      return false;
      }

  try
      {
      // copy of ptrs
      PortableServer::POA_var poaRoot = PortableServer::POA::_duplicate(BACI_CORBA::getInstance()->getPOA());
//      PortableServer::POAManager_var poaManager = PortableServer::POAManager::_duplicate(BACI_CORBA::getInstance()->getPOAManager());
      CORBA::ORB_var orb = CORBA::ORB::_duplicate(BACI_CORBA::getInstance()->getORB());
/*
      if(poaManager.ptr()!=PortableServer::POAManager::_nil())
	{
	  poaManager->deactivate(1, 1);
	}

      ACS_DEBUG("baci::BACI_CORBA::InitCORBA", "POA deactivated (with ehterealization).");
*/
      if(poaRoot.ptr()!=PortableServer::POA::_nil())
	  {
	  poaRoot->destroy(1, 1);
	  }

      if(orb.ptr()!=CORBA::ORB::_nil())
	  {
	  orb->destroy();
	  }

      // delete instance
      BACI_CORBA::destroyInstance();
      }
  catch(...)
    {
      ACS_LOG(0, "baci:BACI_CORBA::DoneCORBA", (LM_ERROR, "Unexpected exception occured"));
      return false;
    }

  return true;
}

<|endoftext|>


<commit_before>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Silence the nested slash-star warning for the next comment's command line.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcomment"

/*
This fuzzer (the fuzz function) is typically run indirectly, by a framework
such as https://github.com/google/oss-fuzz calling LLVMFuzzerTestOneInput.

When working on the fuzz implementation, or as a sanity check, defining
WUFFS_CONFIG__FUZZLIB_MAIN will let you manually run fuzz over a set of files:

g++ -DWUFFS_CONFIG__FUZZLIB_MAIN gif_fuzzer.cc
./a.out ../../../test/testdata/*.gif
rm -f ./a.out

It should print "PASS", amongst other information, and exit(0).
*/

#pragma clang diagnostic pop

// If building this program in an environment that doesn't easily accomodate
// relative includes, you can use the script/inline-c-relative-includes.go
// program to generate a stand-alone C file.
#include "../../../gen/c/std/gif.c"
#include "../fuzzlib/fuzzlib.cc"

void fuzz(wuffs_base__reader1 src_reader, uint32_t hash) {
  void* pixbuf = NULL;

  // Use a {} code block so that "goto exit" doesn't trigger "jump bypasses
  // variable initialization" warnings.
  {
    wuffs_gif__status s;
    wuffs_gif__decoder dec;
    wuffs_gif__decoder__initialize(&dec, WUFFS_VERSION, 0);

    wuffs_base__image_config ic = {{0}};
    s = wuffs_gif__decoder__decode_config(&dec, &ic, src_reader);
    if (s || !wuffs_base__image_config__valid(&ic)) {
      goto exit;
    }

    // Intentionally crash on 0.1% of all possible image widths.
    //
    // TODO: remove this. This intentional segfault is a temporary measure to
    // check that oss-fuzz' fuzzing and reporting works as advertised.
    {
      uint32_t width = wuffs_base__image_config__width(&ic);
      if ((width % 1000) == 123) {
        fprintf(stderr, "intentional segfault for width == %" PRIu32 "\n",
                width);
        intentional_segfault();
      }
    }

    size_t pixbuf_size = wuffs_base__image_config__pixbuf_size(&ic);
    // Don't try to allocate more than 64 MiB.
    if (pixbuf_size > 64 * 1024 * 1024) {
      goto exit;
    }
    pixbuf = malloc(pixbuf_size);
    if (!pixbuf) {
      goto exit;
    }

    wuffs_base__buf1 dst = {.ptr = (uint8_t*)(pixbuf), .len = pixbuf_size};
    wuffs_base__writer1 dst_writer = {.buf = &dst};

    while (true) {
      // TODO: handle the frame rect being larger than the image rect. The
      // GIF89a spec doesn't disallow this and the Wuffs code tolerates it, in
      // that it returns a "short write" (because the dst buffer is too small)
      // and will not e.g. write past the buffer bounds. But the Wuffs GIF API
      // should somehow pass a subset of pixbuf to decode_frame.
      dst.wi = 0;
      s = wuffs_gif__decoder__decode_frame(&dec, dst_writer, src_reader);
      if (s) {
        break;
      }
    }
  }

exit:
  if (pixbuf) {
    free(pixbuf);
  }
}
<commit_msg>Remove intentional OSS-Fuzz segfault<commit_after>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Silence the nested slash-star warning for the next comment's command line.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcomment"

/*
This fuzzer (the fuzz function) is typically run indirectly, by a framework
such as https://github.com/google/oss-fuzz calling LLVMFuzzerTestOneInput.

When working on the fuzz implementation, or as a sanity check, defining
WUFFS_CONFIG__FUZZLIB_MAIN will let you manually run fuzz over a set of files:

g++ -DWUFFS_CONFIG__FUZZLIB_MAIN gif_fuzzer.cc
./a.out ../../../test/testdata/*.gif
rm -f ./a.out

It should print "PASS", amongst other information, and exit(0).
*/

#pragma clang diagnostic pop

// If building this program in an environment that doesn't easily accomodate
// relative includes, you can use the script/inline-c-relative-includes.go
// program to generate a stand-alone C file.
#include "../../../gen/c/std/gif.c"
#include "../fuzzlib/fuzzlib.cc"

void fuzz(wuffs_base__reader1 src_reader, uint32_t hash) {
  void* pixbuf = NULL;

  // Use a {} code block so that "goto exit" doesn't trigger "jump bypasses
  // variable initialization" warnings.
  {
    wuffs_gif__status s;
    wuffs_gif__decoder dec;
    wuffs_gif__decoder__initialize(&dec, WUFFS_VERSION, 0);

    wuffs_base__image_config ic = {{0}};
    s = wuffs_gif__decoder__decode_config(&dec, &ic, src_reader);
    if (s || !wuffs_base__image_config__valid(&ic)) {
      goto exit;
    }

    size_t pixbuf_size = wuffs_base__image_config__pixbuf_size(&ic);
    // Don't try to allocate more than 64 MiB.
    if (pixbuf_size > 64 * 1024 * 1024) {
      goto exit;
    }
    pixbuf = malloc(pixbuf_size);
    if (!pixbuf) {
      goto exit;
    }

    wuffs_base__buf1 dst = {.ptr = (uint8_t*)(pixbuf), .len = pixbuf_size};
    wuffs_base__writer1 dst_writer = {.buf = &dst};

    while (true) {
      // TODO: handle the frame rect being larger than the image rect. The
      // GIF89a spec doesn't disallow this and the Wuffs code tolerates it, in
      // that it returns a "short write" (because the dst buffer is too small)
      // and will not e.g. write past the buffer bounds. But the Wuffs GIF API
      // should somehow pass a subset of pixbuf to decode_frame.
      dst.wi = 0;
      s = wuffs_gif__decoder__decode_frame(&dec, dst_writer, src_reader);
      if (s) {
        break;
      }
    }
  }

exit:
  if (pixbuf) {
    free(pixbuf);
  }
}
<|endoftext|>