<commit_before>
/*
    pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    pbrt is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.  Note that the text contents of
    the book "Physically Based Rendering" are *not* licensed under the
    GNU GPL.

    pbrt 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

// main/pbrt.cpp*
#include "stdafx.h"
#include "api.h"
#include "probes.h"
#include "parser.h"
#include "parallel.h"

// main program
int main(int argc, char *argv[]) {
    Options options;
    vector<string> filenames;
    // Process command-line arguments
    for (int i = 1; i < argc; ++i) {
        if (!strcmp(argv[i], "--ncores")) options.nCores = atoi(argv[++i]);
        else if (!strcmp(argv[i], "--outfile")) options.imageFile = argv[++i];
        else if (!strcmp(argv[i], "--quick")) options.quickRender = true;
        else if (!strcmp(argv[i], "--quiet")) options.quiet = true;
        else if (!strcmp(argv[i], "--verbose")) options.verbose = true;
        else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
            printf("usage: pbrt [--ncores n] [--outfile filename] [--quick] [--quiet] "
                   "[--verbose] [--help] <filename.pbrt> ...\n");
            return 0;
        }
        else filenames.push_back(argv[i]);
    }

    // Print welcome banner
    if (!options.quiet) {
        printf("pbrt version %s of %s at %s [Detected %d core(s)]\n",
               PBRT_VERSION, __DATE__, __TIME__, NumSystemCores());
        printf("Copyright (c)1998-2010 Matt Pharr and Greg Humphreys.\n");
        printf("The source code to pbrt (but *not* the book contents) is covered by the GNU GPL.\n");
        printf("See the file COPYING.txt for the conditions of the license.\n");
        fflush(stdout);
    }
    pbrtInit(options);
    // Process scene description
    PBRT_STARTED_PARSING();
    if (filenames.size() == 0) {
        // Parse scene from standard input
        ParseFile("-");
    } else {
        // Parse scene from input files
        for (u_int i = 0; i < filenames.size(); i++)
            if (!ParseFile(filenames[i]))
                Error("Couldn't open scene file \"%s\"", filenames[i].c_str());
    }
    pbrtCleanup();
    return 0;
}

<commit_msg>Bump copyright to 2012<commit_after>
/*
    pbrt source code Copyright(c) 1998-2010 Matt Pharr and Greg Humphreys.

    This file is part of pbrt.

    pbrt is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.  Note that the text contents of
    the book "Physically Based Rendering" are *not* licensed under the
    GNU GPL.

    pbrt 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

// main/pbrt.cpp*
#include "stdafx.h"
#include "api.h"
#include "probes.h"
#include "parser.h"
#include "parallel.h"

// main program
int main(int argc, char *argv[]) {
    Options options;
    vector<string> filenames;
    // Process command-line arguments
    for (int i = 1; i < argc; ++i) {
        if (!strcmp(argv[i], "--ncores")) options.nCores = atoi(argv[++i]);
        else if (!strcmp(argv[i], "--outfile")) options.imageFile = argv[++i];
        else if (!strcmp(argv[i], "--quick")) options.quickRender = true;
        else if (!strcmp(argv[i], "--quiet")) options.quiet = true;
        else if (!strcmp(argv[i], "--verbose")) options.verbose = true;
        else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
            printf("usage: pbrt [--ncores n] [--outfile filename] [--quick] [--quiet] "
                   "[--verbose] [--help] <filename.pbrt> ...\n");
            return 0;
        }
        else filenames.push_back(argv[i]);
    }

    // Print welcome banner
    if (!options.quiet) {
        printf("pbrt version %s of %s at %s [Detected %d core(s)]\n",
               PBRT_VERSION, __DATE__, __TIME__, NumSystemCores());
        printf("Copyright (c)1998-2012 Matt Pharr and Greg Humphreys.\n");
        printf("The source code to pbrt (but *not* the book contents) is covered by the GNU GPL.\n");
        printf("See the file COPYING.txt for the conditions of the license.\n");
        fflush(stdout);
    }
    pbrtInit(options);
    // Process scene description
    PBRT_STARTED_PARSING();
    if (filenames.size() == 0) {
        // Parse scene from standard input
        ParseFile("-");
    } else {
        // Parse scene from input files
        for (u_int i = 0; i < filenames.size(); i++)
            if (!ParseFile(filenames[i]))
                Error("Couldn't open scene file \"%s\"", filenames[i].c_str());
    }
    pbrtCleanup();
    return 0;
}

<|endoftext|>


<commit_before>#include "io.h"
#include "multiclass.h"
#include "Snap.h"

#include <vector>

int main()
{
	MNM_Dlink *_link;
	MNM_Dlink_Multiclass *_link_m;

	printf("BEGIN multiclass test!\n");

	// On ubuntu (PC)
	std::string folder = "/home/alanpi/Desktop/MAC-POSTS/data/input_files_MckeesRocks_SPC";
	// std::string folder = "/home/lemma/Documents/MAC-POSTS/src/examples/mcDODE/a6e7b31067d2ead8d3725fc0ed587d06c958f63c";
	// std::string folder = "/home/alanpi/Desktop/MAC-POSTS/data/input_files_7link_multiclass";

	// on macOS (Mac air)
	// std::string folder = "/Users/alan-air/Dropbox/MAC-POSTS/data/input_files_MckeesRocks_SPC";
	// std::string folder = "/Users/alan-air/Dropbox/MAC-POSTS/data/input_files_7link_multiclass";

	MNM_Dta_Multiclass *test_dta = new MNM_Dta_Multiclass(folder);

	printf("================================ DTA set! =================================\n");

	test_dta -> build_from_files();
	printf("========================= Finished initialization! ========================\n");

	test_dta -> hook_up_node_and_link();
	printf("====================== Finished node and link hook-up! ====================\n");

	test_dta -> is_ok();
	printf("============================ DTA is OK to run! ============================\n");

	TInt _current_inter = 0;
	TInt _assign_inter = test_dta -> m_start_assign_interval;
	test_dta -> pre_loading();
	printf("========================== Finished pre_loading! ==========================\n");

	printf("\n\n\n====================================== Start loading! =======================================\n");
	bool _verbose = false;
	bool output_link_cong = false; // if true output link congestion level every cong_frequency
	TInt cong_frequency = 180; // 15 minutes
	bool output_veh_locs = false; // if true output veh location every vis_frequency
	TInt vis_frequency = 60; // 5 minutes
	MNM_Veh_Multiclass* _veh;
	std::ofstream _vis_file;
	std::string _str;
	if (output_veh_locs){
		_vis_file.open(folder + "/veh_loc/veh_loc_raw.txt", std::ofstream::out);
		if (! _vis_file.is_open()){
        	printf("Error happens when open _vis_file\n");
        	exit(-1);
        }
	}

	while (!test_dta -> finished_loading(_current_inter)){
		printf("Current interval: %d\n", _current_inter());
		test_dta -> load_once(_verbose, _current_inter, _assign_inter);
		if (_current_inter % test_dta -> m_assign_freq == 0 || _current_inter == 0){
			_assign_inter += 1;
		}
		if (output_veh_locs && (_current_inter % vis_frequency == 0)){
			for (auto _map_it : test_dta -> m_veh_factory -> m_veh_map){
				if (_map_it.second -> m_finish_time < 0) {
					_veh = dynamic_cast<MNM_Veh_Multiclass *>(_map_it.second);
					if (_veh -> m_class == 0){
						_str = "Car ";
					}
					else {
						_str = "Truck ";
					}
					_str += std::to_string(_current_inter) + " ";
					_str += std::to_string(_veh -> get_current_link() -> m_link_ID) + " ";
					_str += std::to_string(_veh -> m_visual_position_on_link);
					_str += "\n";
					_vis_file << _str;
				}
			}
		}
		_current_inter += 1;
		if (_current_inter > 600) break;
	}

	// Output total travels and travel time, before divided by flow_scalar
	TInt _count_car = 0, _count_truck = 0;
	TFlt _tot_tt = 0.0;
	for (auto _map_it : test_dta -> m_veh_factory -> m_veh_map){
		if (_map_it.second -> m_finish_time > 0) {
			_veh = dynamic_cast<MNM_Veh_Multiclass *>(_map_it.second);
			if (_veh -> m_class == 0){
				_count_car += 1;
			}
			else {
				_count_truck += 1;
			}
			_tot_tt += (_veh -> m_finish_time - _veh -> m_start_time) * 5.0 / 3600.0;
		}
	}
	printf("\n\n\nTotal car: %d, Total truck: %d, Total tt: %.2f hours\n\n\n\n", int(_count_car), int(_count_truck), float(_tot_tt));

	if (output_veh_locs){
		if (_vis_file.is_open()) _vis_file.close();
	}

	std::ofstream _vis_file2;
	if (output_link_cong){
		_vis_file2.open(folder + "/link_cong/link_cong_raw.txt", std::ofstream::out);
		if (! _vis_file2.is_open()){
        	printf("Error happens when open _vis_file2\n");
        	exit(-1);
        }
		TInt _iter = 0;
		while (_iter < _current_inter){
			if (_iter % cong_frequency == 0){
				printf("Current iteration: %d\n", int(_iter));
				for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin();
						  _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
					_link = _link_it -> second;
					_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
					_str = std::to_string(_link -> m_link_ID()) + " ";
					_str += std::to_string(_iter) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_link_inflow_car(_link_m, _iter, _iter + 1)) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_link_inflow_truck(_link_m, _iter, _iter + 1)) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))) + " ";
					_str += std::to_string(_link_m -> get_link_freeflow_tt_car()) + " ";
					_str += std::to_string(_link_m -> get_link_freeflow_tt_truck()) + " ";
					_str += std::to_string(_link_m -> m_length/MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))*3600/1600) + " ";
					_str += std::to_string(_link_m -> m_length/MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))*3600/1600) + "\n";
					_vis_file2 << _str;
				}
			}
			_iter += 1;
		}
		if (_vis_file2.is_open()) _vis_file2.close();
	}

	// output tt of some special links
	for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin(); _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
			_link = _link_it -> second;
			if (_link -> m_link_ID() == 7186) {
				TInt _iter = 0;
				while (_iter < _current_inter){
					// if (_iter == 984){
						_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
						printf("%d,%.2f,%.2f\n", int(_iter),
							double(MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))),
							double(MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))));
					// }
					_iter += 1;
				}
			}
	}

	// output CC of some special links
	for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin();
				  _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
			_link = _link_it -> second;
		if (_link -> m_link_ID() == 7186){
			_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
			printf("\n\nm_N_in_car: \n");
			std::cout <<_link_m -> m_N_in_car -> to_string() << std::endl;
			printf("\n\nm_N_out_car: \n");
			std::cout <<_link_m -> m_N_out_car -> to_string() << std::endl;
			printf("\n\nm_N_in_truck: \n");
			std::cout <<_link_m -> m_N_in_truck -> to_string() << std::endl;
			printf("\n\nm_N_out_truck: \n");
			std::cout <<_link_m -> m_N_out_truck -> to_string() << std::endl;
		}
	}

	delete test_dta;
	printf("Finished delete test_dta!\n\n\n");

	return 0;
}<commit_msg>update test<commit_after>#include "io.h"
#include "multiclass.h"
#include "Snap.h"

#include <vector>

int main()
{
	MNM_Dlink *_link;
	MNM_Dlink_Multiclass *_link_m;

	printf("BEGIN multiclass test!\n");

	// On ubuntu (PC)
	std::string folder = "/home/alanpi/Desktop/MAC-POSTS/data/input_files_MckeesRocks_SPC";
	// std::string folder = "/home/lemma/Documents/MAC-POSTS/src/examples/mcDODE/a6e7b31067d2ead8d3725fc0ed587d06c958f63c";
	// std::string folder = "/home/alanpi/Desktop/MAC-POSTS/data/input_files_7link_multiclass";

	// on macOS (Mac air)
	// std::string folder = "/Users/alan-air/Dropbox/MAC-POSTS/data/input_files_MckeesRocks_SPC";
	// std::string folder = "/Users/alan-air/Dropbox/MAC-POSTS/data/input_files_7link_multiclass";

	MNM_Dta_Multiclass *test_dta = new MNM_Dta_Multiclass(folder);

	printf("================================ DTA set! =================================\n");

	test_dta -> build_from_files();
	printf("========================= Finished initialization! ========================\n");

	test_dta -> hook_up_node_and_link();
	printf("====================== Finished node and link hook-up! ====================\n");

	test_dta -> is_ok();
	printf("============================ DTA is OK to run! ============================\n");

	TInt _current_inter = 0;
	TInt _assign_inter = test_dta -> m_start_assign_interval;
	test_dta -> pre_loading();
	printf("========================== Finished pre_loading! ==========================\n");

	printf("\n\n\n====================================== Start loading! =======================================\n");
	bool _verbose = false;
	bool output_link_cong = false; // if true output link congestion level every cong_frequency
	TInt cong_frequency = 180; // 15 minutes
	bool output_veh_locs = false; // if true output veh location every vis_frequency
	TInt vis_frequency = 60; // 5 minutes
	MNM_Veh_Multiclass* _veh;
	std::ofstream _vis_file;
	std::string _str;
	if (output_veh_locs){
		_vis_file.open(folder + "/veh_loc/veh_loc_raw.txt", std::ofstream::out);
		if (! _vis_file.is_open()){
        	printf("Error happens when open _vis_file\n");
        	exit(-1);
        }
	}

	while (!test_dta -> finished_loading(_current_inter)){
		printf("Current interval: %d\n", _current_inter());
		test_dta -> load_once(_verbose, _current_inter, _assign_inter);
		if (_current_inter % test_dta -> m_assign_freq == 0 || _current_inter == 0){
			_assign_inter += 1;
		}
		if (output_veh_locs && (_current_inter % vis_frequency == 0)){
			for (auto _map_it : test_dta -> m_veh_factory -> m_veh_map){
				if (_map_it.second -> m_finish_time < 0) {
					_veh = dynamic_cast<MNM_Veh_Multiclass *>(_map_it.second);
					if (_veh -> m_class == 0){
						_str = "Car ";
					}
					else {
						_str = "Truck ";
					}
					_str += std::to_string(_current_inter) + " ";
					_str += std::to_string(_veh -> get_current_link() -> m_link_ID) + " ";
					_str += std::to_string(_veh -> m_visual_position_on_link);
					_str += "\n";
					_vis_file << _str;
				}
			}
		}
		_current_inter += 1;
		if (_current_inter > 600) break;
	}

	// Output total travels and travel time, before divided by flow_scalar
	TInt _count_car = 0, _count_truck = 0;
	TFlt _tot_tt = 0.0;
	for (auto _map_it : test_dta -> m_veh_factory -> m_veh_map){
		if (_map_it.second -> m_finish_time > 0) {
			_veh = dynamic_cast<MNM_Veh_Multiclass *>(_map_it.second);
			if (_veh -> m_class == 0){
				_count_car += 1;
			}
			else {
				_count_truck += 1;
			}
			_tot_tt += (_veh -> m_finish_time - _veh -> m_start_time) * 5.0 / 3600.0;
		}
	}
	printf("\n\n\nTotal car: %d, Total truck: %d, Total tt: %.2f hours\n\n\n\n", int(_count_car), int(_count_truck), float(_tot_tt));

	if (output_veh_locs){
		if (_vis_file.is_open()) _vis_file.close();
	}

	std::ofstream _vis_file2;
	if (output_link_cong){
		_vis_file2.open(folder + "/link_cong/link_cong_raw.txt", std::ofstream::out);
		if (! _vis_file2.is_open()){
        	printf("Error happens when open _vis_file2\n");
        	exit(-1);
        }
		TInt _iter = 0;
		while (_iter < _current_inter){
			if (_iter % cong_frequency == 0){
				printf("Current iteration: %d\n", int(_iter));
				for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin();
						  _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
					_link = _link_it -> second;
					_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
					_str = std::to_string(_link -> m_link_ID()) + " ";
					_str += std::to_string(_iter) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_link_inflow_car(_link_m, _iter, _iter + 1)) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_link_inflow_truck(_link_m, _iter, _iter + 1)) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))) + " ";
					_str += std::to_string(MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))) + " ";
					_str += std::to_string(_link_m -> get_link_freeflow_tt_car()) + " ";
					_str += std::to_string(_link_m -> get_link_freeflow_tt_truck()) + " ";
					_str += std::to_string(_link_m -> m_length/MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))*3600/1600) + " ";
					_str += std::to_string(_link_m -> m_length/MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))*3600/1600) + "\n";
					_vis_file2 << _str;
				}
			}
			_iter += 1;
		}
		if (_vis_file2.is_open()) _vis_file2.close();
	}

	// // output tt of some special links
	// for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin(); _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
	// 		_link = _link_it -> second;
	// 		if (_link -> m_link_ID() == 7186) {
	// 			TInt _iter = 0;
	// 			while (_iter < _current_inter){
	// 				// if (_iter == 984){
	// 					_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
	// 					printf("%d,%.2f,%.2f\n", int(_iter),
	// 						double(MNM_DTA_GRADIENT::get_travel_time_car(_link_m, TFlt(_iter + 1))),
	// 						double(MNM_DTA_GRADIENT::get_travel_time_truck(_link_m, TFlt(_iter + 1))));
	// 				// }
	// 				_iter += 1;
	// 			}
	// 		}
	// }

	// // output CC of some special links
	// for (auto _link_it = test_dta -> m_link_factory -> m_link_map.begin();
	// 			  _link_it != test_dta -> m_link_factory -> m_link_map.end(); _link_it++){
	// 		_link = _link_it -> second;
	// 	if (_link -> m_link_ID() == 7186){
	// 		_link_m = dynamic_cast<MNM_Dlink_Multiclass*>(_link);
	// 		printf("\n\nm_N_in_car: \n");
	// 		std::cout <<_link_m -> m_N_in_car -> to_string() << std::endl;
	// 		printf("\n\nm_N_out_car: \n");
	// 		std::cout <<_link_m -> m_N_out_car -> to_string() << std::endl;
	// 		printf("\n\nm_N_in_truck: \n");
	// 		std::cout <<_link_m -> m_N_in_truck -> to_string() << std::endl;
	// 		printf("\n\nm_N_out_truck: \n");
	// 		std::cout <<_link_m -> m_N_out_truck -> to_string() << std::endl;
	// 	}
	// }

	delete test_dta;
	printf("Finished delete test_dta!\n\n\n");

	return 0;
}<|endoftext|>


<commit_before>#include <errno.h>
#include <stdlib.h>
#include <getopt.h>
#include <string>

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include "logger.h"
#include <libwatcher/client.h>
#include <libwatcher/labelMessage.h>
#include "sendMessageHandler.h"

using namespace std;
using namespace watcher;
using namespace watcher::event;
using namespace boost;

void usage(const char *progName)
{
    fprintf(stderr, "Usage: %s [args] [optional args]\n", basename(progName));
    fprintf(stderr, "Args:\n");
    fprintf(stderr, "   -l, --label=label        The text to put in the label\n");
    fprintf(stderr, "   -s, --server=server      The name/address of the watcherd server\n");
    fprintf(stderr, "   -h,-H,-?,-help           Show this usage message\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Optional args:\n");
    fprintf(stderr, "   If address is specified, the label will attach to the node with that address. If cooridinates are\n");
    fprintf(stderr, "   specified, the label will float at those coordinates. The node address takes precedence. If neither\n");
    fprintf(stderr, "   option is specified, the label will attach to the local node in the watcher.\n");
    fprintf(stderr, "   -n, --node=address          The node to attach the label to.\n");
    fprintf(stderr, "   -x, --latitude=coord        The latitude to float the node at.\n");
    fprintf(stderr, "   -y, --longitude=coord       The longitude to float the node at.\n");
    fprintf(stderr, "   -z, --altitiude=coord       The altitude to float the node at.\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "   -p, --logProps              log.properties file, which controls logging for this program\n");
    fprintf(stderr, "   -t, --fontSize=size         The font size of the label\n");
    fprintf(stderr, "   -f, --foreground=color      The foreground color of the label. Can be ROYGBIV or RGBA format, string or hex value.\n");
    fprintf(stderr, "   -b, --background=color      The background color of the label. Can be ROYGBIV or RGBA format, string or hex value.\n");
    fprintf(stderr, "   -e, --expiration=seconds    How long in secondt to diplay the label\n");
    fprintf(stderr, "   -r, --remove                Remove the label if it is attached\n");
    fprintf(stderr, "   -L, --layer=layer           Which layer the label is part of. Default is physical\n");

    exit(1);
}

int main(int argc, char **argv)
{
    TRACE_ENTER();

    int c;
    string label;
    string server;
    string logProps("sendMessage.log.properties");
    unsigned int fontSize=10;
    asio::ip::address address;
    Color fg=Color::black;
    Color bg=Color::white;
    uint32_t expiration=10000;
    float lat=0.0, lng=0.0, alt=0.0;
    bool remove=false;
    GUILayer layer=PHYSICAL_LAYER;

    while (true)
    {
        int option_index = 0;
        static struct option long_options[] = {
            {"label", required_argument, 0, 'l'},
            {"server", required_argument, 0, 's'},
            {"node", required_argument, 0, 'n'},
            {"latitude", required_argument, 0, 'x'},
            {"longitude", required_argument, 0, 'y'},
            {"altitiude", required_argument, 0, 'z'},
            {"logProps", required_argument, 0, 'p'},
            {"fontSize", required_argument, 0, 't'},
            {"foreground", required_argument, 0, 'f'},
            {"background", required_argument, 0, 'b'},
            {"expiration", required_argument, 0, 'e'},
            {"remove", no_argument, 0, 'r'},
            {"layer", required_argument, 0, 'L'},
            {"help", no_argument, 0, 'h'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "l:s:n:x:y:t:p:z:f:b:e:L:rhH?", long_options, &option_index);

        if (c == -1)
            break;

        switch(c)
        {
            case 'l': label=optarg; break;
            case 's': server=optarg; break;
            case 'p': logProps=optarg; break;
            case 't': fontSize=lexical_cast<unsigned int>(optarg); break;
            case 'f': { bool val=fg.fromString(optarg); if (!val) { printf("\nBad argument for fg color\n\n"); usage(argv[0]); } break; }
            case 'b': { bool val=bg.fromString(optarg); if (!val) { printf("\nBad argument for bg color\n\n"); usage(argv[0]); } break; }
            case 'e': expiration=lexical_cast<uint32_t>(optarg); break;
            case 'n':
                      {
                          boost::system::error_code e;
                          address=asio::ip::address::from_string(optarg, e);
                          if (e)
                          {
                                fprintf(stderr, "\nI did not understand the \"node\" argument: %s. It should be a host address.\n\n", optarg);
                                usage(argv[0]);
                                TRACE_EXIT_RET(EXIT_FAILURE);
                                return EXIT_FAILURE;
                          }
                      }
                      break;
            case 'x': lat=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'y': lng=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'z': alt=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'r': remove=true; break;
            case 'L': label=optarg; break;
            case 'h':
            case 'H':
            case '?':
            default:
                usage(argv[0]);
                break;
        }
    }

    if (server=="" || label=="")
    {
        usage(argv[0]);
        exit(1);
    }

    //
    // Now do some actual work.
    //
    LOAD_LOG_PROPS(logProps);

    watcher::Client client(server);
    LOG_INFO("Connecting to " << server << " and sending message.");
    client.addMessageHandler(SendMessageHandler::create());

    LabelMessagePtr lm = LabelMessagePtr(new LabelMessage);

    lm->label=label;
    lm->fontSize=fontSize;
    lm->fromNodeID=address;
    lm->foreground=fg;
    lm->background=bg;
    lm->expiration=expiration;
    lm->lat=lat;
    lm->lng=lng;
    lm->alt=alt;
    lm->addLabel=!remove;
    lm->layer=layer;

    if(!client.sendMessage(lm))
    {
        LOG_ERROR("Error sending label message: " << *lm);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    client.wait();

    TRACE_EXIT_RET(EXIT_SUCCESS);
    return EXIT_SUCCESS;
}

<commit_msg>sendLabelMessage: fix thinko.<commit_after>#include <errno.h>
#include <stdlib.h>
#include <getopt.h>
#include <string>

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include "logger.h"
#include <libwatcher/client.h>
#include <libwatcher/labelMessage.h>
#include "sendMessageHandler.h"

using namespace std;
using namespace watcher;
using namespace watcher::event;
using namespace boost;

void usage(const char *progName)
{
    fprintf(stderr, "Usage: %s [args] [optional args]\n", basename(progName));
    fprintf(stderr, "Args:\n");
    fprintf(stderr, "   -l, --label=label        The text to put in the label\n");
    fprintf(stderr, "   -s, --server=server      The name/address of the watcherd server\n");
    fprintf(stderr, "   -h,-H,-?,-help           Show this usage message\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Optional args:\n");
    fprintf(stderr, "   If address is specified, the label will attach to the node with that address. If cooridinates are\n");
    fprintf(stderr, "   specified, the label will float at those coordinates. The node address takes precedence. If neither\n");
    fprintf(stderr, "   option is specified, the label will attach to the local node in the watcher.\n");
    fprintf(stderr, "   -n, --node=address          The node to attach the label to.\n");
    fprintf(stderr, "   -x, --latitude=coord        The latitude to float the node at.\n");
    fprintf(stderr, "   -y, --longitude=coord       The longitude to float the node at.\n");
    fprintf(stderr, "   -z, --altitiude=coord       The altitude to float the node at.\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "   -p, --logProps              log.properties file, which controls logging for this program\n");
    fprintf(stderr, "   -t, --fontSize=size         The font size of the label\n");
    fprintf(stderr, "   -f, --foreground=color      The foreground color of the label. Can be ROYGBIV or RGBA format, string or hex value.\n");
    fprintf(stderr, "   -b, --background=color      The background color of the label. Can be ROYGBIV or RGBA format, string or hex value.\n");
    fprintf(stderr, "   -e, --expiration=seconds    How long in secondt to diplay the label\n");
    fprintf(stderr, "   -r, --remove                Remove the label if it is attached\n");
    fprintf(stderr, "   -L, --layer=layer           Which layer the label is part of. Default is physical\n");

    exit(1);
}

int main(int argc, char **argv)
{
    TRACE_ENTER();

    int c;
    string label;
    string server;
    string logProps("sendMessage.log.properties");
    unsigned int fontSize=10;
    asio::ip::address address;
    Color fg=Color::black;
    Color bg=Color::white;
    uint32_t expiration=10000;
    float lat=0.0, lng=0.0, alt=0.0;
    bool remove=false;
    GUILayer layer=PHYSICAL_LAYER;

    while (true)
    {
        int option_index = 0;
        static struct option long_options[] = {
            {"label", required_argument, 0, 'l'},
            {"server", required_argument, 0, 's'},
            {"node", required_argument, 0, 'n'},
            {"latitude", required_argument, 0, 'x'},
            {"longitude", required_argument, 0, 'y'},
            {"altitiude", required_argument, 0, 'z'},
            {"logProps", required_argument, 0, 'p'},
            {"fontSize", required_argument, 0, 't'},
            {"foreground", required_argument, 0, 'f'},
            {"background", required_argument, 0, 'b'},
            {"expiration", required_argument, 0, 'e'},
            {"remove", no_argument, 0, 'r'},
            {"layer", required_argument, 0, 'L'},
            {"help", no_argument, 0, 'h'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "l:s:n:x:y:t:p:z:f:b:e:L:rhH?", long_options, &option_index);

        if (c == -1)
            break;

        switch(c)
        {
            case 'l': label=optarg; break;
            case 's': server=optarg; break;
            case 'p': logProps=optarg; break;
            case 't': fontSize=lexical_cast<unsigned int>(optarg); break;
            case 'f': { bool val=fg.fromString(optarg); if (!val) { printf("\nBad argument for fg color\n\n"); usage(argv[0]); } break; }
            case 'b': { bool val=bg.fromString(optarg); if (!val) { printf("\nBad argument for bg color\n\n"); usage(argv[0]); } break; }
            case 'e': expiration=lexical_cast<uint32_t>(optarg); break;
            case 'n':
                      {
                          boost::system::error_code e;
                          address=asio::ip::address::from_string(optarg, e);
                          if (e)
                          {
                                fprintf(stderr, "\nI did not understand the \"node\" argument: %s. It should be a host address.\n\n", optarg);
                                usage(argv[0]);
                                TRACE_EXIT_RET(EXIT_FAILURE);
                                return EXIT_FAILURE;
                          }
                      }
                      break;
            case 'x': lat=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'y': lng=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'z': alt=lexical_cast<float>(optarg); break; // GTL should try{}catch{} here for invalid values.
            case 'r': remove=true; break;
            case 'L': layer=optarg; break;
            case 'h':
            case 'H':
            case '?':
            default:
                usage(argv[0]);
                break;
        }
    }

    if (server=="" || label=="")
    {
        usage(argv[0]);
        exit(1);
    }

    //
    // Now do some actual work.
    //
    LOAD_LOG_PROPS(logProps);

    watcher::Client client(server);
    LOG_INFO("Connecting to " << server << " and sending message.");
    client.addMessageHandler(SendMessageHandler::create());

    LabelMessagePtr lm = LabelMessagePtr(new LabelMessage);

    lm->label=label;
    lm->fontSize=fontSize;
    lm->fromNodeID=address;
    lm->foreground=fg;
    lm->background=bg;
    lm->expiration=expiration;
    lm->lat=lat;
    lm->lng=lng;
    lm->alt=alt;
    lm->addLabel=!remove;
    lm->layer=layer;

    if(!client.sendMessage(lm))
    {
        LOG_ERROR("Error sending label message: " << *lm);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    client.wait();

    TRACE_EXIT_RET(EXIT_SUCCESS);
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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
//
//   http://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.

#include "kudu/ranger/ranger_client.h"

#include <ostream>
#include <string>
#include <utility>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "kudu/common/table_util.h"
#include "kudu/gutil/macros.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/strings/join.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/ranger/ranger.pb.h"
#include "kudu/util/env.h"
#include "kudu/util/flag_tags.h"
#include "kudu/util/metrics.h"
#include "kudu/util/path_util.h"
#include "kudu/util/slice.h"
#include "kudu/util/status.h"

DEFINE_string(ranger_config_path, "",
              "Path to directory containing Ranger client configuration. "
              "Enables Ranger authorization provider. "
              "sentry_service_rpc_addresses must not be set if this is "
              "enabled.");
TAG_FLAG(ranger_config_path, experimental);

DEFINE_string(ranger_jar_path, "",
              "Path to the JAR file containing the Ranger subprocess.");
TAG_FLAG(ranger_jar_path, experimental);

METRIC_DEFINE_histogram(server, ranger_subprocess_execution_time_ms,
    "Ranger subprocess execution time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent executing the Ranger subprocess request, excluding "
    "time spent spent in the subprocess queues",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_inbound_queue_length,
    "Ranger subprocess inbound queue length",
    kudu::MetricUnit::kMessages,
    "Number of request messages in the Ranger subprocess' inbound request queue",
    kudu::MetricLevel::kInfo,
    1000, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_inbound_queue_time_ms,
    "Ranger subprocess inbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger subprocess' inbound request queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_outbound_queue_length,
    "Ranger subprocess outbound queue length",
    kudu::MetricUnit::kMessages,
    "Number of request messages in the Ranger subprocess' outbound response queue",
    kudu::MetricLevel::kInfo,
    1000, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_outbound_queue_time_ms,
    "Ranger subprocess outbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger subprocess' outbound response queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_server_inbound_queue_size_bytes,
    "Ranger server inbound queue size (bytes)",
    kudu::MetricUnit::kBytes,
    "Number of bytes in the inbound response queue of the Ranger server, recorded "
    "at the time a new response is read from the pipe and added to the inbound queue",
    kudu::MetricLevel::kInfo,
    4 * 1024 * 1024, 1);
METRIC_DEFINE_histogram(server, ranger_server_inbound_queue_time_ms,
    "Ranger server inbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger server's inbound response queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_server_outbound_queue_size_bytes,
    "Ranger server outbound queue size (bytes)",
    kudu::MetricUnit::kBytes,
    "Number of bytes in the outbound request queue of the Ranger server, recorded "
    "at the time a new request is added to the outbound request queue",
    kudu::MetricLevel::kInfo,
    4 * 1024 * 1024, 1);
METRIC_DEFINE_histogram(server, ranger_server_outbound_queue_time_ms,
    "Ranger server outbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger server's outbound request queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);

namespace kudu {
namespace ranger {

using kudu::subprocess::SubprocessMetrics;
using std::move;
using std::string;
using std::unordered_set;
using std::vector;
using strings::Substitute;

static const char* kUnauthorizedAction = "Unauthorized action";
static const char* kDenyNonRangerTableTemplate = "Denying action on table with invalid name $0. "
                                                 "Use 'kudu table rename_table' to rename it to "
                                                 "a Ranger-compatible name.";
const char* kMainClass = "org.apache.kudu.subprocess.ranger.RangerSubprocessMain";

#define HISTINIT(member, x) member = METRIC_##x.Instantiate(entity)
RangerSubprocessMetrics::RangerSubprocessMetrics(const scoped_refptr<MetricEntity>& entity) {
  HISTINIT(sp_inbound_queue_length, ranger_subprocess_inbound_queue_length);
  HISTINIT(sp_inbound_queue_time_ms, ranger_subprocess_inbound_queue_time_ms);
  HISTINIT(sp_outbound_queue_length, ranger_subprocess_outbound_queue_length);
  HISTINIT(sp_outbound_queue_time_ms, ranger_subprocess_outbound_queue_time_ms);
  HISTINIT(sp_execution_time_ms, ranger_subprocess_execution_time_ms);
  HISTINIT(server_inbound_queue_size_bytes, ranger_server_inbound_queue_size_bytes);
  HISTINIT(server_inbound_queue_time_ms, ranger_server_inbound_queue_time_ms);
  HISTINIT(server_outbound_queue_size_bytes, ranger_server_outbound_queue_size_bytes);
  HISTINIT(server_outbound_queue_time_ms, ranger_server_outbound_queue_time_ms);
}
#undef HISTINIT

RangerClient::RangerClient(const scoped_refptr<MetricEntity>& metric_entity) :
  subprocess_({"java", "-cp", GetJavaClasspath()}, metric_entity) {}

Status RangerClient::Start() {
  VLOG(1) << "Initializing Ranger subprocess server";
  return subprocess_.Start();
}

// TODO(abukor): refactor to avoid code duplication
Status RangerClient::AuthorizeAction(const string& user_name,
                                     const ActionPB& action,
                                     const string& table_name) {
  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  RangerRequestPB* req = req_list.add_requests();

  req->set_action(action);
  req->set_database(db);
  req->set_table(tbl.ToString());

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  CHECK_EQ(1, resp_list.responses_size());
  if (resp_list.responses().begin()->allowed()) {
    return Status::OK();
  }

  LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on $2",
                             user_name, ActionPB_Name(action), table_name);
  return Status::NotAuthorized(kUnauthorizedAction);
}

Status RangerClient::AuthorizeActionMultipleColumns(const string& user_name,
                                                    const ActionPB& action,
                                                    const string& table_name,
                                                    unordered_set<string>* column_names) {
  DCHECK(!column_names->empty());

  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  for (const auto& col : *column_names) {
    auto req = req_list.add_requests();
    req->set_action(action);
    req->set_database(db);
    req->set_table(tbl.ToString());
    req->set_column(col);
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(column_names->size(), resp_list.responses_size());

  unordered_set<string> allowed_columns;
  for (auto i = 0; i < req_list.requests_size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_columns, move(req_list.requests(i).column()));
    }
  }

  if (allowed_columns.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on table $2",
                               user_name, ActionPB_Name(action), table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *column_names = move(allowed_columns);

  return Status::OK();
}

Status RangerClient::AuthorizeActionMultipleTables(const string& user_name,
                                                   const ActionPB& action,
                                                   unordered_set<string>* table_names) {
  if (table_names->empty()) {
    return Status::InvalidArgument("Empty set of tables");
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  vector<string> orig_table_names;

  for (const auto& table : *table_names) {
    string db;
    Slice tbl;

    auto s = ParseRangerTableIdentifier(table, &db, &tbl);
    if (PREDICT_TRUE(s.ok())) {
      orig_table_names.emplace_back(table);

      auto req = req_list.add_requests();
      req->set_action(action);
      req->set_database(db);
      req->set_table(tbl.ToString());
    } else {
      LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table);
    }
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(orig_table_names.size(), resp_list.responses_size());

  unordered_set<string> allowed_tables;
  for (auto i = 0; i < orig_table_names.size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_tables, move(orig_table_names[i]));
    }
  }

  if (allowed_tables.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on $2 tables",
                               user_name, ActionPB_Name(action), table_names->size());
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *table_names = move(allowed_tables);

  return Status::OK();
}

Status RangerClient::AuthorizeActions(const string& user_name,
                                      const string& table_name,
                                      unordered_set<ActionPB, ActionHash>* actions) {
  DCHECK(!actions->empty());

  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  for (const auto& action : *actions) {
    auto req = req_list.add_requests();
    req->set_action(action);
    req->set_database(db);
    req->set_table(tbl.ToString());
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(actions->size(), resp_list.responses_size());

  unordered_set<ActionPB, ActionHash> allowed_actions;
  for (auto i = 0; i < req_list.requests_size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_actions, move(req_list.requests(i).action()));
    }
  }

  if (allowed_actions.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform actions $1 on table $2",
                               user_name, JoinMapped(*actions, ActionPB_Name, ", "), table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *actions = move(allowed_actions);

  return Status::OK();
}

string RangerClient::GetJavaClasspath() {
  Env* env = Env::Default();
  string exe;
  CHECK_OK(env->GetExecutablePath(&exe));
  const string bin_dir = DirName(exe);
  string jar_path = FLAGS_ranger_jar_path.empty() ?
    JoinPathSegments(bin_dir, "kudu-subprocess.jar") :
    FLAGS_ranger_jar_path;

  return Substitute("$0:$1", jar_path, FLAGS_ranger_config_path);
}

} // namespace ranger
} // namespace kudu
<commit_msg>[ranger] parameterize the Java binary path for the subprocess<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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
//
//   http://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.

#include "kudu/ranger/ranger_client.h"

#include <ostream>
#include <string>
#include <utility>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "kudu/common/table_util.h"
#include "kudu/gutil/macros.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/strings/join.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/ranger/ranger.pb.h"
#include "kudu/util/env.h"
#include "kudu/util/flag_tags.h"
#include "kudu/util/flag_validators.h"
#include "kudu/util/metrics.h"
#include "kudu/util/path_util.h"
#include "kudu/util/slice.h"
#include "kudu/util/status.h"
#include "kudu/util/subprocess.h"

DEFINE_string(ranger_java_path, "java",
              "The path where the Java binary was installed. If "
              "the value isn't an absolute path, it will be evaluated "
              "using the Kudu user's PATH.");
TAG_FLAG(ranger_java_path, experimental);

DEFINE_string(ranger_config_path, "",
              "Path to directory containing Ranger client configuration. "
              "Enables Ranger authorization provider. "
              "sentry_service_rpc_addresses must not be set if this is "
              "enabled.");
TAG_FLAG(ranger_config_path, experimental);

DEFINE_string(ranger_jar_path, "",
              "Path to the JAR file containing the Ranger subprocess.");
TAG_FLAG(ranger_jar_path, experimental);

METRIC_DEFINE_histogram(server, ranger_subprocess_execution_time_ms,
    "Ranger subprocess execution time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent executing the Ranger subprocess request, excluding "
    "time spent spent in the subprocess queues",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_inbound_queue_length,
    "Ranger subprocess inbound queue length",
    kudu::MetricUnit::kMessages,
    "Number of request messages in the Ranger subprocess' inbound request queue",
    kudu::MetricLevel::kInfo,
    1000, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_inbound_queue_time_ms,
    "Ranger subprocess inbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger subprocess' inbound request queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_outbound_queue_length,
    "Ranger subprocess outbound queue length",
    kudu::MetricUnit::kMessages,
    "Number of request messages in the Ranger subprocess' outbound response queue",
    kudu::MetricLevel::kInfo,
    1000, 1);
METRIC_DEFINE_histogram(server, ranger_subprocess_outbound_queue_time_ms,
    "Ranger subprocess outbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger subprocess' outbound response queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_server_inbound_queue_size_bytes,
    "Ranger server inbound queue size (bytes)",
    kudu::MetricUnit::kBytes,
    "Number of bytes in the inbound response queue of the Ranger server, recorded "
    "at the time a new response is read from the pipe and added to the inbound queue",
    kudu::MetricLevel::kInfo,
    4 * 1024 * 1024, 1);
METRIC_DEFINE_histogram(server, ranger_server_inbound_queue_time_ms,
    "Ranger server inbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger server's inbound response queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);
METRIC_DEFINE_histogram(server, ranger_server_outbound_queue_size_bytes,
    "Ranger server outbound queue size (bytes)",
    kudu::MetricUnit::kBytes,
    "Number of bytes in the outbound request queue of the Ranger server, recorded "
    "at the time a new request is added to the outbound request queue",
    kudu::MetricLevel::kInfo,
    4 * 1024 * 1024, 1);
METRIC_DEFINE_histogram(server, ranger_server_outbound_queue_time_ms,
    "Ranger server outbound queue time (ms)",
    kudu::MetricUnit::kMilliseconds,
    "Duration of time in ms spent in the Ranger server's outbound request queue",
    kudu::MetricLevel::kInfo,
    60000LU, 1);

namespace kudu {
namespace ranger {

using kudu::subprocess::SubprocessMetrics;
using std::move;
using std::string;
using std::unordered_set;
using std::vector;
using strings::Substitute;

static bool ValidateRangerJavaPath() {
  // First, check the specified path.
  if (!FLAGS_ranger_config_path.empty() &&
      !Env::Default()->FileExists(FLAGS_ranger_java_path)) {
    // Otherwise, since the specified path is not absolute, check if
    // the Java binary is on the PATH.
    string p;
    Status s = Subprocess::Call({ "which", FLAGS_ranger_java_path }, "", &p);
    if (!s.ok()) {
      LOG(ERROR) << Substitute("FLAGS_ranger_java_path has invalid java binary path: $0",
                                FLAGS_ranger_java_path);
      return false;
    }
  }
  return true;
}
GROUP_FLAG_VALIDATOR(ranger_java_path_flags, ValidateRangerJavaPath);

static const char* kUnauthorizedAction = "Unauthorized action";
static const char* kDenyNonRangerTableTemplate = "Denying action on table with invalid name $0. "
                                                 "Use 'kudu table rename_table' to rename it to "
                                                 "a Ranger-compatible name.";
const char* kMainClass = "org.apache.kudu.subprocess.ranger.RangerSubprocessMain";

#define HISTINIT(member, x) member = METRIC_##x.Instantiate(entity)
RangerSubprocessMetrics::RangerSubprocessMetrics(const scoped_refptr<MetricEntity>& entity) {
  HISTINIT(sp_inbound_queue_length, ranger_subprocess_inbound_queue_length);
  HISTINIT(sp_inbound_queue_time_ms, ranger_subprocess_inbound_queue_time_ms);
  HISTINIT(sp_outbound_queue_length, ranger_subprocess_outbound_queue_length);
  HISTINIT(sp_outbound_queue_time_ms, ranger_subprocess_outbound_queue_time_ms);
  HISTINIT(sp_execution_time_ms, ranger_subprocess_execution_time_ms);
  HISTINIT(server_inbound_queue_size_bytes, ranger_server_inbound_queue_size_bytes);
  HISTINIT(server_inbound_queue_time_ms, ranger_server_inbound_queue_time_ms);
  HISTINIT(server_outbound_queue_size_bytes, ranger_server_outbound_queue_size_bytes);
  HISTINIT(server_outbound_queue_time_ms, ranger_server_outbound_queue_time_ms);
}
#undef HISTINIT

RangerClient::RangerClient(const scoped_refptr<MetricEntity>& metric_entity) :
  subprocess_({ FLAGS_ranger_java_path, "-cp", GetJavaClasspath(), kMainClass },
              metric_entity) {}

Status RangerClient::Start() {
  VLOG(1) << "Initializing Ranger subprocess server";
  return subprocess_.Start();
}

// TODO(abukor): refactor to avoid code duplication
Status RangerClient::AuthorizeAction(const string& user_name,
                                     const ActionPB& action,
                                     const string& table_name) {
  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  RangerRequestPB* req = req_list.add_requests();

  req->set_action(action);
  req->set_database(db);
  req->set_table(tbl.ToString());

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  CHECK_EQ(1, resp_list.responses_size());
  if (resp_list.responses().begin()->allowed()) {
    return Status::OK();
  }

  LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on $2",
                             user_name, ActionPB_Name(action), table_name);
  return Status::NotAuthorized(kUnauthorizedAction);
}

Status RangerClient::AuthorizeActionMultipleColumns(const string& user_name,
                                                    const ActionPB& action,
                                                    const string& table_name,
                                                    unordered_set<string>* column_names) {
  DCHECK(!column_names->empty());

  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  for (const auto& col : *column_names) {
    auto req = req_list.add_requests();
    req->set_action(action);
    req->set_database(db);
    req->set_table(tbl.ToString());
    req->set_column(col);
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(column_names->size(), resp_list.responses_size());

  unordered_set<string> allowed_columns;
  for (auto i = 0; i < req_list.requests_size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_columns, move(req_list.requests(i).column()));
    }
  }

  if (allowed_columns.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on table $2",
                               user_name, ActionPB_Name(action), table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *column_names = move(allowed_columns);

  return Status::OK();
}

Status RangerClient::AuthorizeActionMultipleTables(const string& user_name,
                                                   const ActionPB& action,
                                                   unordered_set<string>* table_names) {
  if (table_names->empty()) {
    return Status::InvalidArgument("Empty set of tables");
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  vector<string> orig_table_names;

  for (const auto& table : *table_names) {
    string db;
    Slice tbl;

    auto s = ParseRangerTableIdentifier(table, &db, &tbl);
    if (PREDICT_TRUE(s.ok())) {
      orig_table_names.emplace_back(table);

      auto req = req_list.add_requests();
      req->set_action(action);
      req->set_database(db);
      req->set_table(tbl.ToString());
    } else {
      LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table);
    }
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(orig_table_names.size(), resp_list.responses_size());

  unordered_set<string> allowed_tables;
  for (auto i = 0; i < orig_table_names.size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_tables, move(orig_table_names[i]));
    }
  }

  if (allowed_tables.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform $1 on $2 tables",
                               user_name, ActionPB_Name(action), table_names->size());
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *table_names = move(allowed_tables);

  return Status::OK();
}

Status RangerClient::AuthorizeActions(const string& user_name,
                                      const string& table_name,
                                      unordered_set<ActionPB, ActionHash>* actions) {
  DCHECK(!actions->empty());

  string db;
  Slice tbl;

  auto s = ParseRangerTableIdentifier(table_name, &db, &tbl);
  if (PREDICT_FALSE(!s.ok())) {
    LOG(WARNING) << Substitute(kDenyNonRangerTableTemplate, table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  RangerRequestListPB req_list;
  RangerResponseListPB resp_list;
  req_list.set_user(user_name);

  for (const auto& action : *actions) {
    auto req = req_list.add_requests();
    req->set_action(action);
    req->set_database(db);
    req->set_table(tbl.ToString());
  }

  RETURN_NOT_OK(subprocess_.Execute(req_list, &resp_list));

  DCHECK_EQ(actions->size(), resp_list.responses_size());

  unordered_set<ActionPB, ActionHash> allowed_actions;
  for (auto i = 0; i < req_list.requests_size(); ++i) {
    if (resp_list.responses(i).allowed()) {
      EmplaceOrDie(&allowed_actions, move(req_list.requests(i).action()));
    }
  }

  if (allowed_actions.empty()) {
    LOG(WARNING) << Substitute("User $0 is not authorized to perform actions $1 on table $2",
                               user_name, JoinMapped(*actions, ActionPB_Name, ", "), table_name);
    return Status::NotAuthorized(kUnauthorizedAction);
  }

  *actions = move(allowed_actions);

  return Status::OK();
}

string RangerClient::GetJavaClasspath() {
  Env* env = Env::Default();
  string exe;
  CHECK_OK(env->GetExecutablePath(&exe));
  const string bin_dir = DirName(exe);
  string jar_path = FLAGS_ranger_jar_path.empty() ?
    JoinPathSegments(bin_dir, "kudu-subprocess.jar") :
    FLAGS_ranger_jar_path;

  return Substitute("$0:$1", jar_path, FLAGS_ranger_config_path);
}

} // namespace ranger
} // namespace kudu
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 2009-2011 Red Hat, Inc.
 *
 * 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
 *
 *    http://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.
 *
 ***************************************************************/

