<commit_before>/*
* Copyright (c)2015 - 2016 Oasis LMF Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the
*     distribution.
*
*   * Neither the original author of this software nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
Convert fm output to csv
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#if defined(_MSC_VER)
#include "../wingetopt/wingetopt.h"
#else
#include <unistd.h>
#endif

#include "../include/oasis.h"

using namespace std;

bool skipheader = false;
bool fullprecision = false;

void doit()
{

	int fmstream_type;

	size_t i = fread(&fmstream_type, sizeof(fmstream_type), 1, stdin);

	int stream_type = fmstream_type & fmstream_id ;

	if (stream_type != fmstream_id) {
		fprintf(stderr, "%s: Not a fm stream type\n",__func__);
		exit(-1);
	}
	stream_type = streamno_mask & fmstream_type;
	if (stream_type != 1 ) {
		fprintf(stderr, "%s: Unsupported fm stream type: %s\n", __func__, stream_type);
		exit(-1);
	}

	int sample_size = 0;
	i = fread(&sample_size, sizeof(sample_size), 1, stdin);

	if (skipheader == false) 	printf ("event_id,output_id,sidx,loss\n");

	fmlevelhdr p;
	i = fread(&p, sizeof(fmlevelhdr), 1, stdin);
	int count = 0;
	while (i != 0) {
		fmlevelrec q;
		i = fread(&q, sizeof(fmlevelrec), 1, stdin);
		while (i != 0) {
			count++;
			if (q.sidx == 0) break;
			if (fullprecision) printf("%d,%d,%d,%f\n", p.event_id, p.output_id, q.sidx, q.loss);
			else printf("%d,%d,%d,%.2f\n", p.event_id, p.output_id, q.sidx, q.loss);
			i = fread(&q, sizeof(fmlevelrec), 1, stdin);
		}
		if (i) i = fread(&p, sizeof(fmlevelhdr), 1, stdin);
	}

}

void help()
{
	fprintf(stderr,
	     "-s skip header\n"
		"-f full precision\n"
		"-v version\n"
		"-h help\n"
	) ;
}

int main(int argc, char* argv[])
{

	int opt;

	while ((opt = getopt(argc, argv, "vhfsI:O:")) != -1) {
		switch (opt) {
		case 's':
			skipheader = true;
			break;
		case 'f':
			fullprecision = true;
			break;
		case 'v':
			fprintf(stderr, "%s : version: %s\n", argv[0], VERSION);
			exit(EXIT_FAILURE);
			break;
		case 'h':
			help();
			exit(EXIT_FAILURE);
		}
	}

	initstreams("", "");
	doit();
	return 0;
}
<commit_msg>fixed printf bug<commit_after>/*
* Copyright (c)2015 - 2016 Oasis LMF Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the
*     distribution.
*
*   * Neither the original author of this software nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
Convert fm output to csv
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#if defined(_MSC_VER)
#include "../wingetopt/wingetopt.h"
#else
#include <unistd.h>
#endif

#include "../include/oasis.h"

using namespace std;

bool skipheader = false;
bool fullprecision = false;

void doit()
{

	int fmstream_type;

	size_t i = fread(&fmstream_type, sizeof(fmstream_type), 1, stdin);

	int stream_type = fmstream_type & fmstream_id ;

	if (stream_type != fmstream_id) {
		fprintf(stderr, "%s: Not a fm stream type\n",__func__);
		exit(-1);
	}
	stream_type = streamno_mask & fmstream_type;
	if (stream_type != 1 ) {
		fprintf(stderr, "%s: Unsupported fm stream type: %d\n", __func__, stream_type);
		exit(-1);
	}

	int sample_size = 0;
	i = fread(&sample_size, sizeof(sample_size), 1, stdin);

	if (skipheader == false) 	printf ("event_id,output_id,sidx,loss\n");

	fmlevelhdr p;
	i = fread(&p, sizeof(fmlevelhdr), 1, stdin);
	int count = 0;
	while (i != 0) {
		fmlevelrec q;
		i = fread(&q, sizeof(fmlevelrec), 1, stdin);
		while (i != 0) {
			count++;
			if (q.sidx == 0) break;
			if (fullprecision) printf("%d,%d,%d,%f\n", p.event_id, p.output_id, q.sidx, q.loss);
			else printf("%d,%d,%d,%.2f\n", p.event_id, p.output_id, q.sidx, q.loss);
			i = fread(&q, sizeof(fmlevelrec), 1, stdin);
		}
		if (i) i = fread(&p, sizeof(fmlevelhdr), 1, stdin);
	}

}

void help()
{
	fprintf(stderr,
	     "-s skip header\n"
		"-f full precision\n"
		"-v version\n"
		"-h help\n"
	) ;
}

int main(int argc, char* argv[])
{

	int opt;

	while ((opt = getopt(argc, argv, "vhfsI:O:")) != -1) {
		switch (opt) {
		case 's':
			skipheader = true;
			break;
		case 'f':
			fullprecision = true;
			break;
		case 'v':
			fprintf(stderr, "%s : version: %s\n", argv[0], VERSION);
			exit(EXIT_FAILURE);
			break;
		case 'h':
			help();
			exit(EXIT_FAILURE);
		}
	}

	initstreams("", "");
	doit();
	return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: QTableWindow.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 16:22:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/
#ifndef DBAUI_QUERY_TABLEWINDOW_HXX
#define DBAUI_QUERY_TABLEWINDOW_HXX

#ifndef DBAUI_TABLEWINDOW_HXX
#include "TableWindow.hxx"
#endif
#ifndef DBAUI_QUERY_TABLEWINDOWDATA_HXX
#include "QTableWindowData.hxx"
#endif
#ifndef DBAUI_TABLEFIELDDESC_HXX
#include "TableFieldDescription.hxx"
#endif
#ifndef _RTTI_HXX
#include <tools/rtti.hxx>
#endif

namespace dbaui
{
    //==================================================================
    class OQueryTableWindow : public OTableWindow
    {
        sal_Int32           m_nAliasNum;
        ::rtl::OUString     m_strInitialAlias;
    public:
        TYPEINFO();
        OQueryTableWindow( Window* pParent, OQueryTableWindowData* pTabWinData, sal_Unicode* pszInitialAlias = NULL );
        virtual ~OQueryTableWindow();

        ::rtl::OUString GetAliasName() const
        {
            return static_cast<OQueryTableWindowData*>(GetData())->GetAliasName();
        }
        void            SetAliasName(const ::rtl::OUString& strNewAlias)
        {
            static_cast<OQueryTableWindowData*>(GetData())->SetAliasName(strNewAlias);
        }

        // spaeter Constructor, die Basisklasse ERZEUGT beim ersten Aufruf die Listbox
        virtual BOOL    Init();

        sal_Int32       GetAliasNum() const { return m_nAliasNum; }

        BOOL            ExistsField(const ::rtl::OUString& strFieldName, OTableFieldDescRef& rInfo);
        BOOL            ExistsAVisitedConn() const;

        virtual ::rtl::OUString     GetName() const { return GetWinName(); }

    protected:
        virtual void    KeyInput( const KeyEvent& rEvt );

        virtual void    OnEntryDoubleClicked(SvLBoxEntry* pEntry);
            // wird aus dem DoubleClickHdl der ListBox heraus aufgerufen
        /** delete the user data with the equal type as created within createUserData
            @param  _pUserData
                The user data store in the listbox entries. Created with a call to createUserData.
                _pUserData may be <NULL/>.
        */
        virtual void deleteUserData(void*& _pUserData);

        /** creates user information that will be append at the ListBoxentry
            @param  _xColumn
                The corresponding column, can be <NULL/>.
            @param  _bPrimaryKey
                <TRUE/> when the column belongs to the primary key
            @return
                the user data which will be append at the listbox entry, may be <NULL/>
        */
        virtual void* createUserData(const ::com::sun::star::uno::Reference<
                                    ::com::sun::star::beans::XPropertySet>& _xColumn,
                                    bool _bPrimaryKey);

    };
}
#endif // DBAUI_QUERY_TABLEWINDOW_HXX

<commit_msg>INTEGRATION: CWS qiq (1.6.122); FILE MERGED 2006/07/03 19:48:00 fs 1.6.122.2: #i51143# don't allow to add queries to the designer which do not produce a result set 2006/05/10 11:05:50 fs 1.6.122.1: #i51143# also allow for queries in queries<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: QTableWindow.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-07-10 15:40:58 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/
#ifndef DBAUI_QUERY_TABLEWINDOW_HXX
#define DBAUI_QUERY_TABLEWINDOW_HXX

#ifndef DBAUI_TABLEWINDOW_HXX
#include "TableWindow.hxx"
#endif
#ifndef DBAUI_QUERY_TABLEWINDOWDATA_HXX
#include "QTableWindowData.hxx"
#endif
#ifndef DBAUI_TABLEFIELDDESC_HXX
#include "TableFieldDescription.hxx"
#endif
#ifndef _RTTI_HXX
#include <tools/rtti.hxx>
#endif

namespace dbaui
{
    //==================================================================
    class OQueryTableWindow : public OTableWindow
    {
        sal_Int32           m_nAliasNum;
        ::rtl::OUString     m_strInitialAlias;
    public:
        TYPEINFO();
        OQueryTableWindow( Window* pParent, OQueryTableWindowData* pTabWinData, sal_Unicode* pszInitialAlias = NULL );
        virtual ~OQueryTableWindow();