#include <axutil_error_default.h>
#include <axutil_log_default.h>
#include <axutil_thread_pool.h>
#include <axiom_xml_reader.h>
#include <axutil_file_handler.h>

#include "Axis2SoapProvider.h"

using namespace aviary::soap;

Axis2SoapProvider::Axis2SoapProvider(int _log_level, const char* _log_file, const char* _repo_path)
{
    if (_log_file) {
        m_log_file = _log_file;
    }
    if (_repo_path) {
        m_repo_path = _repo_path;
    }
    m_log_level = axutil_log_levels_t(_log_level);
    m_env = NULL;
    m_http_server = NULL;
    m_svr_thread = NULL;
    m_init = false;
    m_http_socket_read_timeout = AXIS2_HTTP_DEFAULT_SO_TIMEOUT;
}

Axis2SoapProvider::~Axis2SoapProvider()
{
    if (m_http_server) {
        axis2_transport_receiver_free(m_http_server, m_env);
    }

    if (m_svr_thread) {
        axis2_http_svr_thread_free(m_svr_thread, m_env);
    }

    if (m_env) {
        axutil_env_free(m_env);
    }

    axiom_xml_reader_cleanup();

}

bool
Axis2SoapProvider::init(int _port, int _read_timeout, std::string& _error)
{
    m_http_socket_read_timeout = _read_timeout;

    if (m_log_file.empty() || m_repo_path.empty()) {
        _error = "Log file or repo path is NULL";
        return false;
    }

    if (!m_init) {
        axutil_allocator_t* allocator = axutil_allocator_init(NULL);
        axutil_error_t *error = axutil_error_create(allocator);
        axutil_log_t *log = axutil_log_create(allocator, NULL, m_log_file.c_str());

        // TODO: not sure we need a TP but don't wanted to get tripped up by a NP
        // deeper in the stack
        axutil_thread_pool_t *thread_pool = axutil_thread_pool_init(allocator);
        axiom_xml_reader_init();
        m_env = axutil_env_create(allocator);
        axutil_error_init();

        m_env = axutil_env_create_with_error_log_thread_pool(allocator, error, log, thread_pool);
        m_env->log->level = m_log_level;

        axis2_status_t status = axutil_file_handler_access(m_repo_path.c_str(), AXIS2_R_OK);

        if (status != AXIS2_SUCCESS) {
			_error = m_repo_path;
			_error += " does not exist or insufficient permissions";
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,_error.c_str());
            return m_init;
        }

        m_http_server = axis2_http_server_create_with_file(m_env, m_repo_path.c_str(), _port);
        if (!m_http_server) {
			_error =  AXIS2_ERROR_GET_MESSAGE(m_env->error);
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI, "HTTP server create failed: %d: %s",
                            m_env->error->error_number,_error.c_str());
            return m_init;
        }

        m_svr_thread = createReceiver(m_env,m_http_server,_error);
        if (!m_svr_thread) {
			_error =  AXIS2_ERROR_GET_MESSAGE(m_env->error);
			AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI, "HTTP receiver create failed: %d: %s",
                            m_env->error->error_number,_error.c_str());
            return m_init;
        }

        m_init = true;
    }

    return m_init;

}