        ::rtl::OUString GetAliasName() const
        {
            return static_cast<OQueryTableWindowData*>(GetData())->GetAliasName();
        }
        void            SetAliasName(const ::rtl::OUString& strNewAlias)
        {
            static_cast<OQueryTableWindowData*>(GetData())->SetAliasName(strNewAlias);
        }

        // spaeter Constructor, die Basisklasse ERZEUGT beim ersten Aufruf die Listbox
        virtual BOOL    Init();

        sal_Int32       GetAliasNum() const { return m_nAliasNum; }

        BOOL            ExistsField(const ::rtl::OUString& strFieldName, OTableFieldDescRef& rInfo);
        BOOL            ExistsAVisitedConn() const;

        virtual ::rtl::OUString     GetName() const { return GetWinName(); }

    protected:
        virtual void    KeyInput( const KeyEvent& rEvt );

        virtual void    OnEntryDoubleClicked(SvLBoxEntry* pEntry);
            // wird aus dem DoubleClickHdl der ListBox heraus aufgerufen
        /** delete the user data with the equal type as created within createUserData
            @param  _pUserData
                The user data store in the listbox entries. Created with a call to createUserData.
                _pUserData may be <NULL/>.
        */
        virtual void deleteUserData(void*& _pUserData);

        /** creates user information that will be append at the ListBoxentry
            @param  _xColumn
                The corresponding column, can be <NULL/>.
            @param  _bPrimaryKey
                <TRUE/> when the column belongs to the primary key
            @return
                the user data which will be append at the listbox entry, may be <NULL/>
        */
        virtual void* createUserData(const ::com::sun::star::uno::Reference<
                                    ::com::sun::star::beans::XPropertySet>& _xColumn,
                                    bool _bPrimaryKey);

        virtual bool    allowQueries() const;
        virtual void    onNoColumns_throw();
    };
}
#endif // DBAUI_QUERY_TABLEWINDOW_HXX

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: log_module.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 14:58:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/

#ifndef EXTENSIONS_LOG_MODULE_HXX
#define EXTENSIONS_LOG_MODULE_HXX

#ifndef COMPHELPER_INC_COMPHELPER_COMPONENTMODULE_HXX
#include <comphelper/componentmodule.hxx>
#endif

//........................................................................
namespace logging
{
//........................................................................

    DECLARE_COMPONENT_MODULE( LogModule, LogModuleClient )

//........................................................................
} // namespace logging
//........................................................................

#endif // EXTENSIONS_LOG_MODULE_HXX

<commit_msg>INTEGRATION: CWS changefileheader (1.2.134); FILE MERGED 2008/04/01 15:15:07 thb 1.2.134.2: #i85898# Stripping all external header guards 2008/03/31 12:31:31 rt 1.2.134.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: log_module.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef EXTENSIONS_LOG_MODULE_HXX
#define EXTENSIONS_LOG_MODULE_HXX

#include <comphelper/componentmodule.hxx>

//........................................................................
namespace logging
{
//........................................................................

    DECLARE_COMPONENT_MODULE( LogModule, LogModuleClient )

//........................................................................
} // namespace logging
//........................................................................

#endif // EXTENSIONS_LOG_MODULE_HXX

<|endoftext|>


<commit_before>#include <map>
#include <vector>
#include <thread>
#include <mutex>

#include <assert.h>
#include <string.h>
#include <unistd.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#define BITCOIN_UA_LENGTH 24
#define BITCOIN_UA {'/', 'R', 'e', 'l', 'a', 'y', 'N', 'e', 't', 'w', 'o', 'r', 'k', 'C', 'l', 'i', 'e', 'n', 't', ':', '4', '2', '/', '\0'}

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"
#include "p2pclient.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient {
private:
	RELAY_DECLARE_CLASS_VARS

	const char* server_host;

	const std::function<void (std::vector<unsigned char>&)> provide_block;
	const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)> provide_transaction;

	int sock;
	std::mutex send_mutex;
	std::thread* net_thread, *new_thread;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (std::vector<unsigned char>&)>& provide_block_in,
						const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in)
			: RELAY_DECLARE_CONSTRUCTOR_EXTENDS,
			server_host(serverHostIn), provide_block(provide_block_in), provide_transaction(provide_transaction_in),
			sock(0), net_thread(NULL), new_thread(NULL) {
		send_mutex.lock();
		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

	RelayNetworkClient() : RELAY_DECLARE_CONSTRUCTOR_EXTENDS {} // Fake...

	RELAY_DECLARE_FUNCTIONS

private:
	void reconnect(std::string disconnectReason, bool alreadyLocked=false) {
		if (!alreadyLocked)
			send_mutex.lock();

		if (sock) {
			printf("Closing relay socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
			#ifndef WIN32
				errno = 0;
			#endif
			close(sock);
		}

		sleep(1);

		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

	static void do_connect(RelayNetworkClient* me) {
		me->send_mutex.lock();

		if (me->net_thread)
			me->net_thread->join();
		me->net_thread = me->new_thread;

		me->sock = socket(AF_INET6, SOCK_STREAM, 0);
		if (me->sock <= 0)
			return me->reconnect("unable to create socket", true);

		sockaddr_in6 addr;
		if (!lookup_address(me->server_host, &addr))
			return me->reconnect("unable to lookup host", true);

		int v6only = 0;
		setsockopt(me->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		addr.sin6_port = htons(8336);
		if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
			return me->reconnect("failed to connect()", true);

		#ifdef WIN32
			unsigned long nonblocking = 0;
			ioctlsocket(me->sock, FIONBIO, &nonblocking);
		#else
			fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);
		#endif

		#ifdef X86_BSD
			int nosigpipe = 1;
			setsockopt(me->sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
		#endif

		me->net_process();
	}

	void net_process() {
		recv_tx_cache.clear();
		send_tx_cache.clear();

		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		if (send_all(sock, (char*)&version_header, sizeof(version_header)) != sizeof(version_header))
			return reconnect("failed to write version header", true);
		if (send_all(sock, VERSION_STRING, strlen(VERSION_STRING)) != strlen(VERSION_STRING))
			return reconnect("failed to write version string", true);

		int nodelay = 1;
		setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

		if (errno)
			return reconnect("error during connect", true);

		send_mutex.unlock();

		while (true) {
			relay_msg_header header;
			if (read_all(sock, (char*)&header, 4*3) != 4*3)
				return reconnect("failed to read message header");

			if (header.magic != RELAY_MAGIC_BYTES)
				return reconnect("invalid magic bytes");

			uint32_t message_size = ntohl(header.length);

			if (message_size > 1000000)
				return reconnect("got message too large");

			if (header.type == VERSION_TYPE) {
				char data[message_size];
				if (read_all(sock, data, message_size) < (int64_t)(message_size))
					return reconnect("failed to read version message");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					return reconnect("unknown version string");
				else
					printf("Connected to relay node with protocol version %s\n", VERSION_STRING);
			} else if (header.type == MAX_VERSION_TYPE) {
				char data[message_size];
				if (read_all(sock, data, message_size) < (int64_t)(message_size))
					return reconnect("failed to read max_version string");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					printf("Relay network is using a later version (PLEASE UPGRADE)\n");
				else
					return reconnect("got MAX_VERSION of same version as us");
			} else if (header.type == BLOCK_TYPE) {
				auto res = decompressRelayBlock(sock, message_size);
				if (std::get<2>(res))
					return reconnect(std::get<2>(res));

				provide_block(*std::get<1>(res));

				std::vector<unsigned char> fullhash(32);
				CSHA256 hash; // Probably not BE-safe
				hash.Write(&(*std::get<1>(res))[sizeof(struct bitcoin_msg_header)], 80).Finalize(&fullhash[0]);
				hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
				struct tm tm;
				time_t now = time(NULL);
				gmtime_r(&now, &tm);
				printf("[%d-%02d-%02d %02d:%02d:%02d+00] ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" recv'd, size %lu with %u bytes on the wire\n", (unsigned long)std::get<1>(res)->size() - sizeof(bitcoin_msg_header), std::get<0>(res));
			} else if (header.type == END_BLOCK_TYPE) {
			} else if (header.type == TRANSACTION_TYPE) {
				if (message_size > MAX_RELAY_TRANSACTION_BYTES && (recv_tx_cache.flagCount() >= MAX_EXTRA_OVERSIZE_TRANSACTIONS || message_size > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES)) {
					printf("Freely relayed tx of size %u, with %u oversize txn already present\n", message_size, recv_tx_cache.flagCount());
					return reconnect("got freely relayed transaction too large");
				}

				auto tx = std::make_shared<std::vector<unsigned char> > (message_size);
				if (read_all(sock, (char*)&(*tx)[0], message_size) < (int64_t)(message_size))
					return reconnect("failed to read loose transaction data");

				recv_tx_cache.add(tx, message_size > MAX_RELAY_TRANSACTION_BYTES);
				provide_transaction(tx);
				printf("Received transaction of size %u from relay server\n", message_size);
			} else
				return reconnect("got unknown message type");
		}
	}

public:
	void receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx) {
		#ifndef FOR_VALGRIND
			if (!send_mutex.try_lock())
				return;
		#else
			send_mutex.lock();
		#endif

		if (send_tx_cache.contains(tx) ||
				(tx->size() > MAX_RELAY_TRANSACTION_BYTES &&
					(send_tx_cache.flagCount() >= MAX_EXTRA_OVERSIZE_TRANSACTIONS || tx->size() > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES))) {
			send_mutex.unlock();
			return;
		}

		std::vector<unsigned char> msg(sizeof(struct relay_msg_header));
		struct relay_msg_header *header = (struct relay_msg_header*)&msg[0];
		header->magic = RELAY_MAGIC_BYTES;
		header->type = TRANSACTION_TYPE;
		header->length = htonl(tx->size());
		msg.insert(msg.end(), tx->begin(), tx->end());
		if (send_all(sock, (char*)&msg[0], msg.size()) != int(msg.size()))
			printf("Error sending transaction to relay server\n");
		else {
			send_tx_cache.add(tx, tx->size() > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES);
			printf("Sent transaction of size %lu to relay server\n", (unsigned long)tx->size());
		}

		send_mutex.unlock();
	}

	void receive_block(const std::vector<unsigned char>& block) {
		#ifndef FOR_VALGRIND
			if (!send_mutex.try_lock())
				return;
		#else
			send_mutex.lock();
		#endif

		auto compressed_block = compressRelayBlock(block);
		if (!compressed_block->size()) {
			printf("Failed to process block from bitcoind\n");
			send_mutex.unlock();
			return;
		}

		if (send_all(sock, (char*)&(*compressed_block)[0], compressed_block->size()) != int(compressed_block->size()))
			printf("Error sending block to relay server\n");
		else {
			struct relay_msg_header header = { RELAY_MAGIC_BYTES, END_BLOCK_TYPE, 0 };
			if (send_all(sock, (char*)&header, sizeof(header)) != int(sizeof(header)))
				printf("Error sending end block message to relay server\n");
			else {
				std::vector<unsigned char> fullhash(32);
				CSHA256 hash; // Probably not BE-safe
				hash.Write(&block[sizeof(struct bitcoin_msg_header)], 80).Finalize(&fullhash[0]);
				hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" sent, size %lu with %lu bytes on the wire\n", (unsigned long)block.size(), (unsigned long)compressed_block->size());
			}
		}

		send_mutex.unlock();
	}
};

class P2PClient : public P2PRelayer {
public:
	P2PClient(const char* serverHostIn, uint16_t serverPortIn,
				const std::function<void (std::vector<unsigned char>&, struct timeval)>& provide_block_in,
				const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in) :
			P2PRelayer(serverHostIn, serverPortIn, provide_block_in, provide_transaction_in) {};

private:
	bool send_version() {
		struct bitcoin_version_with_header version_msg;
		version_msg.version.start.timestamp = htole64(time(0));
		version_msg.version.start.user_agent_length = BITCOIN_UA_LENGTH; // Work around apparent gcc bug
		return send_message("version", (unsigned char*)&version_msg, sizeof(struct bitcoin_version));
	}
};

int main(int argc, char** argv) {
	if (argc != 4) {
		printf("USAGE: %s RELAY_SERVER BITCOIND_ADDRESS BITCOIND_PORT\n", argv[0]);
		return -1;
	}

#ifdef WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2), &wsaData))
		return -1;
#endif

	RelayNetworkClient* relayClient;
	P2PClient p2p(argv[2], std::stoul(argv[3]),
					[&](std::vector<unsigned char>& bytes, struct timeval) { relayClient->receive_block(bytes); },
					[&](std::shared_ptr<std::vector<unsigned char> >& bytes) { relayClient->receive_transaction(bytes); });
	relayClient = new RelayNetworkClient(argv[1],
										[&](std::vector<unsigned char>& bytes) { p2p.receive_block(bytes); },
										[&](std::shared_ptr<std::vector<unsigned char> >& bytes) { p2p.receive_transaction(bytes); });

	while (true) { sleep(1000); }
}
<commit_msg>Fix print warning<commit_after>#include <map>
#include <vector>
#include <thread>
#include <mutex>

#include <assert.h>
#include <string.h>
#include <unistd.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#define BITCOIN_UA_LENGTH 24
#define BITCOIN_UA {'/', 'R', 'e', 'l', 'a', 'y', 'N', 'e', 't', 'w', 'o', 'r', 'k', 'C', 'l', 'i', 'e', 'n', 't', ':', '4', '2', '/', '\0'}

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"
#include "p2pclient.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient {
private:
	RELAY_DECLARE_CLASS_VARS

	const char* server_host;

	const std::function<void (std::vector<unsigned char>&)> provide_block;
	const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)> provide_transaction;

	int sock;
	std::mutex send_mutex;
	std::thread* net_thread, *new_thread;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (std::vector<unsigned char>&)>& provide_block_in,
						const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in)
			: RELAY_DECLARE_CONSTRUCTOR_EXTENDS,
			server_host(serverHostIn), provide_block(provide_block_in), provide_transaction(provide_transaction_in),
			sock(0), net_thread(NULL), new_thread(NULL) {
		send_mutex.lock();
		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

	RelayNetworkClient() : RELAY_DECLARE_CONSTRUCTOR_EXTENDS {} // Fake...

	RELAY_DECLARE_FUNCTIONS

private:
	void reconnect(std::string disconnectReason, bool alreadyLocked=false) {
		if (!alreadyLocked)
			send_mutex.lock();

		if (sock) {
			printf("Closing relay socket, %s (%i: %s)\n", disconnectReason.c_str(), errno, errno ? strerror(errno) : "");
			#ifndef WIN32
				errno = 0;
			#endif
			close(sock);
		}

		sleep(1);

		new_thread = new std::thread(do_connect, this);
		send_mutex.unlock();
	}

	static void do_connect(RelayNetworkClient* me) {
		me->send_mutex.lock();

		if (me->net_thread)
			me->net_thread->join();
		me->net_thread = me->new_thread;

		me->sock = socket(AF_INET6, SOCK_STREAM, 0);
		if (me->sock <= 0)
			return me->reconnect("unable to create socket", true);

		sockaddr_in6 addr;
		if (!lookup_address(me->server_host, &addr))
			return me->reconnect("unable to lookup host", true);

		int v6only = 0;
		setsockopt(me->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		addr.sin6_port = htons(8336);
		if (connect(me->sock, (struct sockaddr*)&addr, sizeof(addr)))
			return me->reconnect("failed to connect()", true);

		#ifdef WIN32
			unsigned long nonblocking = 0;
			ioctlsocket(me->sock, FIONBIO, &nonblocking);
		#else
			fcntl(me->sock, F_SETFL, fcntl(me->sock, F_GETFL) & ~O_NONBLOCK);
		#endif

		#ifdef X86_BSD
			int nosigpipe = 1;
			setsockopt(me->sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&nosigpipe, sizeof(int));
		#endif

		me->net_process();
	}

	void net_process() {
		recv_tx_cache.clear();
		send_tx_cache.clear();

		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		if (send_all(sock, (char*)&version_header, sizeof(version_header)) != sizeof(version_header))
			return reconnect("failed to write version header", true);
		if (send_all(sock, VERSION_STRING, strlen(VERSION_STRING)) != strlen(VERSION_STRING))
			return reconnect("failed to write version string", true);

		int nodelay = 1;
		setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));

		if (errno)
			return reconnect("error during connect", true);

		send_mutex.unlock();

		while (true) {
			relay_msg_header header;
			if (read_all(sock, (char*)&header, 4*3) != 4*3)
				return reconnect("failed to read message header");

			if (header.magic != RELAY_MAGIC_BYTES)
				return reconnect("invalid magic bytes");

			uint32_t message_size = ntohl(header.length);

			if (message_size > 1000000)
				return reconnect("got message too large");

			if (header.type == VERSION_TYPE) {
				char data[message_size];
				if (read_all(sock, data, message_size) < (int64_t)(message_size))
					return reconnect("failed to read version message");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					return reconnect("unknown version string");
				else
					printf("Connected to relay node with protocol version %s\n", VERSION_STRING);
			} else if (header.type == MAX_VERSION_TYPE) {
				char data[message_size];
				if (read_all(sock, data, message_size) < (int64_t)(message_size))
					return reconnect("failed to read max_version string");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					printf("Relay network is using a later version (PLEASE UPGRADE)\n");
				else
					return reconnect("got MAX_VERSION of same version as us");
			} else if (header.type == BLOCK_TYPE) {
				auto res = decompressRelayBlock(sock, message_size);
				if (std::get<2>(res))
					return reconnect(std::get<2>(res));

				provide_block(*std::get<1>(res));

				std::vector<unsigned char> fullhash(32);
				CSHA256 hash; // Probably not BE-safe
				hash.Write(&(*std::get<1>(res))[sizeof(struct bitcoin_msg_header)], 80).Finalize(&fullhash[0]);
				hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
				struct tm tm;
				time_t now = time(NULL);
				gmtime_r(&now, &tm);
				printf("[%d-%02d-%02d %02d:%02d:%02d+00] ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" recv'd, size %lu with %u bytes on the wire\n", (unsigned long)std::get<1>(res)->size() - sizeof(bitcoin_msg_header), std::get<0>(res));
			} else if (header.type == END_BLOCK_TYPE) {
			} else if (header.type == TRANSACTION_TYPE) {
				if (message_size > MAX_RELAY_TRANSACTION_BYTES && (recv_tx_cache.flagCount() >= MAX_EXTRA_OVERSIZE_TRANSACTIONS || message_size > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES)) {
					printf("Freely relayed tx of size %u, with %lu oversize txn already present\n", message_size, recv_tx_cache.flagCount());
					return reconnect("got freely relayed transaction too large");
				}

				auto tx = std::make_shared<std::vector<unsigned char> > (message_size);
				if (read_all(sock, (char*)&(*tx)[0], message_size) < (int64_t)(message_size))
					return reconnect("failed to read loose transaction data");

				recv_tx_cache.add(tx, message_size > MAX_RELAY_TRANSACTION_BYTES);
				provide_transaction(tx);
				printf("Received transaction of size %u from relay server\n", message_size);
			} else
				return reconnect("got unknown message type");
		}
	}

public:
	void receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx) {
		#ifndef FOR_VALGRIND
			if (!send_mutex.try_lock())
				return;
		#else
			send_mutex.lock();
		#endif

		if (send_tx_cache.contains(tx) ||
				(tx->size() > MAX_RELAY_TRANSACTION_BYTES &&
					(send_tx_cache.flagCount() >= MAX_EXTRA_OVERSIZE_TRANSACTIONS || tx->size() > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES))) {
			send_mutex.unlock();
			return;
		}

		std::vector<unsigned char> msg(sizeof(struct relay_msg_header));
		struct relay_msg_header *header = (struct relay_msg_header*)&msg[0];
		header->magic = RELAY_MAGIC_BYTES;
		header->type = TRANSACTION_TYPE;
		header->length = htonl(tx->size());
		msg.insert(msg.end(), tx->begin(), tx->end());
		if (send_all(sock, (char*)&msg[0], msg.size()) != int(msg.size()))
			printf("Error sending transaction to relay server\n");
		else {
			send_tx_cache.add(tx, tx->size() > MAX_RELAY_OVERSIZE_TRANSACTION_BYTES);
			printf("Sent transaction of size %lu to relay server\n", (unsigned long)tx->size());
		}

		send_mutex.unlock();
	}

	void receive_block(const std::vector<unsigned char>& block) {
		#ifndef FOR_VALGRIND
			if (!send_mutex.try_lock())
				return;
		#else
			send_mutex.lock();
		#endif

		auto compressed_block = compressRelayBlock(block);
		if (!compressed_block->size()) {
			printf("Failed to process block from bitcoind\n");
			send_mutex.unlock();
			return;
		}

		if (send_all(sock, (char*)&(*compressed_block)[0], compressed_block->size()) != int(compressed_block->size()))
			printf("Error sending block to relay server\n");
		else {
			struct relay_msg_header header = { RELAY_MAGIC_BYTES, END_BLOCK_TYPE, 0 };
			if (send_all(sock, (char*)&header, sizeof(header)) != int(sizeof(header)))
				printf("Error sending end block message to relay server\n");
			else {
				std::vector<unsigned char> fullhash(32);
				CSHA256 hash; // Probably not BE-safe
				hash.Write(&block[sizeof(struct bitcoin_msg_header)], 80).Finalize(&fullhash[0]);
				hash.Reset().Write(&fullhash[0], fullhash.size()).Finalize(&fullhash[0]);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" sent, size %lu with %lu bytes on the wire\n", (unsigned long)block.size(), (unsigned long)compressed_block->size());
			}
		}

		send_mutex.unlock();
	}
};