axis2_http_svr_thread_t*
Axis2SoapProvider::createReceiver(axutil_env_t* _env, axis2_transport_receiver_t* _server, std::string& /*_error */)
{

    axis2_http_server_impl_t *server_impl = NULL;
    axis2_http_worker_t *worker = NULL;

    server_impl = AXIS2_INTF_TO_IMPL(_server);
    server_impl->svr_thread = axis2_http_svr_thread_create(_env, server_impl->port);

    // shouldn't bother checking this for ST but we'll play along
    if(!server_impl->svr_thread) {
        AXIS2_LOG_ERROR(_env->log, AXIS2_LOG_SI, "unable to create server thread for port %d",
                server_impl->port);
        return NULL;
    }

    worker = axis2_http_worker_create(_env, server_impl->conf_ctx);
    if(!worker) {
        AXIS2_LOG_ERROR(_env->log, AXIS2_LOG_SI, "axis2 http worker creation failed");
        axis2_http_svr_thread_free(server_impl->svr_thread, _env);
        server_impl->svr_thread = NULL;
        return NULL;
    }

    axis2_http_worker_set_svr_port(worker, _env, server_impl->port);
    axis2_http_svr_thread_set_worker(server_impl->svr_thread, _env, worker);
    return server_impl->svr_thread;

}

SOCKET
Axis2SoapProvider::getListenerSocket()
{
    SOCKET socket = INVALID_SOCKET;
    if (m_svr_thread) {
        socket = m_svr_thread->listen_socket;
    }
    return socket;
}

bool
Axis2SoapProvider::processRequest(std::string& _error)
{
    if (!m_init) {
         _error = "Axis2SoapPovider has not been initialized yet";
        return false;
    }
    else {

        AXIS2_ENV_CHECK(m_env, AXIS2_FAILURE);

        int socket = INVALID_SOCKET;
        axis2_http_svr_thd_args_t *arg_list = NULL;

        if (INVALID_SOCKET == (socket = this->processAccept())) {
            _error = "Failed to accept connection";
            return false;
        }

        if(!m_svr_thread->worker)
        {
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,
                "Worker not ready yet. Cannot serve the request");
            axutil_network_handler_close_socket(m_env, socket);
            return false;
        }

        arg_list = (axis2_http_svr_thd_args_t *)AXIS2_MALLOC(m_env->allocator, sizeof(axis2_http_svr_thd_args_t));
        if(!arg_list)
        {
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,
                "Memory allocation error in the svr thread loop");
            return false;
        }

        arg_list->env = (axutil_env_t *)m_env;
        arg_list->socket = socket;
        arg_list->worker = m_svr_thread->worker;

        // single-threaded for DC
        invokeWorker(NULL, (void *)arg_list);
    }

    return true;
}