class P2PClient : public P2PRelayer {
public:
	P2PClient(const char* serverHostIn, uint16_t serverPortIn,
				const std::function<void (std::vector<unsigned char>&, struct timeval)>& provide_block_in,
				const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in) :
			P2PRelayer(serverHostIn, serverPortIn, provide_block_in, provide_transaction_in) {};

private:
	bool send_version() {
		struct bitcoin_version_with_header version_msg;
		version_msg.version.start.timestamp = htole64(time(0));
		version_msg.version.start.user_agent_length = BITCOIN_UA_LENGTH; // Work around apparent gcc bug
		return send_message("version", (unsigned char*)&version_msg, sizeof(struct bitcoin_version));
	}
};

int main(int argc, char** argv) {
	if (argc != 4) {
		printf("USAGE: %s RELAY_SERVER BITCOIND_ADDRESS BITCOIND_PORT\n", argv[0]);
		return -1;
	}

#ifdef WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2), &wsaData))
		return -1;
#endif

	RelayNetworkClient* relayClient;
	P2PClient p2p(argv[2], std::stoul(argv[3]),
					[&](std::vector<unsigned char>& bytes, struct timeval) { relayClient->receive_block(bytes); },
					[&](std::shared_ptr<std::vector<unsigned char> >& bytes) { relayClient->receive_transaction(bytes); });
	relayClient = new RelayNetworkClient(argv[1],
										[&](std::vector<unsigned char>& bytes) { p2p.receive_block(bytes); },
										[&](std::shared_ptr<std::vector<unsigned char> >& bytes) { p2p.receive_transaction(bytes); });

	while (true) { sleep(1000); }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 "src/traced/probes/ftrace/atrace_wrapper.h"

#include <fcntl.h>
#include <poll.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/android_utils.h"
#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/pipe.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"

namespace perfetto {

namespace {

RunAtraceFunction g_run_atrace_for_testing = nullptr;
base::Optional<bool> g_is_old_atrace_for_testing{};

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
// Args should include "atrace" for argv[0].
bool ExecvAtrace(const std::vector<std::string>& args) {
  int status = 1;

  std::vector<char*> argv;
  // args, and then a null.
  argv.reserve(1 + args.size());
  for (const auto& arg : args)
    argv.push_back(const_cast<char*>(arg.c_str()));
  argv.push_back(nullptr);

  // Create the pipe for the child process to return stderr.
  base::Pipe err_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);

  pid_t pid = fork();
  PERFETTO_CHECK(pid >= 0);
  if (pid == 0) {
    // Duplicate the write end of the pipe into stderr.
    if ((dup2(*err_pipe.wr, STDERR_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stderr fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    int null_fd = open("/dev/null", O_RDWR);
    if (null_fd == -1) {
      const char kError[] = "Unable to open dev null";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    if ((dup2(null_fd, STDOUT_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stdout fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    if ((dup2(null_fd, STDIN_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stdin fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    // Close stdin/out + any file descriptor that we might have mistakenly
    // not marked as FD_CLOEXEC. |err_pipe| is FD_CLOEXEC and will be
    // automatically closed on exec.
    for (int i = 0; i < 128; i++) {
      if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO)
        close(i);
    }

    execv("/system/bin/atrace", &argv[0]);

    // Reached only if execv fails.
    _exit(1);
  }

  // Close the write end of the pipe.
  err_pipe.wr.reset();

  // Collect the output from child process.
  char buffer[4096];
  std::string error;

  // Get the read end of the pipe.
  constexpr uint8_t kFdCount = 1;
  struct pollfd fds[kFdCount]{};
  fds[0].fd = *err_pipe.rd;
  fds[0].events = POLLIN;

  // Store the start time of atrace and setup the timeout.
  constexpr auto timeout = base::TimeMillis(20000);
  auto start = base::GetWallTimeMs();
  for (;;) {
    // Check if we are below the timeout and update the select timeout to
    // the time remaining.
    auto now = base::GetWallTimeMs();
    auto remaining = timeout - (now - start);
    auto timeout_ms = static_cast<int>(remaining.count());
    if (timeout_ms <= 0) {
      // Kill atrace.
      kill(pid, SIGKILL);

      std::string cmdline = "/system/bin/atrace";
      for (const auto& arg : args) {
        cmdline += " " + arg;
      }
      error.append("Timed out waiting for atrace (cmdline: " + cmdline + ")");
      break;
    }

    // Wait for the value of the timeout.
    auto ret = poll(fds, kFdCount, timeout_ms);
    if (ret == 0 || (ret < 0 && errno == EINTR)) {
      // Either timeout occurred in poll (in which case continue so that this
      // will be picked up by our own timeout logic) or we received an EINTR and
      // we should try again.
      continue;
    } else if (ret < 0) {
      error.append("Error while polling atrace stderr");
      break;
    }

    // Data is available to be read from the fd.
    int64_t count = PERFETTO_EINTR(read(*err_pipe.rd, buffer, sizeof(buffer)));
    if (ret < 0 && errno == EAGAIN) {
      continue;
    } else if (count < 0) {
      error.append("Error while reading atrace stderr");
      break;
    } else if (count == 0) {
      // EOF so we can exit this loop.
      break;
    }
    error.append(buffer, static_cast<size_t>(count));
  }

  // Wait until the child process exits fully.
  PERFETTO_EINTR(waitpid(pid, &status, 0));

  bool ok = WIFEXITED(status) && WEXITSTATUS(status) == 0;
  if (!ok) {
    // TODO(lalitm): use the stderr result from atrace.
    PERFETTO_ELOG("%s", error.c_str());
  }
  return ok;
}
#endif

}  // namespace

bool RunAtrace(const std::vector<std::string>& args) {
  if (g_run_atrace_for_testing)
    return g_run_atrace_for_testing(args);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  return ExecvAtrace(args);
#else
  PERFETTO_LOG("Atrace only supported on Android.");
  return false;
#endif
}

void SetRunAtraceForTesting(RunAtraceFunction f) {
  g_run_atrace_for_testing = f;
}

bool IsOldAtrace() {
  if (g_is_old_atrace_for_testing.has_value())
    return *g_is_old_atrace_for_testing;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
    !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  // Sideloaded case. We could be sideloaded on a modern device or an older one.
  std::string str_value = base::GetAndroidProp("ro.build.version.sdk");
  if (str_value.empty())
    return false;
  auto opt_value = base::CStringToUInt32(str_value.c_str());
  return opt_value.has_value() && *opt_value < 28;  // 28 == Android P.
#else
  // In in-tree builds we know that atrace is current, no runtime checks needed.
  return false;
#endif
}

void SetIsOldAtraceForTesting(bool value) {
  g_is_old_atrace_for_testing = value;
}

void ClearIsOldAtraceForTesting() {
  g_is_old_atrace_for_testing.reset();
}

}  // namespace perfetto
<commit_msg>traced_probes: Remove old TODO<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 "src/traced/probes/ftrace/atrace_wrapper.h"

#include <fcntl.h>
#include <poll.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/android_utils.h"
#include "perfetto/ext/base/optional.h"
#include "perfetto/ext/base/pipe.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"

namespace perfetto {

namespace {

RunAtraceFunction g_run_atrace_for_testing = nullptr;
base::Optional<bool> g_is_old_atrace_for_testing{};

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
// Args should include "atrace" for argv[0].
bool ExecvAtrace(const std::vector<std::string>& args) {
  int status = 1;

  std::vector<char*> argv;
  // args, and then a null.
  argv.reserve(1 + args.size());
  for (const auto& arg : args)
    argv.push_back(const_cast<char*>(arg.c_str()));
  argv.push_back(nullptr);

  // Create the pipe for the child process to return stderr.
  base::Pipe err_pipe = base::Pipe::Create(base::Pipe::kRdNonBlock);

  pid_t pid = fork();
  PERFETTO_CHECK(pid >= 0);
  if (pid == 0) {
    // Duplicate the write end of the pipe into stderr.
    if ((dup2(*err_pipe.wr, STDERR_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stderr fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    int null_fd = open("/dev/null", O_RDWR);
    if (null_fd == -1) {
      const char kError[] = "Unable to open dev null";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    if ((dup2(null_fd, STDOUT_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stdout fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    if ((dup2(null_fd, STDIN_FILENO) == -1)) {
      const char kError[] = "Unable to duplicate stdin fd";
      base::ignore_result(write(*err_pipe.wr, kError, sizeof(kError)));
      _exit(1);
    }

    // Close stdin/out + any file descriptor that we might have mistakenly
    // not marked as FD_CLOEXEC. |err_pipe| is FD_CLOEXEC and will be
    // automatically closed on exec.
    for (int i = 0; i < 128; i++) {
      if (i != STDIN_FILENO && i != STDERR_FILENO && i != STDOUT_FILENO)
        close(i);
    }

    execv("/system/bin/atrace", &argv[0]);

    // Reached only if execv fails.
    _exit(1);
  }

  // Close the write end of the pipe.
  err_pipe.wr.reset();

  // Collect the output from child process.
  char buffer[4096];
  std::string error;

  // Get the read end of the pipe.
  constexpr uint8_t kFdCount = 1;
  struct pollfd fds[kFdCount]{};
  fds[0].fd = *err_pipe.rd;
  fds[0].events = POLLIN;

  // Store the start time of atrace and setup the timeout.
  constexpr auto timeout = base::TimeMillis(20000);
  auto start = base::GetWallTimeMs();
  for (;;) {
    // Check if we are below the timeout and update the select timeout to
    // the time remaining.
    auto now = base::GetWallTimeMs();
    auto remaining = timeout - (now - start);
    auto timeout_ms = static_cast<int>(remaining.count());
    if (timeout_ms <= 0) {
      // Kill atrace.
      kill(pid, SIGKILL);

      std::string cmdline = "/system/bin/atrace";
      for (const auto& arg : args) {
        cmdline += " " + arg;
      }
      error.append("Timed out waiting for atrace (cmdline: " + cmdline + ")");
      break;
    }

    // Wait for the value of the timeout.
    auto ret = poll(fds, kFdCount, timeout_ms);
    if (ret == 0 || (ret < 0 && errno == EINTR)) {
      // Either timeout occurred in poll (in which case continue so that this
      // will be picked up by our own timeout logic) or we received an EINTR and
      // we should try again.
      continue;
    } else if (ret < 0) {
      error.append("Error while polling atrace stderr");
      break;
    }

    // Data is available to be read from the fd.
    int64_t count = PERFETTO_EINTR(read(*err_pipe.rd, buffer, sizeof(buffer)));
    if (ret < 0 && errno == EAGAIN) {
      continue;
    } else if (count < 0) {
      error.append("Error while reading atrace stderr");
      break;
    } else if (count == 0) {
      // EOF so we can exit this loop.
      break;
    }
    error.append(buffer, static_cast<size_t>(count));
  }

  // Wait until the child process exits fully.
  PERFETTO_EINTR(waitpid(pid, &status, 0));

  bool ok = WIFEXITED(status) && WEXITSTATUS(status) == 0;
  if (!ok) {
    PERFETTO_ELOG("%s", error.c_str());
  }
  return ok;
}
#endif

}  // namespace

bool RunAtrace(const std::vector<std::string>& args) {
  if (g_run_atrace_for_testing)
    return g_run_atrace_for_testing(args);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  return ExecvAtrace(args);
#else
  PERFETTO_LOG("Atrace only supported on Android.");
  return false;
#endif
}

void SetRunAtraceForTesting(RunAtraceFunction f) {
  g_run_atrace_for_testing = f;
}

bool IsOldAtrace() {
  if (g_is_old_atrace_for_testing.has_value())
    return *g_is_old_atrace_for_testing;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
    !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  // Sideloaded case. We could be sideloaded on a modern device or an older one.
  std::string str_value = base::GetAndroidProp("ro.build.version.sdk");
  if (str_value.empty())
    return false;
  auto opt_value = base::CStringToUInt32(str_value.c_str());
  return opt_value.has_value() && *opt_value < 28;  // 28 == Android P.
#else
  // In in-tree builds we know that atrace is current, no runtime checks needed.
  return false;
#endif
}

void SetIsOldAtraceForTesting(bool value) {
  g_is_old_atrace_for_testing = value;
}

void ClearIsOldAtraceForTesting() {
  g_is_old_atrace_for_testing.reset();
}

}  // namespace perfetto
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "security_manager/crypto_manager_impl.h"

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>

#include <fstream>
#include <iostream>
#include <stdio.h>
#include <ctime>
#include "security_manager/security_manager.h"

#include "utils/logger.h"
#include "utils/atomic.h"
#include "utils/macro.h"
#include "utils/scope_guard.h"
#include "utils/date_time.h"

#define TLS1_1_MINIMAL_VERSION 0x1000103fL
#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L

namespace security_manager {

CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")

uint32_t CryptoManagerImpl::instance_count_ = 0;
sync_primitives::Lock CryptoManagerImpl::instance_lock_;

namespace {
int debug_callback(int preverify_ok, X509_STORE_CTX* ctx) {
  if (!preverify_ok) {
    const int error = X509_STORE_CTX_get_error(ctx);
    UNUSED(error);
    LOG4CXX_WARN(logger_,
                 "Certificate verification failed with error "
                     << error << " \"" << X509_verify_cert_error_string(error)
                     << '"');
  }
  return preverify_ok;
}

void free_ctx(SSL_CTX** ctx) {
  if (ctx) {
    SSL_CTX_free(*ctx);
    *ctx = NULL;
  }
}
}

CryptoManagerImpl::CryptoManagerImpl(
    const utils::SharedPtr<const CryptoManagerSettings> set)
    : settings_(set), context_(NULL) {
  LOG4CXX_AUTO_TRACE(logger_);
  sync_primitives::AutoLock lock(instance_lock_);
  instance_count_++;
  if (instance_count_ == 1) {
    LOG4CXX_DEBUG(logger_, "Openssl engine initialization");
    SSL_load_error_strings();
    ERR_load_BIO_strings();
    OpenSSL_add_all_algorithms();
    SSL_library_init();
  }
  InitCertExpTime();
}

CryptoManagerImpl::~CryptoManagerImpl() {
  LOG4CXX_AUTO_TRACE(logger_);
  sync_primitives::AutoLock lock(instance_lock_);
  LOG4CXX_DEBUG(logger_, "Deinitilization");
  if (!context_) {
    LOG4CXX_WARN(logger_, "Manager is not initialized");
  } else {
    SSL_CTX_free(context_);
  }
  instance_count_--;
  if (instance_count_ == 0) {
    LOG4CXX_DEBUG(logger_, "Openssl engine deinitialization");
    EVP_cleanup();
    ERR_free_strings();
  }
}

bool CryptoManagerImpl::Init() {
  LOG4CXX_AUTO_TRACE(logger_);

  const Mode mode = get_settings().security_manager_mode();
  const bool is_server = (mode == SERVER);
  if (is_server) {
    LOG4CXX_DEBUG(logger_, "Server mode");
  } else {
    LOG4CXX_DEBUG(logger_, "Client mode");
  }
  LOG4CXX_DEBUG(logger_,
                "Peer verification "
                    << (get_settings().verify_peer() ? "enabled" : "disabled"));
  LOG4CXX_DEBUG(logger_,
                "CA certificate file is \"" << get_settings().ca_cert_path()
                                            << '"');

#if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION
  SSL_METHOD* method;
#else
  const SSL_METHOD* method;
#endif
  switch (get_settings().security_manager_protocol_name()) {
    case SSLv3:
      method = is_server ? SSLv3_server_method() : SSLv3_client_method();
      break;
    case TLSv1:
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
      break;
    case TLSv1_1:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
      LOG4CXX_WARN(
          logger_,
          "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0");
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
      method = is_server ? TLSv1_1_server_method() : TLSv1_1_client_method();
#endif
      break;
    case TLSv1_2:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
      LOG4CXX_WARN(
          logger_,
          "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0");
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
      method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method();
#endif
      break;
    default:
      LOG4CXX_ERROR(logger_,
                    "Unknown protocol: "
                        << get_settings().security_manager_protocol_name());
      return false;
  }
  if (context_) {
    free_ctx(&context_);
  }
  context_ = SSL_CTX_new(method);

  utils::ScopeGuard guard = utils::MakeGuard(free_ctx, &context_);

  // Disable SSL2 as deprecated
  SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2);

  set_certificate(get_settings().certificate_data());

  if (get_settings().ciphers_list().empty()) {
    LOG4CXX_WARN(logger_, "Empty ciphers list");
  } else {
    LOG4CXX_DEBUG(logger_, "Cipher list: " << get_settings().ciphers_list());
    if (!SSL_CTX_set_cipher_list(context_,
                                 get_settings().ciphers_list().c_str())) {
      LOG4CXX_ERROR(
          logger_,
          "Could not set cipher list: " << get_settings().ciphers_list());
      return false;
    }
  }

  if (get_settings().ca_cert_path().empty()) {
    LOG4CXX_WARN(logger_, "Setting up empty CA certificate location");
  }

  LOG4CXX_DEBUG(logger_, "Setting up CA certificate location");
  const int result = SSL_CTX_load_verify_locations(
      context_, NULL, get_settings().ca_cert_path().c_str());

  if (!result) {
    const unsigned long error = ERR_get_error();
    UNUSED(error);
    LOG4CXX_WARN(logger_,
                 "Wrong certificate file '"
                     << get_settings().ca_cert_path() << "', err 0x" << std::hex
                     << error << " \"" << ERR_reason_error_string(error)
                     << '"');
  }

  guard.Dismiss();

  const int verify_mode =
      get_settings().verify_peer()
          ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
          : SSL_VERIFY_NONE;
  LOG4CXX_DEBUG(logger_,
                "Setting up peer verification in mode: " << verify_mode);
  SSL_CTX_set_verify(context_, verify_mode, &debug_callback);
  return true;
}

bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) {
  LOG4CXX_AUTO_TRACE(logger_);
  if (!context_) {
    LOG4CXX_WARN(logger_, "Not initialized");
    return false;
  }

  return set_certificate(data);
}

SSLContext* CryptoManagerImpl::CreateSSLContext() {
  if (context_ == NULL) {
    return NULL;
  }

  SSL* conn = SSL_new(context_);
  if (conn == NULL)
    return NULL;

  if (get_settings().security_manager_mode() == SERVER) {
    SSL_set_accept_state(conn);
  } else {
    SSL_set_connect_state(conn);
  }
  return new SSLContextImpl(conn,
                            get_settings().security_manager_mode(),
                            get_settings().maximum_payload_size());
}

void CryptoManagerImpl::ReleaseSSLContext(SSLContext* context) {
  delete context;
}

std::string CryptoManagerImpl::LastError() const {
  if (!context_) {
    return std::string("Initialization is not completed");
  }
  const char* reason = ERR_reason_error_string(ERR_get_error());
  return std::string(reason ? reason : "");
}

bool CryptoManagerImpl::IsCertificateUpdateRequired() const {
  LOG4CXX_AUTO_TRACE(logger_);

  const time_t cert_date = mktime(&expiration_time_);

  if (cert_date == -1) {
    LOG4CXX_WARN(logger_,
                 "The certifiacte expiration time cannot be represented.");
    return false;
  }
  const time_t now = time(NULL);
  const double seconds = difftime(cert_date, now);

  LOG4CXX_DEBUG(logger_,
                "Certificate expiration time: " << asctime(&expiration_time_));
  LOG4CXX_DEBUG(logger_,
                "Host time: " << asctime(localtime(&now))
                              << ". Seconds before expiration: " << seconds);
  if (seconds < 0) {
    LOG4CXX_WARN(logger_, "Certificate is already expired.");
    return true;
  }

  return seconds <= (get_settings().update_before_hours() *
                     date_time::DateTime::SECONDS_IN_HOUR);
}

const CryptoManagerSettings& CryptoManagerImpl::get_settings() const {
  return *settings_;
}

bool CryptoManagerImpl::set_certificate(const std::string& cert_data) {
  LOG4CXX_AUTO_TRACE(logger_);

  if (cert_data.empty()) {
    LOG4CXX_WARN(logger_, "Empty certificate");
    return false;
  }

  BIO* bio_cert =
      BIO_new_mem_buf(const_cast<char*>(cert_data.c_str()), cert_data.length());

  utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert);
  UNUSED(bio_guard)

  X509* cert = NULL;
  PEM_read_bio_X509(bio_cert, &cert, 0, 0);

  EVP_PKEY* pkey = NULL;
  if (1 == BIO_reset(bio_cert)) {
    PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0);
  } else {
    LOG4CXX_WARN(logger_,
                 "Unabled to reset BIO in order to read private key, "
                     << LastError());
  }

  if (NULL == cert || NULL == pkey) {
    LOG4CXX_WARN(logger_, "Either certificate or key not valid.");
    return false;
  }

  if (!SSL_CTX_use_certificate(context_, cert)) {
    LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError());
    return false;
  }

  asn1_time_to_tm(X509_get_notAfter(cert));

  if (!SSL_CTX_use_PrivateKey(context_, pkey)) {
    LOG4CXX_ERROR(logger_, "Could not use key: " << LastError());
    return false;
  }

  if (!SSL_CTX_check_private_key(context_)) {
    LOG4CXX_ERROR(logger_, "Could not use certificate: " << LastError());
    return false;
  }

  LOG4CXX_DEBUG(logger_, "Certificate and key successfully updated");
  return true;
}

int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) {
  if (!idx) {
    return 0;
  }
  const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0';
  *idx = *idx + 2;
  return val;
}

void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) {
  char* buf = (char*)time->data;
  int index = 0;
  const int year = pull_number_from_buf(buf, &index);
  if (V_ASN1_GENERALIZEDTIME == time->type) {
    expiration_time_.tm_year =
        (year * 100 - 1900) + pull_number_from_buf(buf, &index);
  } else {
    expiration_time_.tm_year = year < 50 ? year + 100 : year;
  }

  const int mon = pull_number_from_buf(buf, &index);
  const int day = pull_number_from_buf(buf, &index);
  const int hour = pull_number_from_buf(buf, &index);
  const int mn = pull_number_from_buf(buf, &index);

  expiration_time_.tm_mon = mon - 1;
  expiration_time_.tm_mday = day;
  expiration_time_.tm_hour = hour;
  expiration_time_.tm_min = mn;

  if (buf[index] == 'Z') {
    expiration_time_.tm_sec = 0;
  }
  if ((buf[index] == '+') || (buf[index] == '-')) {
    const int mn = pull_number_from_buf(buf, &index);
    const int mn1 = pull_number_from_buf(buf, &index);
    expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60);
  } else {
    const int sec = pull_number_from_buf(buf, &index);
    expiration_time_.tm_sec = sec;
  }
}

void CryptoManagerImpl::InitCertExpTime() {
  strptime("1 Jan 1970 00:00:00", "%d %b %Y %H:%M:%S", &expiration_time_);
}

}  // namespace security_manager
<commit_msg>Fixed certificate chain reading from PEM file<commit_after>/*
 * Copyright (c) 2014, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "security_manager/crypto_manager_impl.h"

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>

#include <fstream>
#include <iostream>
#include <stdio.h>
#include <ctime>
#include "security_manager/security_manager.h"

#include "utils/logger.h"
#include "utils/atomic.h"
#include "utils/macro.h"
#include "utils/scope_guard.h"
#include "utils/date_time.h"

#define TLS1_1_MINIMAL_VERSION 0x1000103fL
#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L

namespace security_manager {

CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")

uint32_t CryptoManagerImpl::instance_count_ = 0;
sync_primitives::Lock CryptoManagerImpl::instance_lock_;

namespace {
int debug_callback(int preverify_ok, X509_STORE_CTX* ctx) {
  if (!preverify_ok) {
    const int error = X509_STORE_CTX_get_error(ctx);
    UNUSED(error);
    LOG4CXX_WARN(logger_,
                 "Certificate verification failed with error "
                     << error << " \"" << X509_verify_cert_error_string(error)
                     << '"');
  }
  return preverify_ok;
}

void free_ctx(SSL_CTX** ctx) {
  if (ctx) {
    SSL_CTX_free(*ctx);
    *ctx = NULL;
  }
}
}

CryptoManagerImpl::CryptoManagerImpl(
    const utils::SharedPtr<const CryptoManagerSettings> set)
    : settings_(set), context_(NULL) {
  LOG4CXX_AUTO_TRACE(logger_);
  sync_primitives::AutoLock lock(instance_lock_);
  instance_count_++;
  if (instance_count_ == 1) {
    LOG4CXX_DEBUG(logger_, "Openssl engine initialization");
    SSL_load_error_strings();
    ERR_load_BIO_strings();
    OpenSSL_add_all_algorithms();
    SSL_library_init();
  }
  InitCertExpTime();
}

CryptoManagerImpl::~CryptoManagerImpl() {
  LOG4CXX_AUTO_TRACE(logger_);
  sync_primitives::AutoLock lock(instance_lock_);
  LOG4CXX_DEBUG(logger_, "Deinitilization");
  if (!context_) {
    LOG4CXX_WARN(logger_, "Manager is not initialized");
  } else {
    SSL_CTX_free(context_);
  }
  instance_count_--;
  if (instance_count_ == 0) {
    LOG4CXX_DEBUG(logger_, "Openssl engine deinitialization");
    EVP_cleanup();
    ERR_free_strings();
  }
}

bool CryptoManagerImpl::Init() {
  LOG4CXX_AUTO_TRACE(logger_);

  const Mode mode = get_settings().security_manager_mode();
  const bool is_server = (mode == SERVER);
  if (is_server) {
    LOG4CXX_DEBUG(logger_, "Server mode");
  } else {
    LOG4CXX_DEBUG(logger_, "Client mode");
  }
  LOG4CXX_DEBUG(logger_,
                "Peer verification "
                    << (get_settings().verify_peer() ? "enabled" : "disabled"));
  LOG4CXX_DEBUG(logger_,
                "CA certificate file is \"" << get_settings().ca_cert_path()
                                            << '"');

#if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION
  SSL_METHOD* method;
#else
  const SSL_METHOD* method;
#endif
  switch (get_settings().security_manager_protocol_name()) {
    case SSLv3:
      method = is_server ? SSLv3_server_method() : SSLv3_client_method();
      break;
    case TLSv1:
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
      break;
    case TLSv1_1:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
      LOG4CXX_WARN(
          logger_,
          "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0");
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
      method = is_server ? TLSv1_1_server_method() : TLSv1_1_client_method();
#endif
      break;
    case TLSv1_2:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
      LOG4CXX_WARN(
          logger_,
          "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0");
      method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
      method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method();
#endif
      break;
    default:
      LOG4CXX_ERROR(logger_,
                    "Unknown protocol: "
                        << get_settings().security_manager_protocol_name());
      return false;
  }
  if (context_) {
    free_ctx(&context_);
  }
  context_ = SSL_CTX_new(method);

  utils::ScopeGuard guard = utils::MakeGuard(free_ctx, &context_);

  // Disable SSL2 as deprecated
  SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2);

  set_certificate(get_settings().certificate_data());

  if (get_settings().ciphers_list().empty()) {
    LOG4CXX_WARN(logger_, "Empty ciphers list");
  } else {
    LOG4CXX_DEBUG(logger_, "Cipher list: " << get_settings().ciphers_list());
    if (!SSL_CTX_set_cipher_list(context_,
                                 get_settings().ciphers_list().c_str())) {
      LOG4CXX_ERROR(
          logger_,
          "Could not set cipher list: " << get_settings().ciphers_list());
      return false;
    }
  }

  if (get_settings().ca_cert_path().empty()) {
    LOG4CXX_WARN(logger_, "Setting up empty CA certificate location");
  }

  LOG4CXX_DEBUG(logger_, "Setting up CA certificate location");
  const int result = SSL_CTX_load_verify_locations(
      context_, NULL, get_settings().ca_cert_path().c_str());

  if (!result) {
    const unsigned long error = ERR_get_error();
    UNUSED(error);
    LOG4CXX_WARN(logger_,
                 "Wrong certificate file '"
                     << get_settings().ca_cert_path() << "', err 0x" << std::hex
                     << error << " \"" << ERR_reason_error_string(error)
                     << '"');
  }

  guard.Dismiss();

  const int verify_mode =
      get_settings().verify_peer()
          ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
          : SSL_VERIFY_NONE;
  LOG4CXX_DEBUG(logger_,
                "Setting up peer verification in mode: " << verify_mode);
  SSL_CTX_set_verify(context_, verify_mode, &debug_callback);
  return true;
}

bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) {
  LOG4CXX_AUTO_TRACE(logger_);
  if (!context_) {
    LOG4CXX_WARN(logger_, "Not initialized");
    return false;
  }

  return set_certificate(data);
}

SSLContext* CryptoManagerImpl::CreateSSLContext() {
  if (context_ == NULL) {
    return NULL;
  }

  SSL* conn = SSL_new(context_);
  if (conn == NULL)
    return NULL;

  if (get_settings().security_manager_mode() == SERVER) {
    SSL_set_accept_state(conn);
  } else {
    SSL_set_connect_state(conn);
  }
  return new SSLContextImpl(conn,
                            get_settings().security_manager_mode(),
                            get_settings().maximum_payload_size());
}

void CryptoManagerImpl::ReleaseSSLContext(SSLContext* context) {
  delete context;
}

std::string CryptoManagerImpl::LastError() const {
  if (!context_) {
    return std::string("Initialization is not completed");
  }
  const char* reason = ERR_reason_error_string(ERR_get_error());
  return std::string(reason ? reason : "");
}

bool CryptoManagerImpl::IsCertificateUpdateRequired() const {
  LOG4CXX_AUTO_TRACE(logger_);

  const time_t cert_date = mktime(&expiration_time_);

  if (cert_date == -1) {
    LOG4CXX_WARN(logger_,
                 "The certifiacte expiration time cannot be represented.");
    return false;
  }
  const time_t now = time(NULL);
  const double seconds = difftime(cert_date, now);

  LOG4CXX_DEBUG(logger_,
                "Certificate expiration time: " << asctime(&expiration_time_));
  LOG4CXX_DEBUG(logger_,
                "Host time: " << asctime(localtime(&now))
                              << ". Seconds before expiration: " << seconds);
  if (seconds < 0) {
    LOG4CXX_WARN(logger_, "Certificate is already expired.");
    return true;
  }

  return seconds <= (get_settings().update_before_hours() *
                     date_time::DateTime::SECONDS_IN_HOUR);
}

const CryptoManagerSettings& CryptoManagerImpl::get_settings() const {
  return *settings_;
}

bool CryptoManagerImpl::set_certificate(const std::string& cert_data) {
  LOG4CXX_AUTO_TRACE(logger_);

  if (cert_data.empty()) {
    LOG4CXX_WARN(logger_, "Empty certificate");
    return false;
  }

  BIO* bio_cert =
      BIO_new_mem_buf(const_cast<char*>(cert_data.c_str()), cert_data.length());

  utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert);
  UNUSED(bio_guard)

  X509* cert = NULL;
  PEM_read_bio_X509(bio_cert, &cert, 0, 0);

  EVP_PKEY* pkey = NULL;
  if (1 == BIO_reset(bio_cert)) {
    PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0);
  } else {
    LOG4CXX_WARN(logger_,
                 "Unabled to reset BIO in order to read private key, "
                     << LastError());
  }

  if (NULL == cert || NULL == pkey) {
    LOG4CXX_WARN(logger_, "Either certificate or key not valid.");
    return false;
  }

  if (!SSL_CTX_use_certificate(context_, cert)) {
    LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError());
    return false;
  }

  asn1_time_to_tm(X509_get_notAfter(cert));

  if (!SSL_CTX_use_PrivateKey(context_, pkey)) {
    LOG4CXX_ERROR(logger_, "Could not use key: " << LastError());
    return false;
  }

  if (!SSL_CTX_check_private_key(context_)) {
    LOG4CXX_ERROR(logger_, "Could not use certificate: " << LastError());
    return false;
  }

  X509_STORE* store = SSL_CTX_get_cert_store(context_);
  if (store) {
    X509* extra_cert = NULL;
    while ((extra_cert = PEM_read_bio_X509(bio_cert, NULL, 0, 0))) {
      if (extra_cert != cert) {
        LOG4CXX_DEBUG(logger_,
                      "Added new certificate to store: " << extra_cert);
        X509_STORE_add_cert(store, extra_cert);
      }
    }
  }

  LOG4CXX_DEBUG(logger_, "Certificate and key successfully updated");
  return true;
}

int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) {
  if (!idx) {
    return 0;
  }
  const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0';
  *idx = *idx + 2;
  return val;
}

void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) {
  char* buf = (char*)time->data;
  int index = 0;
  const int year = pull_number_from_buf(buf, &index);
  if (V_ASN1_GENERALIZEDTIME == time->type) {
    expiration_time_.tm_year =
        (year * 100 - 1900) + pull_number_from_buf(buf, &index);
  } else {
    expiration_time_.tm_year = year < 50 ? year + 100 : year;
  }

  const int mon = pull_number_from_buf(buf, &index);
  const int day = pull_number_from_buf(buf, &index);
  const int hour = pull_number_from_buf(buf, &index);
  const int mn = pull_number_from_buf(buf, &index);

  expiration_time_.tm_mon = mon - 1;
  expiration_time_.tm_mday = day;
  expiration_time_.tm_hour = hour;
  expiration_time_.tm_min = mn;

  if (buf[index] == 'Z') {
    expiration_time_.tm_sec = 0;
  }
  if ((buf[index] == '+') || (buf[index] == '-')) {
    const int mn = pull_number_from_buf(buf, &index);
    const int mn1 = pull_number_from_buf(buf, &index);
    expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60);
  } else {
    const int sec = pull_number_from_buf(buf, &index);
    expiration_time_.tm_sec = sec;
  }
}

void CryptoManagerImpl::InitCertExpTime() {
  strptime("1 Jan 1970 00:00:00", "%d %b %Y %H:%M:%S", &expiration_time_);
}

}  // namespace security_manager
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_SUPERLU
#define MFEM_SUPERLU

#include "../config/config.hpp"

#ifdef MFEM_USE_SUPERLU
#ifdef MFEM_USE_MPI
#include "operator.hpp"
#include "hypre.hpp"

#include <mpi.h>

namespace mfem
{

namespace superlu_internal
{
unsigned int sqrti(const unsigned int & a);
}

namespace superlu
{
// Copy selected enumerations from SuperLU
typedef enum {NOROWPERM, LargeDiag_MC64, LargeDiag_HWPM, MY_PERMR}  RowPerm;
typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD,
              METIS_AT_PLUS_A, PARMETIS, ZOLTAN, MY_PERMC}          ColPerm;
typedef enum {NOTRANS, TRANS, CONJ}                                 Trans;
typedef enum {NOREFINE, SLU_SINGLE=1, SLU_DOUBLE, SLU_EXTRA}        IterRefine;
}

class SuperLURowLocMatrix : public Operator
{
public:
   /** Creates a general parallel matrix from a local CSR matrix on each
       processor described by the I, J and data arrays. The local matrix should
       be of size (local) nrows by (global) glob_ncols. The new parallel matrix
       contains copies of all input arrays (so they can be deleted). */
   SuperLURowLocMatrix(MPI_Comm comm,
                       int num_loc_rows, int first_loc_row,
                       int glob_nrows, int glob_ncols,
                       int *I, int *J, double *data);

   /** Creates a copy of the parallel matrix hypParMat in SuperLU's RowLoc
       format. All data is copied so the original matrix may be deleted. */
   SuperLURowLocMatrix(const HypreParMatrix & hypParMat);

   ~SuperLURowLocMatrix();

   void Mult(const Vector &x, Vector &y) const
   {
      mfem_error("SuperLURowLocMatrix::Mult(...)\n"
                 "  matrix vector products are not supported.");
   }

   MPI_Comm GetComm() const { return comm_; }

   void * InternalData() const { return rowLocPtr_; }

private:
   MPI_Comm   comm_;
   void     * rowLocPtr_;

}; // mfem::SuperLURowLocMatrix

/** The MFEM SuperLU Direct Solver class.

    The mfem::SuperLUSolver class uses the SuperLU_DIST library to perform LU
    factorization of a parallel sparse matrix. The solver is capable of handling
    double precision types. It is currently maintained by Xiaoye Sherry Li at
    NERSC, see http://crd-legacy.lbl.gov/~xiaoye/SuperLU/.
*/
class SuperLUSolver : public mfem::Solver
{
public:
   // Constructor with MPI_Comm parameter.
   SuperLUSolver( MPI_Comm comm );

   // Constructor with SuperLU Matrix Object.
   SuperLUSolver( SuperLURowLocMatrix & A);

   // Default destructor.
   ~SuperLUSolver( void );

   // Allocate and deallocate the MPI communicators. This routine is called
   // internally by SetOperator().
   void SetupGrid();
   // This routing must be called after the solve, but before destruction.
   void DismantleGrid();

   // Factor and solve the linear system y = Op^{-1} x.
   void Mult( const Vector & x, Vector & y ) const;

   // Set the operator.
   void SetOperator( const Operator & op );

   // Set various solver options. Refer to SuperLU documentation for details.
   void SetPrintStatistics  ( bool              print_stat );
   void SetEquilibriate     ( bool                   equil );
   void SetColumnPermutation( superlu::ColPerm    col_perm );
   void SetRowPermutation   ( superlu::RowPerm    row_perm,
                              Array<int> *     perm = NULL );
   void SetTranspose        ( superlu::Trans         trans );
   void SetIterativeRefine  ( superlu::IterRefine iter_ref );
   void SetReplaceTinyPivot ( bool                     rtp );
   void SetNumLookAheads    ( int           num_lookaheads );
   void SetLookAheadElimTree( bool                   etree );
   void SetSymmetricPattern ( bool                     sym );

private:
   void Init();

protected:

   MPI_Comm      comm_;
   int           numProcs_;
   int           myid_;

   const SuperLURowLocMatrix * APtr_;

   // The actual types of the following pointers are hidden to avoid exposing
   // the SuperLU header files to the entire library. Their types are given in
   // the trailing comments. The reason that this is necessary is that SuperLU
   // defines these structs differently for use with its real and complex
   // solvers. If we want to add support for SuperLU's complex solvers one day
   // we will need to hide these types to avoid name conflicts.
   void*         optionsPtr_;         // superlu_options_t *
   void*         statPtr_;            //     SuperLUStat_t *
   void*         ScalePermstructPtr_; //  ScalePermsruct_t *
   void*         LUstructPtr_;        //        LUstruct_t *
   void*         SOLVEstructPtr_;     //     SOLVEstruct_t *
   void*         gridPtr_;            //        gridinfo_t *

   double*       berr_;
   mutable int*  perm_r_;
   int           nrhs_;
   int           nprow_;
   int           npcol_;
   mutable bool  firstSolveWithThisA_;
   bool          gridInitialized_;
   mutable bool  LUStructInitialized_;

}; // mfem::SuperLUSolver class

} // mfem namespace

#endif // MFEM_USE_MPI
#endif // MFEM_USE_SUPERLU
#endif // MFEM_SUPERLU
<commit_msg>make style<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_SUPERLU
#define MFEM_SUPERLU

#include "../config/config.hpp"

#ifdef MFEM_USE_SUPERLU
#ifdef MFEM_USE_MPI
#include "operator.hpp"
#include "hypre.hpp"

#include <mpi.h>

namespace mfem
{

namespace superlu_internal
{
unsigned int sqrti(const unsigned int & a);
}

namespace superlu
{
// Copy selected enumerations from SuperLU
typedef enum {NOROWPERM, LargeDiag_MC64, LargeDiag_HWPM, MY_PERMR}  RowPerm;
typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD,
              METIS_AT_PLUS_A, PARMETIS, ZOLTAN, MY_PERMC
             }          ColPerm;
typedef enum {NOTRANS, TRANS, CONJ}                                 Trans;
typedef enum {NOREFINE, SLU_SINGLE=1, SLU_DOUBLE, SLU_EXTRA}        IterRefine;
}

class SuperLURowLocMatrix : public Operator
{
public:
   /** Creates a general parallel matrix from a local CSR matrix on each
       processor described by the I, J and data arrays. The local matrix should
       be of size (local) nrows by (global) glob_ncols. The new parallel matrix
       contains copies of all input arrays (so they can be deleted). */
   SuperLURowLocMatrix(MPI_Comm comm,
                       int num_loc_rows, int first_loc_row,
                       int glob_nrows, int glob_ncols,
                       int *I, int *J, double *data);

   /** Creates a copy of the parallel matrix hypParMat in SuperLU's RowLoc
       format. All data is copied so the original matrix may be deleted. */
   SuperLURowLocMatrix(const HypreParMatrix & hypParMat);

   ~SuperLURowLocMatrix();

   void Mult(const Vector &x, Vector &y) const
   {
      mfem_error("SuperLURowLocMatrix::Mult(...)\n"
                 "  matrix vector products are not supported.");
   }

   MPI_Comm GetComm() const { return comm_; }

   void * InternalData() const { return rowLocPtr_; }

private:
   MPI_Comm   comm_;
   void     * rowLocPtr_;

}; // mfem::SuperLURowLocMatrix

/** The MFEM SuperLU Direct Solver class.

    The mfem::SuperLUSolver class uses the SuperLU_DIST library to perform LU
    factorization of a parallel sparse matrix. The solver is capable of handling
    double precision types. It is currently maintained by Xiaoye Sherry Li at
    NERSC, see http://crd-legacy.lbl.gov/~xiaoye/SuperLU/.
*/
class SuperLUSolver : public mfem::Solver
{
public:
   // Constructor with MPI_Comm parameter.
   SuperLUSolver( MPI_Comm comm );

   // Constructor with SuperLU Matrix Object.
   SuperLUSolver( SuperLURowLocMatrix & A);

   // Default destructor.
   ~SuperLUSolver( void );

   // Allocate and deallocate the MPI communicators. This routine is called
   // internally by SetOperator().
   void SetupGrid();
   // This routing must be called after the solve, but before destruction.
   void DismantleGrid();

   // Factor and solve the linear system y = Op^{-1} x.
   void Mult( const Vector & x, Vector & y ) const;

   // Set the operator.
   void SetOperator( const Operator & op );

   // Set various solver options. Refer to SuperLU documentation for details.
   void SetPrintStatistics  ( bool              print_stat );
   void SetEquilibriate     ( bool                   equil );
   void SetColumnPermutation( superlu::ColPerm    col_perm );
   void SetRowPermutation   ( superlu::RowPerm    row_perm,
                              Array<int> *     perm = NULL );
   void SetTranspose        ( superlu::Trans         trans );
   void SetIterativeRefine  ( superlu::IterRefine iter_ref );
   void SetReplaceTinyPivot ( bool                     rtp );
   void SetNumLookAheads    ( int           num_lookaheads );
   void SetLookAheadElimTree( bool                   etree );
   void SetSymmetricPattern ( bool                     sym );

private:
   void Init();

protected:

   MPI_Comm      comm_;
   int           numProcs_;
   int           myid_;

   const SuperLURowLocMatrix * APtr_;

   // The actual types of the following pointers are hidden to avoid exposing
   // the SuperLU header files to the entire library. Their types are given in
   // the trailing comments. The reason that this is necessary is that SuperLU
   // defines these structs differently for use with its real and complex
   // solvers. If we want to add support for SuperLU's complex solvers one day
   // we will need to hide these types to avoid name conflicts.
   void*         optionsPtr_;         // superlu_options_t *
   void*         statPtr_;            //     SuperLUStat_t *
   void*         ScalePermstructPtr_; //  ScalePermsruct_t *
   void*         LUstructPtr_;        //        LUstruct_t *
   void*         SOLVEstructPtr_;     //     SOLVEstruct_t *
   void*         gridPtr_;            //        gridinfo_t *

   double*       berr_;
   mutable int*  perm_r_;
   int           nrhs_;
   int           nprow_;
   int           npcol_;
   mutable bool  firstSolveWithThisA_;
   bool          gridInitialized_;
   mutable bool  LUStructInitialized_;

}; // mfem::SuperLUSolver class

} // mfem namespace

#endif // MFEM_USE_MPI
#endif // MFEM_USE_SUPERLU
#endif // MFEM_SUPERLU
<|endoftext|>