SOCKET Axis2SoapProvider::processAccept() {
    return (SOCKET)axutil_network_handler_svr_socket_accept(m_env, m_svr_thread->listen_socket);
}

void* Axis2SoapProvider::createServerConnection(axutil_env_t *thread_env, SOCKET socket) {
    return axis2_simple_http_svr_conn_create(thread_env, (SOCKET)socket);
}

void *AXIS2_THREAD_FUNC
Axis2SoapProvider::invokeWorker(
    axutil_thread_t * /*thd */,
    void *data)
{
    struct AXIS2_PLATFORM_TIMEB t1, t2;
    axis2_simple_http_svr_conn_t *svr_conn = NULL;
    axis2_http_simple_request_t *request = NULL;
    int millisecs = 0;
    double secs = 0;
    axis2_http_worker_t *tmp = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axutil_env_t *env = NULL;
    axis2_socket_t socket;
    axutil_env_t *thread_env = NULL;
    axis2_http_svr_thd_args_t *arg_list = NULL;

#ifndef WIN32
#ifdef AXIS2_SVR_MULTI_THREADED
    signal(SIGPIPE, SIG_IGN);
#endif
#endif

    if(!data)
    {
        return NULL;
    }
    arg_list = (axis2_http_svr_thd_args_t *)data;

    env = arg_list->env;
    thread_env = axutil_init_thread_env(env);

    IF_AXIS2_LOG_DEBUG_ENABLED(env->log)
    {
        AXIS2_PLATFORM_GET_TIME_IN_MILLIS(&t1);
    }

    socket = arg_list->socket;
    svr_conn = (axis2_simple_http_svr_conn_t*)(this->createServerConnection(thread_env, (int)socket));

    if(!svr_conn)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "creating simple_http_svr_connection failed");
        return NULL;
    }

    axis2_simple_http_svr_conn_set_rcv_timeout(svr_conn, thread_env, m_http_socket_read_timeout);

    /* read HTTPMethod, URL, HTTP Version and http headers. Leave the remaining in the stream */
    request = axis2_simple_http_svr_conn_read_request(svr_conn, thread_env);
    if(!request)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Could not create request");
        return NULL;
    }

    tmp = arg_list->worker;
    status = axis2_http_worker_process_request(tmp, thread_env, svr_conn, request);
    axis2_simple_http_svr_conn_free(svr_conn, thread_env);
    axis2_http_simple_request_free(request, thread_env);

    IF_AXIS2_LOG_DEBUG_ENABLED(env->log)
    {
        AXIS2_PLATFORM_GET_TIME_IN_MILLIS(&t2);
        millisecs = t2.millitm - t1.millitm;
        secs = difftime(t2.time, t1.time);
        if(millisecs < 0)
        {
            millisecs += 1000;
            secs--;
        }
        secs += millisecs / 1000.0;

        AXIS2_LOG_DEBUG(thread_env->log, AXIS2_LOG_SI, "Request processed in %.3f seconds", secs);
    }

    if(status == AXIS2_SUCCESS) {
        AXIS2_LOG_DEBUG(thread_env->log, AXIS2_LOG_SI, "Request served successfully");
    }
    else {
        AXIS2_LOG_WARNING(thread_env->log, AXIS2_LOG_SI, "Error occurred in processing request ");
    }

    // just ST here
    AXIS2_FREE(thread_env->allocator, arg_list);
    axutil_free_thread_env(thread_env);
    thread_env = NULL;

    return NULL;
}
<commit_msg>Connection cleanup on failed/timeout reads in aviary contrib to fail faster for clients<commit_after>/***************************************************************
 *
 * Copyright (C) 2009-2011 Red Hat, Inc.
 *
 * 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
 *
 *    http://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.
 *
 ***************************************************************/

#include <axutil_error_default.h>
#include <axutil_log_default.h>
#include <axutil_thread_pool.h>
#include <axiom_xml_reader.h>
#include <axutil_file_handler.h>

#include "Axis2SoapProvider.h"

using namespace aviary::soap;

Axis2SoapProvider::Axis2SoapProvider(int _log_level, const char* _log_file, const char* _repo_path)
{
    if (_log_file) {
        m_log_file = _log_file;
    }
    if (_repo_path) {
        m_repo_path = _repo_path;
    }
    m_log_level = axutil_log_levels_t(_log_level);
    m_env = NULL;
    m_http_server = NULL;
    m_svr_thread = NULL;
    m_init = false;
    m_http_socket_read_timeout = AXIS2_HTTP_DEFAULT_SO_TIMEOUT;
}

Axis2SoapProvider::~Axis2SoapProvider()
{
    if (m_http_server) {
        axis2_transport_receiver_free(m_http_server, m_env);
    }

    if (m_svr_thread) {
        axis2_http_svr_thread_free(m_svr_thread, m_env);
    }

    if (m_env) {
        axutil_env_free(m_env);
    }

    axiom_xml_reader_cleanup();

}

bool
Axis2SoapProvider::init(int _port, int _read_timeout, std::string& _error)
{
    m_http_socket_read_timeout = _read_timeout;

    if (m_log_file.empty() || m_repo_path.empty()) {
        _error = "Log file or repo path is NULL";
        return false;
    }

    if (!m_init) {
        axutil_allocator_t* allocator = axutil_allocator_init(NULL);
        axutil_error_t *error = axutil_error_create(allocator);
        axutil_log_t *log = axutil_log_create(allocator, NULL, m_log_file.c_str());

        // TODO: not sure we need a TP but don't wanted to get tripped up by a NP
        // deeper in the stack
        axutil_thread_pool_t *thread_pool = axutil_thread_pool_init(allocator);
        axiom_xml_reader_init();
        m_env = axutil_env_create(allocator);
        axutil_error_init();

        m_env = axutil_env_create_with_error_log_thread_pool(allocator, error, log, thread_pool);
        m_env->log->level = m_log_level;

        axis2_status_t status = axutil_file_handler_access(m_repo_path.c_str(), AXIS2_R_OK);

        if (status != AXIS2_SUCCESS) {
			_error = m_repo_path;
			_error += " does not exist or insufficient permissions";
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,_error.c_str());
            return m_init;
        }

        m_http_server = axis2_http_server_create_with_file(m_env, m_repo_path.c_str(), _port);
        if (!m_http_server) {
			_error =  AXIS2_ERROR_GET_MESSAGE(m_env->error);
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI, "HTTP server create failed: %d: %s",
                            m_env->error->error_number,_error.c_str());
            return m_init;
        }

        m_svr_thread = createReceiver(m_env,m_http_server,_error);
        if (!m_svr_thread) {
			_error =  AXIS2_ERROR_GET_MESSAGE(m_env->error);
			AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI, "HTTP receiver create failed: %d: %s",
                            m_env->error->error_number,_error.c_str());
            return m_init;
        }

        m_init = true;
    }

    return m_init;

}

axis2_http_svr_thread_t*
Axis2SoapProvider::createReceiver(axutil_env_t* _env, axis2_transport_receiver_t* _server, std::string& /*_error */)
{

    axis2_http_server_impl_t *server_impl = NULL;
    axis2_http_worker_t *worker = NULL;

    server_impl = AXIS2_INTF_TO_IMPL(_server);
    server_impl->svr_thread = axis2_http_svr_thread_create(_env, server_impl->port);

    // shouldn't bother checking this for ST but we'll play along
    if(!server_impl->svr_thread) {
        AXIS2_LOG_ERROR(_env->log, AXIS2_LOG_SI, "unable to create server thread for port %d",
                server_impl->port);
        return NULL;
    }

    worker = axis2_http_worker_create(_env, server_impl->conf_ctx);
    if(!worker) {
        AXIS2_LOG_ERROR(_env->log, AXIS2_LOG_SI, "axis2 http worker creation failed");
        axis2_http_svr_thread_free(server_impl->svr_thread, _env);
        server_impl->svr_thread = NULL;
        return NULL;
    }

    axis2_http_worker_set_svr_port(worker, _env, server_impl->port);
    axis2_http_svr_thread_set_worker(server_impl->svr_thread, _env, worker);
    return server_impl->svr_thread;

}

SOCKET
Axis2SoapProvider::getListenerSocket()
{
    SOCKET socket = INVALID_SOCKET;
    if (m_svr_thread) {
        socket = m_svr_thread->listen_socket;
    }
    return socket;
}

bool
Axis2SoapProvider::processRequest(std::string& _error)
{
    if (!m_init) {
         _error = "Axis2SoapPovider has not been initialized yet";
        return false;
    }
    else {

        AXIS2_ENV_CHECK(m_env, AXIS2_FAILURE);

        int socket = INVALID_SOCKET;
        axis2_http_svr_thd_args_t *arg_list = NULL;

        if (INVALID_SOCKET == (socket = this->processAccept())) {
            _error = "Failed to accept connection";
            return false;
        }

        if(!m_svr_thread->worker)
        {
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,
                "Worker not ready yet. Cannot serve the request");
            axutil_network_handler_close_socket(m_env, socket);
            return false;
        }

        arg_list = (axis2_http_svr_thd_args_t *)AXIS2_MALLOC(m_env->allocator, sizeof(axis2_http_svr_thd_args_t));
        if(!arg_list)
        {
            AXIS2_LOG_ERROR(m_env->log, AXIS2_LOG_SI,
                "Memory allocation error in the svr thread loop");
            return false;
        }

        arg_list->env = (axutil_env_t *)m_env;
        arg_list->socket = socket;
        arg_list->worker = m_svr_thread->worker;

        // single-threaded for DC
        invokeWorker(NULL, (void *)arg_list);
    }

    return true;
}

SOCKET Axis2SoapProvider::processAccept() {
    return (SOCKET)axutil_network_handler_svr_socket_accept(m_env, m_svr_thread->listen_socket);
}

void* Axis2SoapProvider::createServerConnection(axutil_env_t *thread_env, SOCKET socket) {
    return axis2_simple_http_svr_conn_create(thread_env, (SOCKET)socket);
}

void *AXIS2_THREAD_FUNC
Axis2SoapProvider::invokeWorker(
    axutil_thread_t * /*thd */,
    void *data)
{
    struct AXIS2_PLATFORM_TIMEB t1, t2;
    axis2_simple_http_svr_conn_t *svr_conn = NULL;
    axis2_http_simple_request_t *request = NULL;
    int millisecs = 0;
    double secs = 0;
    axis2_http_worker_t *tmp = NULL;
    axis2_status_t status = AXIS2_FAILURE;
    axutil_env_t *env = NULL;
    axis2_socket_t socket;
    axutil_env_t *thread_env = NULL;
    axis2_http_svr_thd_args_t *arg_list = NULL;

#ifndef WIN32
#ifdef AXIS2_SVR_MULTI_THREADED
    signal(SIGPIPE, SIG_IGN);
#endif
#endif

    if(!data)
    {
        return NULL;
    }
    arg_list = (axis2_http_svr_thd_args_t *)data;

    env = arg_list->env;
    thread_env = axutil_init_thread_env(env);

    IF_AXIS2_LOG_DEBUG_ENABLED(env->log)
    {
        AXIS2_PLATFORM_GET_TIME_IN_MILLIS(&t1);
    }

    socket = arg_list->socket;
    svr_conn = (axis2_simple_http_svr_conn_t*)(this->createServerConnection(thread_env, (int)socket));

    if(!svr_conn)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "creating simple_http_svr_connection failed");
        return NULL;
    }

    axis2_simple_http_svr_conn_set_rcv_timeout(svr_conn, thread_env, m_http_socket_read_timeout);

    /* read HTTPMethod, URL, HTTP Version and http headers. Leave the remaining in the stream */
    request = axis2_simple_http_svr_conn_read_request(svr_conn, thread_env);
    if(!request)
    {
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Could not create request");
        axis2_simple_http_svr_conn_free(svr_conn, thread_env);
        return NULL;
    }

    tmp = arg_list->worker;
    status = axis2_http_worker_process_request(tmp, thread_env, svr_conn, request);
    axis2_simple_http_svr_conn_free(svr_conn, thread_env);
    axis2_http_simple_request_free(request, thread_env);

    IF_AXIS2_LOG_DEBUG_ENABLED(env->log)
    {
        AXIS2_PLATFORM_GET_TIME_IN_MILLIS(&t2);
        millisecs = t2.millitm - t1.millitm;
        secs = difftime(t2.time, t1.time);
        if(millisecs < 0)
        {
            millisecs += 1000;
            secs--;
        }
        secs += millisecs / 1000.0;

        AXIS2_LOG_DEBUG(thread_env->log, AXIS2_LOG_SI, "Request processed in %.3f seconds", secs);
    }

    if(status == AXIS2_SUCCESS) {
        AXIS2_LOG_DEBUG(thread_env->log, AXIS2_LOG_SI, "Request served successfully");
    }
    else {
        AXIS2_LOG_WARNING(thread_env->log, AXIS2_LOG_SI, "Error occurred in processing request ");
    }

    // just ST here
    AXIS2_FREE(thread_env->allocator, arg_list);
    axutil_free_thread_env(thread_env);
    thread_env = NULL;

    return NULL;
}
<|endoftext|>


<commit_before>/*
 * NotebookPlots.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "NotebookPlots.hpp"
#include "../SessionPlots.hpp"

#include <boost/format.hpp>
#include <boost/foreach.hpp>

#include <core/system/FileMonitor.hpp>
#include <core/StringUtils.hpp>

#include <session/SessionModuleContext.hpp>

#include <r/RExec.hpp>
#include <r/session/RGraphics.hpp>

#define kPlotPrefix "_rs_chunk_plot_"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

class PlotState
{
public:
   PlotState():
      hasPlots(false),
      sexpMargins(R_NilValue)
   { }

   bool hasPlots;
   SEXP sexpMargins;
   r::sexp::Protect protect;
};

bool isPlotPath(const FilePath& path)
{
   return path.hasExtensionLowerCase(".png") &&
          string_utils::isPrefixOf(path.stem(), kPlotPrefix);
}

void processPlots(const FilePath& plotFolder, bool fireEvents)
{
   // ensure plot folder exists
   if (!plotFolder.exists())
      return;

   // collect plots from the folder
   std::vector<FilePath> folderContents;
   Error error = plotFolder.children(&folderContents);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& path, folderContents)
   {
      if (isPlotPath(path))
      {
         if (fireEvents)
            events().onPlotOutput(path);

         // clean up the plot so it isn't emitted twice
         error = path.removeIfExists();
         if (error)
            LOG_ERROR(error);
      }
   }
}

void removeGraphicsDevice(const FilePath& plotFolder,
                          boost::shared_ptr<PlotState> pPlotState)
{

   // restore the figure margins
   Error error = r::exec::RFunction("par", pPlotState->sexpMargins).call();
   if (error)
      LOG_ERROR(error);

   // turn off the graphics device -- this has the side effect of writing the
   // device's remaining output to files
   error = r::exec::RFunction("dev.off").call();
   if (error)
      LOG_ERROR(error);

#ifdef _WIN32
   // on Windows, turning off the PNG device writes an empty PNG file if no
   // plot output occurs; we avoid treating that empty file as an actual plot
   // by only emitting an event if a plot occurred.
   //
   // TODO: not all plot libraries cause the new plot hooks to invoke, so this
   // heuristic may cause us to miss a plot on Windows; we may need some
   // mechanism by which we can determine whether the device or its output is
   // empty.
   processPlots(plotFolder, hasPlots);
#else
   processPlots(plotFolder, true);
#endif
}

void onNewPlot(const FilePath& plotFolder,
               boost::shared_ptr<PlotState> pPlotState)
{
   pPlotState->hasPlots = true;
   processPlots(plotFolder, true);
}

void onConsolePrompt(const FilePath& plotFolder,
                     boost::shared_ptr<PlotState> pPlotState,
                     const std::string& )
{
   removeGraphicsDevice(plotFolder, pPlotState);

   module_context::events().onConsolePrompt.disconnect(
         boost::bind(onConsolePrompt, plotFolder, pPlotState, _1));

   plots::events().onNewPlot.disconnect(
         boost::bind(onNewPlot, pPlotState, _1));
}

} // anonymous namespace

// begins capturing plot output
core::Error beginPlotCapture(const FilePath& plotFolder)
{
   // clean up any stale plots from the folder
   std::vector<FilePath> folderContents;
   Error error = plotFolder.children(&folderContents);
   if (error)
      return error;

   BOOST_FOREACH(const core::FilePath& file, folderContents)
   {
      // remove if it looks like a plot
      if (isPlotPath(file))
      {
         error = file.remove();
         if (error)
         {
            // this is non-fatal
            LOG_ERROR(error);
         }
      }
   }

   // generate code for creating PNG device
   boost::format fmt("{ require(grDevices, quietly=TRUE); "
                     "  png(file = \"%1%/" kPlotPrefix "%%03d.png\", "
                     "  width = 6.5, height = 4, "
                     "  units=\"in\", res = 96 %2%)"
                     "}");

   // marker for content; this is necessary because on Windows, turning off
   // the png device writes an empty PNG file even if nothing was plotted, and
   // we need to avoid treating that file as though it were an actual plot
   boost::shared_ptr<PlotState> pPlotState = boost::make_shared<PlotState>();

   // create the PNG device
   error = r::exec::executeString(
         (fmt % string_utils::utf8ToSystem(plotFolder.absolutePath())
              % r::session::graphics::extraBitmapParams()).str());
   if (error)
      return error;

   // save old plot state
   r::exec::RFunction par("par");
   par.addParam("no.readonly", true);
   error = par.call(&pPlotState->sexpMargins, &pPlotState->protect);
   if (error)
      LOG_ERROR(error);

   // set notebook-friendly figure margins
   //                                          bot  left top  right
   error = r::exec::executeString("par(mar = c(5.1, 4.1, 2.1, 2.1))");
   if (error)
      LOG_ERROR(error);

   // complete the capture on the next console prompt
   module_context::events().onConsolePrompt.connect(
         boost::bind(onConsolePrompt, plotFolder, pPlotState, _1));

   plots::events().onNewPlot.connect(
         boost::bind(onNewPlot, plotFolder, pPlotState));

   return Success();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<commit_msg>use preserved SEXP to guard old plot state<commit_after>/*
 * NotebookPlots.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "NotebookPlots.hpp"
#include "../SessionPlots.hpp"

#include <boost/format.hpp>
#include <boost/foreach.hpp>

#include <core/system/FileMonitor.hpp>
#include <core/StringUtils.hpp>

#include <session/SessionModuleContext.hpp>

#include <r/RExec.hpp>
#include <r/RSexp.hpp>
#include <r/session/RGraphics.hpp>

#define kPlotPrefix "_rs_chunk_plot_"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

class PlotState
{
public:
   PlotState():
      hasPlots(false)
   { }

   bool hasPlots;
   r::sexp::PreservedSEXP sexpMargins;
};

bool isPlotPath(const FilePath& path)
{
   return path.hasExtensionLowerCase(".png") &&
          string_utils::isPrefixOf(path.stem(), kPlotPrefix);
}

void processPlots(const FilePath& plotFolder, bool fireEvents)
{
   // ensure plot folder exists
   if (!plotFolder.exists())
      return;

   // collect plots from the folder
   std::vector<FilePath> folderContents;
   Error error = plotFolder.children(&folderContents);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& path, folderContents)
   {
      if (isPlotPath(path))
      {
         if (fireEvents)
            events().onPlotOutput(path);

         // clean up the plot so it isn't emitted twice
         error = path.removeIfExists();
         if (error)
            LOG_ERROR(error);
      }
   }
}

void removeGraphicsDevice(const FilePath& plotFolder,
                          boost::shared_ptr<PlotState> pPlotState)
{

   // restore the figure margins
   Error error = r::exec::RFunction("par", pPlotState->sexpMargins).call();
   if (error)
      LOG_ERROR(error);

   // turn off the graphics device -- this has the side effect of writing the
   // device's remaining output to files
   error = r::exec::RFunction("dev.off").call();
   if (error)
      LOG_ERROR(error);

#ifdef _WIN32
   // on Windows, turning off the PNG device writes an empty PNG file if no
   // plot output occurs; we avoid treating that empty file as an actual plot
   // by only emitting an event if a plot occurred.
   //
   // TODO: not all plot libraries cause the new plot hooks to invoke, so this
   // heuristic may cause us to miss a plot on Windows; we may need some
   // mechanism by which we can determine whether the device or its output is
   // empty.
   processPlots(plotFolder, hasPlots);
#else
   processPlots(plotFolder, true);
#endif
}

void onNewPlot(const FilePath& plotFolder,
               boost::shared_ptr<PlotState> pPlotState)
{
   pPlotState->hasPlots = true;
   processPlots(plotFolder, true);
}

void onConsolePrompt(const FilePath& plotFolder,
                     boost::shared_ptr<PlotState> pPlotState,
                     const std::string& )
{
   removeGraphicsDevice(plotFolder, pPlotState);

   module_context::events().onConsolePrompt.disconnect(
         boost::bind(onConsolePrompt, plotFolder, pPlotState, _1));

   plots::events().onNewPlot.disconnect(
         boost::bind(onNewPlot, pPlotState, _1));
}

} // anonymous namespace

// begins capturing plot output
core::Error beginPlotCapture(const FilePath& plotFolder)
{
   // clean up any stale plots from the folder
   std::vector<FilePath> folderContents;
   Error error = plotFolder.children(&folderContents);
   if (error)
      return error;

   BOOST_FOREACH(const core::FilePath& file, folderContents)
   {
      // remove if it looks like a plot
      if (isPlotPath(file))
      {
         error = file.remove();
         if (error)
         {
            // this is non-fatal
            LOG_ERROR(error);
         }
      }
   }

   // generate code for creating PNG device
   boost::format fmt("{ require(grDevices, quietly=TRUE); "
                     "  png(file = \"%1%/" kPlotPrefix "%%03d.png\", "
                     "  width = 6.5, height = 4, "
                     "  units=\"in\", res = 96 %2%)"
                     "}");

   // marker for content; this is necessary because on Windows, turning off
   // the png device writes an empty PNG file even if nothing was plotted, and
   // we need to avoid treating that file as though it were an actual plot
   boost::shared_ptr<PlotState> pPlotState = boost::make_shared<PlotState>();

   // create the PNG device
   error = r::exec::executeString(
         (fmt % string_utils::utf8ToSystem(plotFolder.absolutePath())
              % r::session::graphics::extraBitmapParams()).str());
   if (error)
      return error;

   // save old plot state
   r::exec::RFunction par("par");
   par.addParam("no.readonly", true);
   r::sexp::Protect protect;
   SEXP sexpMargins;
   error = par.call(&sexpMargins, &protect);
   if (error)
      LOG_ERROR(error);

   // preserve until chunk is finished executing
   pPlotState->sexpMargins.set(sexpMargins);

   // set notebook-friendly figure margins
   //                                          bot  left top  right
   error = r::exec::executeString("par(mar = c(5.1, 4.1, 2.1, 2.1))");
   if (error)
      LOG_ERROR(error);

   // complete the capture on the next console prompt
   module_context::events().onConsolePrompt.connect(
         boost::bind(onConsolePrompt, plotFolder, pPlotState, _1));

   plots::events().onNewPlot.connect(
         boost::bind(onNewPlot, plotFolder, pPlotState));

   return Success();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<|endoftext|>