<commit_before>/*************************************************************************
 *
 *  $RCSfile: logfile.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: cd $ $Date: 2001-07-06 10:41:38 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2001 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _RTL_LOGFILE_HXX_
#define _RTL_LOGFILE_HXX_

#ifndef _OSL_TIME_H_
#include <osl/time.h>
#endif
#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

#ifndef _RTL_LOGFILE_H_
#include <rtl/logfile.h>
#endif
#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif

namespace rtl
{
/**
@descr  The intended use for class Logfile is to write time stamp information
        for profiling purposes. The class calls rtl_logfile_trace which uses the traditional
        C fopen/fprintf family instead of the new C++ ofstream class because of a (hopefully)
        lower time penalty: Logging should not distort the logged data.

        Profiling output should only be generated for a special product version of OpenOffice
        which is compiled with a defined preprocessor symbol 'PROFILE'.
        Therefore we have provided a set of macros that uses the class Logfile only if
        this symbol is defined.  If the macros are not sufficient, i.e. you need more
        then three arguments for a printf style message, then you have to insert an
        #ifdef PROFILE/#endif brace yourself.
        Additionally the environment variable RTL_LOGFILE has to be defined in order to generate
        profiling data.  It can be used as a run time switch for enabling or disabling the logging.
        Note that this variable is evaluated only once at the first attempt to write a message.

        The class LogFile collects runtime data within its constructor and destructor. It can be
        used for timing whole functions.
        If you want to write timing data without context you can use the RTL_LOGFILE_TRACE-macros
        which are defined inside <rtl/logfile.h>.

        The class LogFile should not be used directly, instead use the RTL_LOGFILE_CONTEXT/
        RTL_LOGFILE_TRACE-macros.

        The lines written to the log file consist of the following space separated elements:
        1.  The time relative to the start of the global timer in milliseconds.  The times is
            started typically for the first logged line.
        2.  Thread id.  It's absolut value is probably of less interest than providing a way to
            distinguish different threads.
        3.  a.  An opening or closing curly brace indicating the start or end of a scope.
                4a. Function name or general scope identifier.
            b.  A vertical line indicating an arbitrary message.
                4b optional function name or general scope identifier.
                5b A colon followed by a space and a free form message terminated by a newline.
*/
    class Logfile
    {
    public:
        inline Logfile( const sal_Char *name );
        inline ~Logfile();
        inline const sal_Char *getName();
    private:
        ::rtl::OString m_sName;
    };

    inline Logfile::Logfile( const sal_Char *name )
        : m_sName( name )
    {
        rtl_logfile_trace( "%06lu %lu { %s\n",
                           osl_getGlobalTimer(),
                           osl_getThreadIdentifier( 0 ),
                           name );
    }

    inline Logfile::~Logfile()
    {
        rtl_logfile_trace( "%06lu %lu } %s\n",
                           osl_getGlobalTimer(),
                           osl_getThreadIdentifier(0),
                           m_sName.pData->buffer );
    }

    inline const sal_Char * Logfile::getName()
    {
        return m_sName.getStr();
    }
}

#ifdef PROFILE
#define RTL_LOGFILE_CONTEXT( instance, name ) ::rtl::Logfile instance( name )
#define RTL_LOGFILE_CONTEXT_TRACE( instance, message ) \
        rtl_logfile_trace( "%06lu %lu | %s : %s\n", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName(), \
                           message )
#define RTL_LOGFILE_CONTEXT_TRACE1( instance , frmt, arg1 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 ); \
        rtl_logfile_trace( "\n" )
#define RTL_LOGFILE_CONTEXT_TRACE2( instance , frmt, arg1 , arg2 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 , arg2 ); \
        rtl_logfile_trace( "\n" )
#define RTL_LOGFILE_CONTEXT_TRACE3( instance , frmt, arg1 , arg2 , arg3 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 , arg2 , arg3 ); \
        rtl_logfile_trace( "\n" )

#else
#define RTL_LOGFILE_CONTEXT( instance,name )  ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE( instance, message )  ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE1( instance, frmt, arg1 ) ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE2( instance, frmt, arg1, arg2 ) ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE3( instance, frmt, arg1, arg2 , arg3 ) ((void)0)
#endif

#endif
<commit_msg>#88409# more usage infos added<commit_after>/*************************************************************************
 *
 *  $RCSfile: logfile.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: cd $ $Date: 2001-07-06 12:16:20 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2001 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _RTL_LOGFILE_HXX_
#define _RTL_LOGFILE_HXX_

#ifndef _OSL_TIME_H_
#include <osl/time.h>
#endif
#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

#ifndef _RTL_LOGFILE_H_
#include <rtl/logfile.h>
#endif
#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif

namespace rtl
{
/**
@descr  The intended use for class Logfile is to write time stamp information
        for profiling purposes.

        Profiling output should only be generated for a special product version of OpenOffice
        which is compiled with a defined preprocessor symbol 'PROFILE'.
        Therefore we have provided a set of macros that uses the class Logfile only if
        this symbol is defined.  If the macros are not sufficient, i.e. you need more
        then three arguments for a printf style message, then you have to insert an
        #ifdef PROFILE/#endif brace yourself.

        Additionally the environment variable RTL_LOGFILE has to be defined in order to generate
        logging information. If the variable is not empty, it creates a file with the name
        $(RTL_LOGFILE)_$(PID).log, where $(PID) is the process id of the running process.
        It can be used as a run time switch for enabling or disabling the logging.
        Note that this variable is evaluated only once at the first attempt to write a message.

        The class LogFile collects runtime data within its constructor and destructor. It can be
        used for timing whole functions.
        If you want to write timing data without context you can use the RTL_LOGFILE_TRACE-macros
        which are defined inside <rtl/logfile.h>.

        The class LogFile should not be used directly, instead use the RTL_LOGFILE_CONTEXT/
        RTL_LOGFILE_TRACE-macros.

        Macro usage:
        ------------
        RTL_LOGFILE_CONTEXT( instance, name );
        This macro creates an instance of class LogFile with the name "instance" and writes the current time,
        thread id and "name" to the log file.

        Example: RTL_LOGFILE_CONTEXT( aLog, "Timing for foo-method" );

        RTL_LOGFILE_CONTEXT_TRACE( instance, mesage );
        RTL_LOGFILE_CONTEXT_TRACEn( instance, frmt, arg1, .., arg3 );
        These macros can be used to log information in a "instance" context. The "instance" object
        is used to log message informations. All macros with "frmt" uses printf notation to log timing infos.

        Example: RTL_LOGFILE_CONTEXT_TRACE( aLog, "Now we call an expensive function" );
                 RTL_LOGFIlE_CONTEXT_TRACE1( aLog, "Config entries read: %u", (unsigned short)i );

        RTL_LOGFILE_TRACE( string );
        RTL_LOGFILE_TRACEn( frmt, arg1, .., arg3 );
        These macros can be used to log information outside a context. The macro directly calls
        rtl_logfile_trace to write the info to the log file. All macros with "frmt" uses printf
        notation to log timing infos.

        Example: RTL_LOGFILE_TRACE( "Timing for loading a file" );
                 RTL_LOGFILE_TRACE1( aLog, "Timing for loading file: %s", aFileName );

        The lines written to the log file consist of the following space separated elements:
        1.  The time relative to the start of the global timer in milliseconds.  The times is
            started typically for the first logged line.
        2.  Thread id.  It's absolut value is probably of less interest than providing a way to
            distinguish different threads.
        3.  a.  An opening or closing curly brace indicating the start or end of a scope.
                4a. Function name or general scope identifier.
            b.  A vertical line indicating an arbitrary message.
                4b optional function name or general scope identifier.
                5b A colon followed by a space and a free form message terminated by a newline.
*/
    class Logfile
    {
    public:
        inline Logfile( const sal_Char *name );
        inline ~Logfile();
        inline const sal_Char *getName();
    private:
        ::rtl::OString m_sName;
    };

    inline Logfile::Logfile( const sal_Char *name )
        : m_sName( name )
    {
        rtl_logfile_trace( "%06lu %lu { %s\n",
                           osl_getGlobalTimer(),
                           osl_getThreadIdentifier( 0 ),
                           name );
    }

    inline Logfile::~Logfile()
    {
        rtl_logfile_trace( "%06lu %lu } %s\n",
                           osl_getGlobalTimer(),
                           osl_getThreadIdentifier(0),
                           m_sName.pData->buffer );
    }

    inline const sal_Char * Logfile::getName()
    {
        return m_sName.getStr();
    }
}

#ifdef PROFILE
#define RTL_LOGFILE_CONTEXT( instance, name ) ::rtl::Logfile instance( name )
#define RTL_LOGFILE_CONTEXT_TRACE( instance, message ) \
        rtl_logfile_trace( "%06lu %lu | %s : %s\n", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName(), \
                           message )
#define RTL_LOGFILE_CONTEXT_TRACE1( instance , frmt, arg1 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 ); \
        rtl_logfile_trace( "\n" )
#define RTL_LOGFILE_CONTEXT_TRACE2( instance , frmt, arg1 , arg2 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 , arg2 ); \
        rtl_logfile_trace( "\n" )
#define RTL_LOGFILE_CONTEXT_TRACE3( instance , frmt, arg1 , arg2 , arg3 ) \
        rtl_logfile_trace( "%06lu %lu | %s : ", \
                           osl_getGlobalTimer(),  \
                           osl_getThreadIdentifier( 0 ), \
                           instance.getName() ); \
        rtl_logfile_trace( frmt , arg1 , arg2 , arg3 ); \
        rtl_logfile_trace( "\n" )

#else
#define RTL_LOGFILE_CONTEXT( instance,name )  ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE( instance, message )  ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE1( instance, frmt, arg1 ) ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE2( instance, frmt, arg1, arg2 ) ((void)0)
#define RTL_LOGFILE_CONTEXT_TRACE3( instance, frmt, arg1, arg2 , arg3 ) ((void)0)
#endif

#endif
<|endoftext|>


<commit_before>#include "ingameelements/heroes/mccree.h"
#include "datastructures.h"
#include "spriteloader.h"
#include "animation.h"
#include "gamestate.h"
#include "engine.h"
#include "ingameelements/projectiles/flashbang.h"

#include <memory>
#include <cmath>
#include <allegro5/allegro_primitives.h>

Mccree::Mccree(uint64_t id_, Gamestate *state, EntityPtr owner_) : Character(id_, state, owner_, constructparameters(id_, state, owner_)),
                rollanim("heroes/mccree/roll/"), flashbanganim("heroes/mccree/flashbang/"), rollcooldown(8), flashbangcooldown(10), ultwalkanim("heroes/mccree/ultwalk/"),
                ulting(std::bind(&Mccree::resetafterult, this, state), 6), deadeyetargets()
{
    rollanim.active(false);
    rollcooldown.active = false;
    flashbanganim.active(false);
    flashbangcooldown.active = false;
    ulting.active = false;
}

Mccree::~Mccree()
{
    //dtor
}

void Mccree::render(Renderer *renderer, Gamestate *state)
{
    Character::render(renderer, state);
    al_set_target_bitmap(renderer->midground);

    std::string mainsprite;
    ALLEGRO_BITMAP *sprite;
    int spriteoffset_x;
    int spriteoffset_y;

    if (flashbanganim.active())
    {
        std::string armsprite = flashbanganim.getframepath();
        sprite = renderer->spriteloader.requestsprite(armsprite);
        spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(armsprite);
        spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(armsprite);
        if (isflipped)
        {
            // Flip horizontally
            al_draw_scaled_rotated_bitmap(sprite, spriteoffset_x, spriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
        }
        else
        {
            al_draw_bitmap(sprite, x-spriteoffset_x - renderer->cam_x, y-spriteoffset_y - renderer->cam_y, 0);
        }
    }

    mainsprite = getsprite(state, false);
    sprite = renderer->spriteloader.requestsprite(mainsprite);
    spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(mainsprite);
    spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(mainsprite);

    std::string outlinesprite = mainsprite+"_outline";
    ALLEGRO_BITMAP *outline = renderer->spriteloader.requestsprite(outlinesprite);
    int outlinespriteoffset_x = renderer->spriteloader.get_spriteoffset_x(outlinesprite);
    int outlinespriteoffset_y = renderer->spriteloader.get_spriteoffset_y(outlinesprite);
    ALLEGRO_COLOR outlinecolor;
    if (state->get<Player>(renderer->myself)->team == team)
    {
        // Draw friendly outline
        outlinecolor = al_map_rgb(0, 145, 181);
    }
    else
    {
        // Draw enemy outline
        outlinecolor = al_map_rgb(225, 17, 17);
    }

    if (isflipped)
    {
        // Flip horizontally
        al_draw_scaled_rotated_bitmap(sprite, spriteoffset_x, spriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
        al_draw_tinted_scaled_rotated_bitmap(outline, outlinecolor, outlinespriteoffset_x, outlinespriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
    }
    else
    {
        al_draw_bitmap(sprite, x-spriteoffset_x - renderer->cam_x, y-spriteoffset_y - renderer->cam_y, 0);
        al_draw_tinted_bitmap(outline, outlinecolor, x-outlinespriteoffset_x - renderer->cam_x, y-outlinespriteoffset_y - renderer->cam_y, 0);
    }

    state->get<Weapon>(weapon)->render(renderer, state);
}

void Mccree::drawhud(Renderer *renderer, Gamestate *state)
{
    Character::drawhud(renderer, state);

    double space = 3;
    float r[8];

    ALLEGRO_BITMAP *sprite;
    Rect spriterect = renderer->spriteloader.get_rect("ui/ingame/mccree/rolling");
    if (rollcooldown.active)
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/rollingcooldown");
    }
    else
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/rolling");
    }
    spriterect.x = renderer->WINDOW_WIDTH*6/7.0 - spriterect.w*2 - space;
    spriterect.y = renderer->WINDOW_HEIGHT*hudheight()-spriterect.h;
    al_draw_bitmap(sprite, spriterect.x, spriterect.y, 0);
    if (rollcooldown.active)
    {
        // Draw the fill-in
        r[0] = spriterect.x+17*rollcooldown.getpercent();
        r[1] = spriterect.y+2+34*(1-rollcooldown.getpercent());

        r[2] = spriterect.x;
        r[3] = spriterect.y+spriterect.h-2;

        r[4] = spriterect.x+39;
        r[5] = spriterect.y+spriterect.h-2;

        r[6] = spriterect.x+17*rollcooldown.getpercent()+39;
        r[7] = spriterect.y+2+34*(1-rollcooldown.getpercent());

        al_draw_filled_polygon(r, 4, al_premul_rgba_f(239/255.0, 179/255.0, 89/255.0, 0.5));

        al_draw_text(renderer->font10, al_map_rgb(255, 255, 255), spriterect.x+spriterect.w/2.0+2, spriterect.y+spriterect.h/2.0-al_get_font_line_height(renderer->font10)/2.0,
                        ALLEGRO_ALIGN_CENTER, std::to_string((int)std::ceil(rollcooldown.duration - rollcooldown.timer)).c_str());
    }

    if (flashbangcooldown.active)
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/flashbangcooldown");
    }
    else
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/flashbang");
    }
    spriterect.x = spriterect.x + spriterect.w+space;
    al_draw_bitmap(sprite, spriterect.x, spriterect.y, 0);
    if (flashbangcooldown.active)
    {
        // Draw the fill-in
        r[0] = spriterect.x+17*flashbangcooldown.getpercent();
        r[1] = spriterect.y+2+34*(1-flashbangcooldown.getpercent());

        r[2] = spriterect.x;
        r[3] = spriterect.y+spriterect.h-2;

        r[4] = spriterect.x+39;
        r[5] = spriterect.y+spriterect.h-2;

        r[6] = spriterect.x+17*flashbangcooldown.getpercent()+39;
        r[7] = spriterect.y+2+34*(1-flashbangcooldown.getpercent());

        al_draw_filled_polygon(r, 4, al_premul_rgba_f(239/255.0, 179/255.0, 89/255.0, 0.5));

        al_draw_text(renderer->font10, al_map_rgb(255, 255, 255), spriterect.x+spriterect.w/2.0+2, spriterect.y+spriterect.h/2.0-al_get_font_line_height(renderer->font10)/2.0,
                        ALLEGRO_ALIGN_CENTER, std::to_string((int)std::ceil(flashbangcooldown.duration - flashbangcooldown.timer)).c_str());
    }
}

void Mccree::midstep(Gamestate *state, double frametime)
{
    Character::midstep(state, frametime);

    rollanim.update(state, frametime);
    if (rollanim.active())
    {
        if (isflipped)
        {
            hspeed = -360;
        }
        else
        {
            hspeed = 360;
        }
    }
    flashbanganim.update(state, frametime);
    rollcooldown.update(state, frametime);
    flashbangcooldown.update(state, frametime);
    ulting.update(state, frametime);

    if (isflipped)
    {
        ultwalkanim.update(state, -hspeed*frametime);
    }
    else
    {
        ultwalkanim.update(state, hspeed*frametime);
    }

    if (canuseabilities(state))
    {
        if (heldkeys.ABILITY_1 and not rollcooldown.active and onground(state) and state->engine->isserver)
        {
            useability1(state);
            state->engine->sendbuffer->write<uint8_t>(ABILITY1_USED);
            state->engine->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
        if (heldkeys.ABILITY_2 and not flashbangcooldown.active and state->engine->isserver)
        {
            useability2(state);
            state->engine->sendbuffer->write<uint8_t>(ABILITY2_USED);
            state->engine->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
    }

    if (ulting.active)
    {
        for (auto p : state->playerlist)
        {
            Player *player = state->get<Player>(p);
            if (player->team != SPECTATOR and player->team != team)
            {
                Character *c = player->getcharacter(state);
                if (c != 0)
                {
                    if (state->currentmap->collideline(getweapon(state)->x, getweapon(state)->y, c->x, c->y))
                    {
                        if (deadeyetargets.count(p) == 0)
                        {
                            deadeyetargets[p] = 0;
                        }
                        deadeyetargets[p] += frametime*170;
                    }
                }
            }
        }
    }
}

void Mccree::interpolate(Entity *prev_entity, Entity *next_entity, double alpha)
{
    Character::interpolate(prev_entity, next_entity, alpha);

    Mccree *p = static_cast<Mccree*>(prev_entity);
    Mccree *n = static_cast<Mccree*>(next_entity);

    rollanim.interpolate(&(p->rollanim), &(n->rollanim), alpha);
    rollcooldown.interpolate(&(p->rollcooldown), &(n->rollcooldown), alpha);
    flashbanganim.interpolate(&(p->flashbanganim), &(n->flashbanganim), alpha);
    flashbangcooldown.interpolate(&(p->flashbangcooldown), &(n->flashbangcooldown), alpha);
    ulting.interpolate(&(p->ulting), &(n->ulting), alpha);
    ultwalkanim.interpolate(&(p->ultwalkanim), &(n->ultwalkanim), alpha);
}

void Mccree::useability1(Gamestate *state)
{
    if (heldkeys.LEFT and not heldkeys.RIGHT)
    {
        isflipped = true;
    }
    else if (heldkeys.RIGHT and not heldkeys.LEFT)
    {
        isflipped = false;
    }
    // Lets roll
    rollanim.reset();
    rollcooldown.reset();
    Peacemaker *w = reinterpret_cast<Peacemaker*>(getweapon(state));
    w->clip = w->getclipsize();
    w->reloadanim.active(0);
    w->isfthing = false;
    w->fthanim.active(false);
    vspeed = 0;
}

void Mccree::useability2(Gamestate *state)
{
    // Flashbang
    flashbanganim.reset();
    flashbangcooldown.reset();
    Flashbang *f = state->get<Flashbang>(state->make_entity<Flashbang>(state, owner));
    f->x = x;
    f->y = y;
    double dir = std::atan2(mouse_y-y, mouse_x-x);
    f->hspeed = std::cos(dir) * 300;
    f->vspeed = std::sin(dir) * 300;
}

void Mccree::useultimate(Gamestate *state)
{
    ulting.reset();
    deadeyetargets.clear();
}

void Mccree::resetafterult(Gamestate *state)
{
    ulting.active = false;
    ultwalkanim.reset();
    Player *ownerplayer = state->get<Player>(owner);
    ownerplayer->ultcharge.active = true;
}

void Mccree::stun(Gamestate *state)
{
    Character::stun(state);

    if (ulting.active)
    {
        resetafterult(state);
    }
    rollanim.active(false);
}

Rect Mccree::getcollisionrect(Gamestate *state)
{
    if (crouchanim.active())
    {
        return state->engine->maskloader.get_rect_from_json("heroes/"+getcharacterfolder()+"crouch/").offset(x, y);
    }
    return getstandingcollisionrect(state);
}

Rect Mccree::getstandingcollisionrect(Gamestate *state)
{
    return state->engine->maskloader.get_rect_from_json("heroes/"+getcharacterfolder()).offset(x, y);
}

std::string Mccree::getsprite(Gamestate *state, bool mask)
{
    if (stunanim.active())
    {
        return stunanim.getframepath();
    }
    if (ulting.active)
    {
        if (std::fabs(hspeed) < 5.0 and not heldkeys.LEFT and not heldkeys.RIGHT)
        {
            return "heroes/"+getcharacterfolder()+"ult/1";
        }
        return ultwalkanim.getframepath();
    }
    if (rollanim.active())
    {
        return rollanim.getframepath();
    }
    if (crouchanim.active())
    {
        return crouchanim.getframepath();
    }
    if (not ongroundsmooth.active)
    {
        if (vspeed > 100)
        {
            return "heroes/"+getcharacterfolder()+"falling/1";
        }
        else
        {
            return "heroes/"+getcharacterfolder()+"jump/1";
        }
    }
    if (std::fabs(hspeed) < 11.0 and not heldkeys.LEFT and not heldkeys.RIGHT)
    {
        return "heroes/"+getcharacterfolder()+"idle/1";
    }
    return runanim.getframepath();
}

CharacterChildParameters Mccree::constructparameters(uint64_t id_, Gamestate *state, EntityPtr owner_)
{
    CharacterChildParameters p;
    p.runpower = 1.8;
    p.weapon = state->make_entity<Peacemaker>(state, owner_);
    p.maxhp.normal = 200;
    p.maxhp.armor = 0;
    p.maxhp.shields = 0;
    p.characterfolder = "heroes/mccree/";
    return p;
}

Health Mccree::getmaxhp()
{
    Health maxhp;
    maxhp.normal = 200;
    maxhp.armor = 0;
    maxhp.shields = 0;
    return maxhp;
}
<commit_msg>Temp commit for pc change, bug discovered.<commit_after>#include "ingameelements/heroes/mccree.h"
#include "datastructures.h"
#include "spriteloader.h"
#include "animation.h"
#include "gamestate.h"
#include "engine.h"
#include "ingameelements/projectiles/flashbang.h"

#include <memory>
#include <cmath>
#include <allegro5/allegro_primitives.h>

Mccree::Mccree(uint64_t id_, Gamestate *state, EntityPtr owner_) : Character(id_, state, owner_, constructparameters(id_, state, owner_)),
                rollanim("heroes/mccree/roll/"), flashbanganim("heroes/mccree/flashbang/"), rollcooldown(8), flashbangcooldown(10), ultwalkanim("heroes/mccree/ultwalk/"),
                ulting(std::bind(&Mccree::resetafterult, this, state), 6), deadeyetargets()
{
    rollanim.active(false);
    rollcooldown.active = false;
    flashbanganim.active(false);
    flashbangcooldown.active = false;
    ulting.active = false;
}

Mccree::~Mccree()
{
    //dtor
}

void Mccree::render(Renderer *renderer, Gamestate *state)
{
    Character::render(renderer, state);
    al_set_target_bitmap(renderer->midground);

    std::string mainsprite;
    ALLEGRO_BITMAP *sprite;
    int spriteoffset_x;
    int spriteoffset_y;

    if (flashbanganim.active())
    {
        std::string armsprite = flashbanganim.getframepath();
        sprite = renderer->spriteloader.requestsprite(armsprite);
        spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(armsprite);
        spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(armsprite);
        if (isflipped)
        {
            // Flip horizontally
            al_draw_scaled_rotated_bitmap(sprite, spriteoffset_x, spriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
        }
        else
        {
            al_draw_bitmap(sprite, x-spriteoffset_x - renderer->cam_x, y-spriteoffset_y - renderer->cam_y, 0);
        }
    }

    mainsprite = getsprite(state, false);
    sprite = renderer->spriteloader.requestsprite(mainsprite);
    spriteoffset_x = renderer->spriteloader.get_spriteoffset_x(mainsprite);
    spriteoffset_y = renderer->spriteloader.get_spriteoffset_y(mainsprite);

    std::string outlinesprite = mainsprite+"_outline";
    ALLEGRO_BITMAP *outline = renderer->spriteloader.requestsprite(outlinesprite);
    int outlinespriteoffset_x = renderer->spriteloader.get_spriteoffset_x(outlinesprite);
    int outlinespriteoffset_y = renderer->spriteloader.get_spriteoffset_y(outlinesprite);
    ALLEGRO_COLOR outlinecolor;
    if (state->get<Player>(renderer->myself)->team == team)
    {
        // Draw friendly outline
        outlinecolor = al_map_rgb(0, 145, 181);
    }
    else
    {
        // Draw enemy outline
        outlinecolor = al_map_rgb(225, 17, 17);
    }

    if (isflipped)
    {
        // Flip horizontally
        al_draw_scaled_rotated_bitmap(sprite, spriteoffset_x, spriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
        al_draw_tinted_scaled_rotated_bitmap(outline, outlinecolor, outlinespriteoffset_x, outlinespriteoffset_y, x-renderer->cam_x, y-renderer->cam_y, -1, 1, 0, 0);
    }
    else
    {
        al_draw_bitmap(sprite, x-spriteoffset_x - renderer->cam_x, y-spriteoffset_y - renderer->cam_y, 0);
        al_draw_tinted_bitmap(outline, outlinecolor, x-outlinespriteoffset_x - renderer->cam_x, y-outlinespriteoffset_y - renderer->cam_y, 0);
    }

    state->get<Weapon>(weapon)->render(renderer, state);
}

void Mccree::drawhud(Renderer *renderer, Gamestate *state)
{
    Character::drawhud(renderer, state);

    double space = 3;
    float r[8];

    ALLEGRO_BITMAP *sprite;
    Rect spriterect = renderer->spriteloader.get_rect("ui/ingame/mccree/rolling");
    if (rollcooldown.active)
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/rollingcooldown");
    }
    else
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/rolling");
    }
    spriterect.x = renderer->WINDOW_WIDTH*6/7.0 - spriterect.w*2 - space;
    spriterect.y = renderer->WINDOW_HEIGHT*hudheight()-spriterect.h;
    al_draw_bitmap(sprite, spriterect.x, spriterect.y, 0);
    if (rollcooldown.active)
    {
        // Draw the fill-in
        r[0] = spriterect.x+17*rollcooldown.getpercent();
        r[1] = spriterect.y+2+34*(1-rollcooldown.getpercent());

        r[2] = spriterect.x;
        r[3] = spriterect.y+spriterect.h-2;

        r[4] = spriterect.x+39;
        r[5] = spriterect.y+spriterect.h-2;

        r[6] = spriterect.x+17*rollcooldown.getpercent()+39;
        r[7] = spriterect.y+2+34*(1-rollcooldown.getpercent());

        al_draw_filled_polygon(r, 4, al_premul_rgba_f(239/255.0, 179/255.0, 89/255.0, 0.5));

        al_draw_text(renderer->font10, al_map_rgb(255, 255, 255), spriterect.x+spriterect.w/2.0+2, spriterect.y+spriterect.h/2.0-al_get_font_line_height(renderer->font10)/2.0,
                        ALLEGRO_ALIGN_CENTER, std::to_string((int)std::ceil(rollcooldown.duration - rollcooldown.timer)).c_str());
    }

    if (flashbangcooldown.active)
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/flashbangcooldown");
    }
    else
    {
        sprite = renderer->spriteloader.requestsprite("ui/ingame/mccree/flashbang");
    }
    spriterect.x = spriterect.x + spriterect.w+space;
    al_draw_bitmap(sprite, spriterect.x, spriterect.y, 0);
    if (flashbangcooldown.active)
    {
        // Draw the fill-in
        r[0] = spriterect.x+17*flashbangcooldown.getpercent();
        r[1] = spriterect.y+2+34*(1-flashbangcooldown.getpercent());

        r[2] = spriterect.x;
        r[3] = spriterect.y+spriterect.h-2;

        r[4] = spriterect.x+39;
        r[5] = spriterect.y+spriterect.h-2;

        r[6] = spriterect.x+17*flashbangcooldown.getpercent()+39;
        r[7] = spriterect.y+2+34*(1-flashbangcooldown.getpercent());

        al_draw_filled_polygon(r, 4, al_premul_rgba_f(239/255.0, 179/255.0, 89/255.0, 0.5));

        al_draw_text(renderer->font10, al_map_rgb(255, 255, 255), spriterect.x+spriterect.w/2.0+2, spriterect.y+spriterect.h/2.0-al_get_font_line_height(renderer->font10)/2.0,
                        ALLEGRO_ALIGN_CENTER, std::to_string((int)std::ceil(flashbangcooldown.duration - flashbangcooldown.timer)).c_str());
    }
}

void Mccree::midstep(Gamestate *state, double frametime)
{
    Character::midstep(state, frametime);

    rollanim.update(state, frametime);
    if (rollanim.active())
    {
        if (isflipped)
        {
            hspeed = -360;
        }
        else
        {
            hspeed = 360;
        }
    }
    flashbanganim.update(state, frametime);
    rollcooldown.update(state, frametime);
    flashbangcooldown.update(state, frametime);
    ulting.update(state, frametime);

    if (isflipped)
    {
        ultwalkanim.update(state, -hspeed*frametime);
    }
    else
    {
        ultwalkanim.update(state, hspeed*frametime);
    }

    if (canuseabilities(state))
    {
        if (heldkeys.ABILITY_1 and not rollcooldown.active and onground(state) and state->engine->isserver)
        {
            useability1(state);
            state->engine->sendbuffer->write<uint8_t>(ABILITY1_USED);
            state->engine->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
        if (heldkeys.ABILITY_2 and not flashbangcooldown.active and state->engine->isserver)
        {
            useability2(state);
            state->engine->sendbuffer->write<uint8_t>(ABILITY2_USED);
            state->engine->sendbuffer->write<uint8_t>(state->findplayerid(owner));
        }
    }

    if (ulting.active)
    {
        for (auto p : state->playerlist)
        {
            Player *player = state->get<Player>(p);
            if (player->team != SPECTATOR and player->team != team)
            {
                Character *c = player->getcharacter(state);
                if (c != 0)
                {
                    printf("\n%d %d %d %d", getweapon(state)->x, getweapon(state)->y, c->x, c->y);
                    if (not state->currentmap->collideline(getweapon(state)->x, getweapon(state)->y, c->x, c->y))
                    {
                        if (deadeyetargets.count(p) == 0)
                        {
                            deadeyetargets[p] = 0;
                        }
                        deadeyetargets[p] += frametime*170;
                    }
                }
            }
        }
    }
}

void Mccree::interpolate(Entity *prev_entity, Entity *next_entity, double alpha)
{
    Character::interpolate(prev_entity, next_entity, alpha);

    Mccree *p = static_cast<Mccree*>(prev_entity);
    Mccree *n = static_cast<Mccree*>(next_entity);

    rollanim.interpolate(&(p->rollanim), &(n->rollanim), alpha);
    rollcooldown.interpolate(&(p->rollcooldown), &(n->rollcooldown), alpha);
    flashbanganim.interpolate(&(p->flashbanganim), &(n->flashbanganim), alpha);
    flashbangcooldown.interpolate(&(p->flashbangcooldown), &(n->flashbangcooldown), alpha);
    ulting.interpolate(&(p->ulting), &(n->ulting), alpha);
    ultwalkanim.interpolate(&(p->ultwalkanim), &(n->ultwalkanim), alpha);
}

void Mccree::useability1(Gamestate *state)
{
    if (heldkeys.LEFT and not heldkeys.RIGHT)
    {
        isflipped = true;
    }
    else if (heldkeys.RIGHT and not heldkeys.LEFT)
    {
        isflipped = false;
    }
    // Lets roll
    rollanim.reset();
    rollcooldown.reset();
    Peacemaker *w = reinterpret_cast<Peacemaker*>(getweapon(state));
    w->clip = w->getclipsize();
    w->reloadanim.active(0);
    w->isfthing = false;
    w->fthanim.active(false);
    vspeed = 0;
}

void Mccree::useability2(Gamestate *state)
{
    // Flashbang
    flashbanganim.reset();
    flashbangcooldown.reset();
    Flashbang *f = state->get<Flashbang>(state->make_entity<Flashbang>(state, owner));
    f->x = x;
    f->y = y;
    double dir = std::atan2(mouse_y-y, mouse_x-x);
    f->hspeed = std::cos(dir) * 300;
    f->vspeed = std::sin(dir) * 300;
}

void Mccree::useultimate(Gamestate *state)
{
    ulting.reset();
    deadeyetargets.clear();
}

void Mccree::resetafterult(Gamestate *state)
{
    ulting.active = false;
    ultwalkanim.reset();
    Player *ownerplayer = state->get<Player>(owner);
    ownerplayer->ultcharge.active = true;
}

void Mccree::stun(Gamestate *state)
{
    Character::stun(state);

    if (ulting.active)
    {
        resetafterult(state);
    }
    rollanim.active(false);
}

Rect Mccree::getcollisionrect(Gamestate *state)
{
    if (crouchanim.active())
    {
        return state->engine->maskloader.get_rect_from_json("heroes/"+getcharacterfolder()+"crouch/").offset(x, y);
    }
    return getstandingcollisionrect(state);
}

Rect Mccree::getstandingcollisionrect(Gamestate *state)
{
    return state->engine->maskloader.get_rect_from_json("heroes/"+getcharacterfolder()).offset(x, y);
}

std::string Mccree::getsprite(Gamestate *state, bool mask)
{
    if (stunanim.active())
    {
        return stunanim.getframepath();
    }
    if (ulting.active)
    {
        if (std::fabs(hspeed) < 5.0 and not heldkeys.LEFT and not heldkeys.RIGHT)
        {
            return "heroes/"+getcharacterfolder()+"ult/1";
        }
        return ultwalkanim.getframepath();
    }
    if (rollanim.active())
    {
        return rollanim.getframepath();
    }
    if (crouchanim.active())
    {
        return crouchanim.getframepath();
    }
    if (not ongroundsmooth.active)
    {
        if (vspeed > 100)
        {
            return "heroes/"+getcharacterfolder()+"falling/1";
        }
        else
        {
            return "heroes/"+getcharacterfolder()+"jump/1";
        }
    }
    if (std::fabs(hspeed) < 11.0 and not heldkeys.LEFT and not heldkeys.RIGHT)
    {
        return "heroes/"+getcharacterfolder()+"idle/1";
    }
    return runanim.getframepath();
}

CharacterChildParameters Mccree::constructparameters(uint64_t id_, Gamestate *state, EntityPtr owner_)
{
    CharacterChildParameters p;
    p.runpower = 1.8;
    p.weapon = state->make_entity<Peacemaker>(state, owner_);
    p.maxhp.normal = 200;
    p.maxhp.armor = 0;
    p.maxhp.shields = 0;
    p.characterfolder = "heroes/mccree/";
    return p;
}

Health Mccree::getmaxhp()
{
    Health maxhp;
    maxhp.normal = 200;
    maxhp.armor = 0;
    maxhp.shields = 0;
    return maxhp;
}
<|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 "arrow/flight/server.h"
#include "arrow/flight/protocol-internal.h"

#include <signal.h>
#include <atomic>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>

#include "arrow/util/config.h"
#ifdef GRPCPP_PP_INCLUDE
#include <grpcpp/grpcpp.h>
#else
#include <grpc++/grpc++.h>
#endif

#include "arrow/ipc/dictionary.h"
#include "arrow/ipc/reader.h"
#include "arrow/ipc/writer.h"
#include "arrow/memory_pool.h"
#include "arrow/record_batch.h"
#include "arrow/status.h"
#include "arrow/util/logging.h"

#include "arrow/flight/internal.h"
#include "arrow/flight/serialization-internal.h"
#include "arrow/flight/types.h"

using FlightService = arrow::flight::protocol::FlightService;
using ServerContext = grpc::ServerContext;

template <typename T>
using ServerWriter = grpc::ServerWriter<T>;

namespace pb = arrow::flight::protocol;

namespace arrow {
namespace flight {

#define CHECK_ARG_NOT_NULL(VAL, MESSAGE)                              \
  if (VAL == nullptr) {                                               \
    return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, MESSAGE); \
  }

class FlightMessageReaderImpl : public FlightMessageReader {
 public:
  FlightMessageReaderImpl(const FlightDescriptor& descriptor,
                          std::shared_ptr<Schema> schema,
                          grpc::ServerReader<pb::FlightData>* reader)
      : descriptor_(descriptor),
        schema_(schema),
        reader_(reader),
        stream_finished_(false) {}

  const FlightDescriptor& descriptor() const override { return descriptor_; }

  std::shared_ptr<Schema> schema() const override { return schema_; }

  Status ReadNext(std::shared_ptr<RecordBatch>* out) override {
    if (stream_finished_) {
      *out = nullptr;
      return Status::OK();
    }

    internal::FlightData data;
    // Pretend to be pb::FlightData and intercept in SerializationTraits
#ifndef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
    if (reader_->Read(reinterpret_cast<pb::FlightData*>(&data))) {
#ifndef _WIN32
#pragma GCC diagnostic pop
#endif
      std::unique_ptr<ipc::Message> message;

      // Validate IPC message
      RETURN_NOT_OK(ipc::Message::Open(data.metadata, data.body, &message));
      if (message->type() == ipc::Message::Type::RECORD_BATCH) {
        return ipc::ReadRecordBatch(*message, schema_, out);
      } else {
        return Status(StatusCode::Invalid, "Unrecognized message in Flight stream");
      }
    } else {
      // Stream is completed
      stream_finished_ = true;
      *out = nullptr;
      return Status::OK();
    }
  }

 private:
  FlightDescriptor descriptor_;
  std::shared_ptr<Schema> schema_;
  grpc::ServerReader<pb::FlightData>* reader_;
  bool stream_finished_;
};

// This class glues an implementation of FlightServerBase together with the
// gRPC service definition, so the latter is not exposed in the public API
class FlightServiceImpl : public FlightService::Service {
 public:
  explicit FlightServiceImpl(FlightServerBase* server) : server_(server) {}

  template <typename UserType, typename Iterator, typename ProtoType>
  grpc::Status WriteStream(Iterator* iterator, ServerWriter<ProtoType>* writer) {
    if (!iterator) {
      return grpc::Status(grpc::StatusCode::INTERNAL, "No items to iterate");
    }
    // Write flight info to stream until listing is exhausted
    ProtoType pb_value;
    std::unique_ptr<UserType> value;
    while (true) {
      GRPC_RETURN_NOT_OK(iterator->Next(&value));
      if (!value) {
        break;
      }
      GRPC_RETURN_NOT_OK(internal::ToProto(*value, &pb_value));

      // Blocking write
      if (!writer->Write(pb_value)) {
        // Write returns false if the stream is closed
        break;
      }
    }
    return grpc::Status::OK;
  }

  template <typename UserType, typename ProtoType>
  grpc::Status WriteStream(const std::vector<UserType>& values,
                           ServerWriter<ProtoType>* writer) {
    // Write flight info to stream until listing is exhausted
    ProtoType pb_value;
    for (const UserType& value : values) {
      GRPC_RETURN_NOT_OK(internal::ToProto(value, &pb_value));
      // Blocking write
      if (!writer->Write(pb_value)) {
        // Write returns false if the stream is closed
        break;
      }
    }
    return grpc::Status::OK;
  }

  grpc::Status ListFlights(ServerContext* context, const pb::Criteria* request,
                           ServerWriter<pb::FlightGetInfo>* writer) {
    // Retrieve the listing from the implementation
    std::unique_ptr<FlightListing> listing;

    Criteria criteria;
    if (request) {
      GRPC_RETURN_NOT_OK(internal::FromProto(*request, &criteria));
    }
    GRPC_RETURN_NOT_OK(server_->ListFlights(&criteria, &listing));
    if (!listing) {
      // Treat null listing as no flights available
      return grpc::Status::OK;
    }
    return WriteStream<FlightInfo>(listing.get(), writer);
  }

  grpc::Status GetFlightInfo(ServerContext* context, const pb::FlightDescriptor* request,
                             pb::FlightGetInfo* response) {
    CHECK_ARG_NOT_NULL(request, "FlightDescriptor cannot be null");

    FlightDescriptor descr;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &descr));

    std::unique_ptr<FlightInfo> info;
    GRPC_RETURN_NOT_OK(server_->GetFlightInfo(descr, &info));

    if (!info) {
      // Treat null listing as no flights available
      return grpc::Status(grpc::StatusCode::NOT_FOUND, "Flight not found");
    }

    GRPC_RETURN_NOT_OK(internal::ToProto(*info, response));
    return grpc::Status::OK;
  }

  grpc::Status DoGet(ServerContext* context, const pb::Ticket* request,
                     ServerWriter<pb::FlightData>* writer) {
    CHECK_ARG_NOT_NULL(request, "ticket cannot be null");

    Ticket ticket;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &ticket));

    std::unique_ptr<FlightDataStream> data_stream;
    GRPC_RETURN_NOT_OK(server_->DoGet(ticket, &data_stream));

    if (!data_stream) {
      return grpc::Status(grpc::StatusCode::NOT_FOUND, "No data in this flight");
    }

    // Write the schema as the first message in the stream
    FlightPayload schema_payload;
    MemoryPool* pool = default_memory_pool();
    ipc::DictionaryMemo dictionary_memo;
    GRPC_RETURN_NOT_OK(ipc::internal::GetSchemaPayload(
        *data_stream->schema(), pool, &dictionary_memo, &schema_payload.ipc_message));

    // Pretend to be pb::FlightData, we cast back to FlightPayload in
    // SerializationTraits
#ifndef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
    writer->Write(*reinterpret_cast<const pb::FlightData*>(&schema_payload),
                  grpc::WriteOptions());

    while (true) {
      FlightPayload payload;
      GRPC_RETURN_NOT_OK(data_stream->Next(&payload));
      if (payload.ipc_message.metadata == nullptr ||
          !writer->Write(*reinterpret_cast<const pb::FlightData*>(&payload),
                         grpc::WriteOptions())) {
        // No more messages to write, or connection terminated for some other
        // reason
        break;
      }
    }
#ifndef _WIN32
#pragma GCC diagnostic pop
#endif
    return grpc::Status::OK;
  }

  grpc::Status DoPut(ServerContext* context, grpc::ServerReader<pb::FlightData>* reader,
                     pb::PutResult* response) {
    // Get metadata
    internal::FlightData data;
    if (reader->Read(reinterpret_cast<pb::FlightData*>(&data))) {
      // Message only lives as long as data
      std::unique_ptr<ipc::Message> message;
      GRPC_RETURN_NOT_OK(ipc::Message::Open(data.metadata, data.body, &message));

      if (!message || message->type() != ipc::Message::Type::SCHEMA) {
        return internal::ToGrpcStatus(
            Status(StatusCode::Invalid, "DoPut must start with schema/descriptor"));
      } else if (!data.descriptor) {
        return internal::ToGrpcStatus(
            Status(StatusCode::Invalid, "DoPut must start with non-null descriptor"));
      } else {
        std::shared_ptr<Schema> schema;
        GRPC_RETURN_NOT_OK(ipc::ReadSchema(*message, &schema));

        auto message_reader = std::unique_ptr<FlightMessageReader>(
            new FlightMessageReaderImpl(*data.descriptor.get(), schema, reader));
        return internal::ToGrpcStatus(server_->DoPut(std::move(message_reader)));
      }
    } else {
      return internal::ToGrpcStatus(
          Status(StatusCode::Invalid,
                 "Client provided malformed message or did not provide message"));
    }
  }

  grpc::Status ListActions(ServerContext* context, const pb::Empty* request,
                           ServerWriter<pb::ActionType>* writer) {
    // Retrieve the listing from the implementation
    std::vector<ActionType> types;
    GRPC_RETURN_NOT_OK(server_->ListActions(&types));
    return WriteStream<ActionType>(types, writer);
  }

  grpc::Status DoAction(ServerContext* context, const pb::Action* request,
                        ServerWriter<pb::Result>* writer) {
    CHECK_ARG_NOT_NULL(request, "Action cannot be null");
    Action action;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &action));

    std::unique_ptr<ResultStream> results;
    GRPC_RETURN_NOT_OK(server_->DoAction(action, &results));

    if (!results) {
      return grpc::Status::CANCELLED;
    }

    while (true) {
      std::unique_ptr<Result> result;
      GRPC_RETURN_NOT_OK(results->Next(&result));
      if (!result) {
        // No more results
        break;
      }
      pb::Result pb_result;
      GRPC_RETURN_NOT_OK(internal::ToProto(*result, &pb_result));
      if (!writer->Write(pb_result)) {
        // Stream may be closed
        break;
      }
    }
    return grpc::Status::OK;
  }

 private:
  FlightServerBase* server_;
};

#if (ATOMIC_INT_LOCK_FREE != 2 || ATOMIC_POINTER_LOCK_FREE != 2)
#error "atomic ints and atomic pointers not always lock-free!"
#endif

struct FlightServerBase::Impl {
  std::string address_;
  std::unique_ptr<FlightServiceImpl> service_;
  std::unique_ptr<grpc::Server> server_;

  // Signal handling
  std::vector<int> signals_;
  std::vector<struct sigaction> old_signal_handlers_;
  std::atomic<int> got_signal_;
  static thread_local std::atomic<Impl*> running_instance_;

  static void HandleSignal(int signum);

  void DoHandleSignal(int signum) {
    got_signal_ = signum;
    server_->Shutdown();
  }
};

thread_local std::atomic<FlightServerBase::Impl*>
    FlightServerBase::Impl::running_instance_;

void FlightServerBase::Impl::HandleSignal(int signum) {
  auto instance = running_instance_.load();
  if (instance != nullptr) {
    instance->DoHandleSignal(signum);
  }
}

FlightServerBase::FlightServerBase() { impl_.reset(new Impl); }

FlightServerBase::~FlightServerBase() {}

Status FlightServerBase::Init(int port) {
  impl_->address_ = "localhost:" + std::to_string(port);
  impl_->service_.reset(new FlightServiceImpl(this));

  grpc::ServerBuilder builder;
  // Allow uploading messages of any length
  builder.SetMaxReceiveMessageSize(-1);
  builder.AddListeningPort(impl_->address_, grpc::InsecureServerCredentials());
  builder.RegisterService(impl_->service_.get());

  impl_->server_ = builder.BuildAndStart();
  return Status::OK();
}

Status FlightServerBase::SetShutdownOnSignals(const std::vector<int> sigs) {
  impl_->signals_ = sigs;
  impl_->old_signal_handlers_.clear();
  return Status::OK();
}

Status FlightServerBase::Serve() {
  impl_->got_signal_ = 0;
  impl_->running_instance_ = impl_.get();

  // Setup signal handlers
  impl_->old_signal_handlers_.clear();
  for (size_t i = 0; i < impl_->signals_.size(); ++i) {
    int signum = impl_->signals_[i];
    // Override with our own handler so as to stop the server.
    struct sigaction sa, old_handler;
    sa.sa_handler = &Impl::HandleSignal;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    int ret = sigaction(signum, &sa, &old_handler);
    if (ret != 0) {
      return Status::IOError("sigaction call failed");
    }
    impl_->old_signal_handlers_.push_back(old_handler);
  }

  // TODO(wesm): How can we tell if the server failed to start for some reason?
  impl_->server_->Wait();
  impl_->running_instance_ = nullptr;

  // Restore signal handlers
  for (size_t i = 0; i < impl_->signals_.size(); ++i) {
    int ret = sigaction(impl_->signals_[i], &impl_->old_signal_handlers_[i], nullptr);
    if (ret != 0) {
      return Status::IOError("sigaction call failed");
    }
  }

  return Status::OK();
}

int FlightServerBase::GotSignal() const { return impl_->got_signal_; }

void FlightServerBase::Shutdown() {
  DCHECK(impl_->server_);
  impl_->server_->Shutdown();
}

Status FlightServerBase::ListFlights(const Criteria* criteria,
                                     std::unique_ptr<FlightListing>* listings) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::GetFlightInfo(const FlightDescriptor& request,
                                       std::unique_ptr<FlightInfo>* info) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoGet(const Ticket& request,
                               std::unique_ptr<FlightDataStream>* data_stream) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoPut(std::unique_ptr<FlightMessageReader> reader) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoAction(const Action& action,
                                  std::unique_ptr<ResultStream>* result) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::ListActions(std::vector<ActionType>* actions) {
  return Status::NotImplemented("NYI");
}

// ----------------------------------------------------------------------
// Implement RecordBatchStream

RecordBatchStream::RecordBatchStream(const std::shared_ptr<RecordBatchReader>& reader)
    : pool_(default_memory_pool()), reader_(reader) {}

std::shared_ptr<Schema> RecordBatchStream::schema() { return reader_->schema(); }

Status RecordBatchStream::Next(FlightPayload* payload) {
  std::shared_ptr<RecordBatch> batch;
  RETURN_NOT_OK(reader_->ReadNext(&batch));

  if (!batch) {
    // Signal that iteration is over
    payload->ipc_message.metadata = nullptr;
    return Status::OK();
  } else {
    return ipc::internal::GetRecordBatchPayload(*batch, pool_, &payload->ipc_message);
  }
}

}  // namespace flight
}  // namespace arrow
<commit_msg>ARROW-4984: Check if Flight gRPC server starts properly<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 "arrow/flight/server.h"
#include "arrow/flight/protocol-internal.h"

#include <signal.h>
#include <atomic>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>

#include "arrow/util/config.h"
#ifdef GRPCPP_PP_INCLUDE
#include <grpcpp/grpcpp.h>
#else
#include <grpc++/grpc++.h>
#endif

#include "arrow/ipc/dictionary.h"
#include "arrow/ipc/reader.h"
#include "arrow/ipc/writer.h"
#include "arrow/memory_pool.h"
#include "arrow/record_batch.h"
#include "arrow/status.h"
#include "arrow/util/logging.h"

#include "arrow/flight/internal.h"
#include "arrow/flight/serialization-internal.h"
#include "arrow/flight/types.h"

using FlightService = arrow::flight::protocol::FlightService;
using ServerContext = grpc::ServerContext;

template <typename T>
using ServerWriter = grpc::ServerWriter<T>;

namespace pb = arrow::flight::protocol;

namespace arrow {
namespace flight {

#define CHECK_ARG_NOT_NULL(VAL, MESSAGE)                              \
  if (VAL == nullptr) {                                               \
    return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, MESSAGE); \
  }

class FlightMessageReaderImpl : public FlightMessageReader {
 public:
  FlightMessageReaderImpl(const FlightDescriptor& descriptor,
                          std::shared_ptr<Schema> schema,
                          grpc::ServerReader<pb::FlightData>* reader)
      : descriptor_(descriptor),
        schema_(schema),
        reader_(reader),
        stream_finished_(false) {}

  const FlightDescriptor& descriptor() const override { return descriptor_; }

  std::shared_ptr<Schema> schema() const override { return schema_; }

  Status ReadNext(std::shared_ptr<RecordBatch>* out) override {
    if (stream_finished_) {
      *out = nullptr;
      return Status::OK();
    }

    internal::FlightData data;
    // Pretend to be pb::FlightData and intercept in SerializationTraits
#ifndef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
    if (reader_->Read(reinterpret_cast<pb::FlightData*>(&data))) {
#ifndef _WIN32
#pragma GCC diagnostic pop
#endif
      std::unique_ptr<ipc::Message> message;

      // Validate IPC message
      RETURN_NOT_OK(ipc::Message::Open(data.metadata, data.body, &message));
      if (message->type() == ipc::Message::Type::RECORD_BATCH) {
        return ipc::ReadRecordBatch(*message, schema_, out);
      } else {
        return Status(StatusCode::Invalid, "Unrecognized message in Flight stream");
      }
    } else {
      // Stream is completed
      stream_finished_ = true;
      *out = nullptr;
      return Status::OK();
    }
  }

 private:
  FlightDescriptor descriptor_;
  std::shared_ptr<Schema> schema_;
  grpc::ServerReader<pb::FlightData>* reader_;
  bool stream_finished_;
};

// This class glues an implementation of FlightServerBase together with the
// gRPC service definition, so the latter is not exposed in the public API
class FlightServiceImpl : public FlightService::Service {
 public:
  explicit FlightServiceImpl(FlightServerBase* server) : server_(server) {}

  template <typename UserType, typename Iterator, typename ProtoType>
  grpc::Status WriteStream(Iterator* iterator, ServerWriter<ProtoType>* writer) {
    if (!iterator) {
      return grpc::Status(grpc::StatusCode::INTERNAL, "No items to iterate");
    }
    // Write flight info to stream until listing is exhausted
    ProtoType pb_value;
    std::unique_ptr<UserType> value;
    while (true) {
      GRPC_RETURN_NOT_OK(iterator->Next(&value));
      if (!value) {
        break;
      }
      GRPC_RETURN_NOT_OK(internal::ToProto(*value, &pb_value));

      // Blocking write
      if (!writer->Write(pb_value)) {
        // Write returns false if the stream is closed
        break;
      }
    }
    return grpc::Status::OK;
  }

  template <typename UserType, typename ProtoType>
  grpc::Status WriteStream(const std::vector<UserType>& values,
                           ServerWriter<ProtoType>* writer) {
    // Write flight info to stream until listing is exhausted
    ProtoType pb_value;
    for (const UserType& value : values) {
      GRPC_RETURN_NOT_OK(internal::ToProto(value, &pb_value));
      // Blocking write
      if (!writer->Write(pb_value)) {
        // Write returns false if the stream is closed
        break;
      }
    }
    return grpc::Status::OK;
  }

  grpc::Status ListFlights(ServerContext* context, const pb::Criteria* request,
                           ServerWriter<pb::FlightGetInfo>* writer) {
    // Retrieve the listing from the implementation
    std::unique_ptr<FlightListing> listing;

    Criteria criteria;
    if (request) {
      GRPC_RETURN_NOT_OK(internal::FromProto(*request, &criteria));
    }
    GRPC_RETURN_NOT_OK(server_->ListFlights(&criteria, &listing));
    if (!listing) {
      // Treat null listing as no flights available
      return grpc::Status::OK;
    }
    return WriteStream<FlightInfo>(listing.get(), writer);
  }

  grpc::Status GetFlightInfo(ServerContext* context, const pb::FlightDescriptor* request,
                             pb::FlightGetInfo* response) {
    CHECK_ARG_NOT_NULL(request, "FlightDescriptor cannot be null");

    FlightDescriptor descr;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &descr));

    std::unique_ptr<FlightInfo> info;
    GRPC_RETURN_NOT_OK(server_->GetFlightInfo(descr, &info));

    if (!info) {
      // Treat null listing as no flights available
      return grpc::Status(grpc::StatusCode::NOT_FOUND, "Flight not found");
    }

    GRPC_RETURN_NOT_OK(internal::ToProto(*info, response));
    return grpc::Status::OK;
  }

  grpc::Status DoGet(ServerContext* context, const pb::Ticket* request,
                     ServerWriter<pb::FlightData>* writer) {
    CHECK_ARG_NOT_NULL(request, "ticket cannot be null");

    Ticket ticket;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &ticket));

    std::unique_ptr<FlightDataStream> data_stream;
    GRPC_RETURN_NOT_OK(server_->DoGet(ticket, &data_stream));

    if (!data_stream) {
      return grpc::Status(grpc::StatusCode::NOT_FOUND, "No data in this flight");
    }

    // Write the schema as the first message in the stream
    FlightPayload schema_payload;
    MemoryPool* pool = default_memory_pool();
    ipc::DictionaryMemo dictionary_memo;
    GRPC_RETURN_NOT_OK(ipc::internal::GetSchemaPayload(
        *data_stream->schema(), pool, &dictionary_memo, &schema_payload.ipc_message));

    // Pretend to be pb::FlightData, we cast back to FlightPayload in
    // SerializationTraits
#ifndef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
    writer->Write(*reinterpret_cast<const pb::FlightData*>(&schema_payload),
                  grpc::WriteOptions());

    while (true) {
      FlightPayload payload;
      GRPC_RETURN_NOT_OK(data_stream->Next(&payload));
      if (payload.ipc_message.metadata == nullptr ||
          !writer->Write(*reinterpret_cast<const pb::FlightData*>(&payload),
                         grpc::WriteOptions())) {
        // No more messages to write, or connection terminated for some other
        // reason
        break;
      }
    }
#ifndef _WIN32
#pragma GCC diagnostic pop
#endif
    return grpc::Status::OK;
  }

  grpc::Status DoPut(ServerContext* context, grpc::ServerReader<pb::FlightData>* reader,
                     pb::PutResult* response) {
    // Get metadata
    internal::FlightData data;
    if (reader->Read(reinterpret_cast<pb::FlightData*>(&data))) {
      // Message only lives as long as data
      std::unique_ptr<ipc::Message> message;
      GRPC_RETURN_NOT_OK(ipc::Message::Open(data.metadata, data.body, &message));

      if (!message || message->type() != ipc::Message::Type::SCHEMA) {
        return internal::ToGrpcStatus(
            Status(StatusCode::Invalid, "DoPut must start with schema/descriptor"));
      } else if (!data.descriptor) {
        return internal::ToGrpcStatus(
            Status(StatusCode::Invalid, "DoPut must start with non-null descriptor"));
      } else {
        std::shared_ptr<Schema> schema;
        GRPC_RETURN_NOT_OK(ipc::ReadSchema(*message, &schema));

        auto message_reader = std::unique_ptr<FlightMessageReader>(
            new FlightMessageReaderImpl(*data.descriptor.get(), schema, reader));
        return internal::ToGrpcStatus(server_->DoPut(std::move(message_reader)));
      }
    } else {
      return internal::ToGrpcStatus(
          Status(StatusCode::Invalid,
                 "Client provided malformed message or did not provide message"));
    }
  }

  grpc::Status ListActions(ServerContext* context, const pb::Empty* request,
                           ServerWriter<pb::ActionType>* writer) {
    // Retrieve the listing from the implementation
    std::vector<ActionType> types;
    GRPC_RETURN_NOT_OK(server_->ListActions(&types));
    return WriteStream<ActionType>(types, writer);
  }

  grpc::Status DoAction(ServerContext* context, const pb::Action* request,
                        ServerWriter<pb::Result>* writer) {
    CHECK_ARG_NOT_NULL(request, "Action cannot be null");
    Action action;
    GRPC_RETURN_NOT_OK(internal::FromProto(*request, &action));

    std::unique_ptr<ResultStream> results;
    GRPC_RETURN_NOT_OK(server_->DoAction(action, &results));

    if (!results) {
      return grpc::Status::CANCELLED;
    }

    while (true) {
      std::unique_ptr<Result> result;
      GRPC_RETURN_NOT_OK(results->Next(&result));
      if (!result) {
        // No more results
        break;
      }
      pb::Result pb_result;
      GRPC_RETURN_NOT_OK(internal::ToProto(*result, &pb_result));
      if (!writer->Write(pb_result)) {
        // Stream may be closed
        break;
      }
    }
    return grpc::Status::OK;
  }

 private:
  FlightServerBase* server_;
};

#if (ATOMIC_INT_LOCK_FREE != 2 || ATOMIC_POINTER_LOCK_FREE != 2)
#error "atomic ints and atomic pointers not always lock-free!"
#endif

struct FlightServerBase::Impl {
  std::string address_;
  std::unique_ptr<FlightServiceImpl> service_;
  std::unique_ptr<grpc::Server> server_;

  // Signal handling
  std::vector<int> signals_;
  std::vector<struct sigaction> old_signal_handlers_;
  std::atomic<int> got_signal_;
  static thread_local std::atomic<Impl*> running_instance_;

  static void HandleSignal(int signum);

  void DoHandleSignal(int signum) {
    got_signal_ = signum;
    server_->Shutdown();
  }
};

thread_local std::atomic<FlightServerBase::Impl*>
    FlightServerBase::Impl::running_instance_;

void FlightServerBase::Impl::HandleSignal(int signum) {
  auto instance = running_instance_.load();
  if (instance != nullptr) {
    instance->DoHandleSignal(signum);
  }
}

FlightServerBase::FlightServerBase() { impl_.reset(new Impl); }

FlightServerBase::~FlightServerBase() {}

Status FlightServerBase::Init(int port) {
  impl_->address_ = "localhost:" + std::to_string(port);
  impl_->service_.reset(new FlightServiceImpl(this));

  grpc::ServerBuilder builder;
  // Allow uploading messages of any length
  builder.SetMaxReceiveMessageSize(-1);
  builder.AddListeningPort(impl_->address_, grpc::InsecureServerCredentials());
  builder.RegisterService(impl_->service_.get());

  impl_->server_ = builder.BuildAndStart();
  if (!impl_->server_) {
    return Status::UnknownError("Server did not start properly");
  }
  return Status::OK();
}

Status FlightServerBase::SetShutdownOnSignals(const std::vector<int> sigs) {
  impl_->signals_ = sigs;
  impl_->old_signal_handlers_.clear();
  return Status::OK();
}

Status FlightServerBase::Serve() {
  if (!impl_->server_) {
    return Status::UnknownError("Server did not start properly");
  }

  impl_->got_signal_ = 0;
  impl_->running_instance_ = impl_.get();

  // Setup signal handlers
  impl_->old_signal_handlers_.clear();
  for (size_t i = 0; i < impl_->signals_.size(); ++i) {
    int signum = impl_->signals_[i];
    // Override with our own handler so as to stop the server.
    struct sigaction sa, old_handler;
    sa.sa_handler = &Impl::HandleSignal;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    int ret = sigaction(signum, &sa, &old_handler);
    if (ret != 0) {
      return Status::IOError("sigaction call failed");
    }
    impl_->old_signal_handlers_.push_back(old_handler);
  }

  impl_->server_->Wait();
  impl_->running_instance_ = nullptr;

  // Restore signal handlers
  for (size_t i = 0; i < impl_->signals_.size(); ++i) {
    int ret = sigaction(impl_->signals_[i], &impl_->old_signal_handlers_[i], nullptr);
    if (ret != 0) {
      return Status::IOError("sigaction call failed");
    }
  }

  return Status::OK();
}

int FlightServerBase::GotSignal() const { return impl_->got_signal_; }

void FlightServerBase::Shutdown() {
  DCHECK(impl_->server_);
  impl_->server_->Shutdown();
}

Status FlightServerBase::ListFlights(const Criteria* criteria,
                                     std::unique_ptr<FlightListing>* listings) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::GetFlightInfo(const FlightDescriptor& request,
                                       std::unique_ptr<FlightInfo>* info) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoGet(const Ticket& request,
                               std::unique_ptr<FlightDataStream>* data_stream) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoPut(std::unique_ptr<FlightMessageReader> reader) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::DoAction(const Action& action,
                                  std::unique_ptr<ResultStream>* result) {
  return Status::NotImplemented("NYI");
}

Status FlightServerBase::ListActions(std::vector<ActionType>* actions) {
  return Status::NotImplemented("NYI");
}

// ----------------------------------------------------------------------
// Implement RecordBatchStream

RecordBatchStream::RecordBatchStream(const std::shared_ptr<RecordBatchReader>& reader)
    : pool_(default_memory_pool()), reader_(reader) {}

std::shared_ptr<Schema> RecordBatchStream::schema() { return reader_->schema(); }

Status RecordBatchStream::Next(FlightPayload* payload) {
  std::shared_ptr<RecordBatch> batch;
  RETURN_NOT_OK(reader_->ReadNext(&batch));

  if (!batch) {
    // Signal that iteration is over
    payload->ipc_message.metadata = nullptr;
    return Status::OK();
  } else {
    return ipc::internal::GetRecordBatchPayload(*batch, pool_, &payload->ipc_message);
  }
}

}  // namespace flight
}  // namespace arrow
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 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 "host/commands/wifirouter/router.h"

#include <cerrno>
#include <cstddef>
#include <map>
#include <memory>
#include <set>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/genl.h>
#include <netlink/netlink.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

DEFINE_string(socket_name, "cvd-wifirouter",
              "Name of the unix-domain socket providing access for routing. "
              "Socket will be created in abstract namespace.");

namespace cvd {
namespace {
using MacHash = uint64_t;
using MacToClientsTable = std::multimap<MacHash, int>;
using ClientsTable = std::set<int>;

// Copied out of mac80211_hwsim.h header.
constexpr int HWSIM_CMD_REGISTER = 1;
constexpr int HWSIM_ATTR_ADDR_TRANSMITTER = 2;
constexpr int HWSIM_ATTR_MAX = 19;

// Name of the WIFI SIM Netlink Family.
constexpr char kWifiSimFamilyName[] = "MAC80211_HWSIM";
const int kMaxSupportedPacketSize = getpagesize();

// Get hash for mac address serialized to 6 bytes of data starting at specified
// location.
// We don't care about byte ordering as much as we do about having all bytes
// there. Byte order does not matter, we want to use it as a key in our map.
uint64_t GetMacHash(const void* macaddr) {
  auto typed = reinterpret_cast<const uint16_t*>(macaddr);
  return (1ull * typed[0] << 32) | (typed[1] << 16) | typed[2];
}

// Enable asynchronous notifications from MAC80211_HWSIM.
// - `sock` is a valid netlink socket connected to NETLINK_GENERIC,
// - `family` is MAC80211_HWSIM genl family number.
//
// Upon failure, this function will terminate execution of the program.
void RegisterForHWSimNotifications(nl_sock* sock, int family) {
  std::unique_ptr<nl_msg, void (*)(nl_msg*)> msg(
      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
  genlmsg_put(msg.get(), NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST,
              HWSIM_CMD_REGISTER, 0);
  nl_send_auto(sock, msg.get());
  auto res = nl_wait_for_ack(sock);
  if (res < 0) {
    LOG(ERROR) << "Could not register for notifications: " << nl_geterror(res);
    exit(1);
  }
}

// Create and configure WIFI Router server socket.
// This function is guaranteed to success. If at any point an error is detected,
// the function will terminate execution of the program.
int CreateWifiRouterServerSocket() {
  auto fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
  if (fd <= 0) {
    LOG(ERROR) << "Could not create unix socket: " << strerror(-fd);
    exit(1);
  }

  sockaddr_un addr{};
  addr.sun_family = AF_UNIX;
  auto len = std::min(sizeof(addr.sun_path) - 2, FLAGS_socket_name.size());
  strncpy(&addr.sun_path[1], FLAGS_socket_name.c_str(), len);
  len += offsetof(sockaddr_un, sun_path) + 1;  // include heading \0 byte.
  auto res = bind(fd, reinterpret_cast<sockaddr*>(&addr), len);

  if (res < 0) {
    LOG(ERROR) << "Could not bind unix socket: " << strerror(-res);
    exit(1);
  }

  listen(fd, 4);
  return fd;
}

// Accept new WIFI Router client. When successful, client will be placed in
// clients table.
void AcceptNewClient(int server_fd, ClientsTable* clients) {
  auto client = accept(server_fd, nullptr, nullptr);
  if (client < 0) {
    LOG(ERROR) << "Could not accept client: " << strerror(errno);
    return;
  }

  clients->insert(client);
  LOG(INFO) << "Client " << client << " added.";
}

// Disconnect and remove client from list of registered clients and recipients
// of WLAN traffic.
void RemoveClient(int client, ClientsTable* clients,
                  MacToClientsTable* targets) {
  close(client);
  clients->erase(client);
  for (auto iter = targets->begin(); iter != targets->end();) {
    if (iter->second == client) {
      iter = targets->erase(iter);
    } else {
      ++iter;
    }
  }
  LOG(INFO) << "Client " << client << " removed.";
}

// Read MAC80211HWSIM packet, find the originating MAC address and redirect it
// to proper sink.
void RouteWIFIPacket(nl_sock* nl, int simfamily, ClientsTable* clients,
                     MacToClientsTable* targets) {
  sockaddr_nl tmp;
  uint8_t* buf;

  const auto len = nl_recv(nl, &tmp, &buf, nullptr);
  if (len < 0) {
    LOG(ERROR) << "Could not read from netlink: " << nl_geterror(len);
    return;
  }

  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
      reinterpret_cast<nlmsghdr*>(buf), [](nlmsghdr* m) { free(m); });

  // Discard messages that originate from anything else than MAC80211_HWSIM.
  if (msg->nlmsg_type != simfamily) return;

  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rep(
      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
  genlmsg_put(rep.get(), 0, 0, 0, 0, 0, WIFIROUTER_CMD_NOTIFY, 0);

  // Note, this is generic netlink message, and uses different parsing
  // technique.
  nlattr* attrs[HWSIM_ATTR_MAX + 1];
  if (genlmsg_parse(msg.get(), 0, attrs, HWSIM_ATTR_MAX, nullptr)) return;

  std::set<int> pending_removals;
  auto addr = attrs[HWSIM_ATTR_ADDR_TRANSMITTER];
  if (addr != nullptr) {
    nla_put(rep.get(), WIFIROUTER_ATTR_MAC, nla_len(addr), nla_data(addr));
    nla_put(rep.get(), WIFIROUTER_ATTR_PACKET, len, buf);
    auto hdr = nlmsg_hdr(rep.get());

    auto key = GetMacHash(nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]));
    LOG(INFO) << "Received netlink packet from " << std::hex << key;
    for (auto it = targets->find(key); it != targets->end() && it->first == key;
         ++it) {
      auto num_written =
          send(it->second, hdr, hdr->nlmsg_len, MSG_NOSIGNAL);
      if (num_written != static_cast<int64_t>(hdr->nlmsg_len)) {
        pending_removals.insert(it->second);
      }
    }

    for (auto client : pending_removals) {
      RemoveClient(client, clients, targets);
    }
  }
}

bool HandleClientMessage(int client, MacToClientsTable* targets) {
  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
      reinterpret_cast<nlmsghdr*>(malloc(kMaxSupportedPacketSize)),
      [](nlmsghdr* h) { free(h); });
  int64_t size = recv(client, msg.get(), kMaxSupportedPacketSize, 0);

  // Invalid message or no data -> client invalid or disconnected.
  if (size == 0 || size != msg->nlmsg_len || size < sizeof(nlmsghdr)) {
    return false;
  }

  int result = -EINVAL;
  genlmsghdr* ghdr = reinterpret_cast<genlmsghdr*>(nlmsg_data(msg.get()));

  switch (ghdr->cmd) {
    case WIFIROUTER_CMD_REGISTER:
      // Register client to receive notifications for specified MAC address.
      nlattr* attrs[WIFIROUTER_ATTR_MAX];
      if (!nlmsg_parse(msg.get(), sizeof(genlmsghdr), attrs,
                       WIFIROUTER_ATTR_MAX - 1, nullptr)) {
        if (attrs[WIFIROUTER_ATTR_MAC] != nullptr) {
          targets->emplace(GetMacHash(nla_data(attrs[WIFIROUTER_ATTR_MAC])),
                           client);
          result = 0;
        }
      }
      break;

    default:
      break;
  }

  nlmsgerr err{.error = result};
  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rsp(nlmsg_alloc(), nlmsg_free);
  nlmsg_put(rsp.get(), msg->nlmsg_pid, msg->nlmsg_seq, NLMSG_ERROR, 0, 0);
  nlmsg_append(rsp.get(), &err, sizeof(err), 0);
  auto hdr = nlmsg_hdr(rsp.get());
  if (send(client, hdr, hdr->nlmsg_len, MSG_NOSIGNAL) !=
      static_cast<int64_t>(hdr->nlmsg_len)) {
    return false;
  }
  return true;
}

// Process incoming requests from netlink, server or clients.
void ServerLoop(int server_fd, nl_sock* netlink_sock, int family) {
  ClientsTable clients;
  MacToClientsTable targets;
  int netlink_fd = nl_socket_get_fd(netlink_sock);

  while (true) {
    auto max_fd = server_fd;
    fd_set reads{};

    auto fdset = [&max_fd, &reads](int fd) {
      FD_SET(fd, &reads);
      max_fd = std::max(max_fd, fd);
    };

    fdset(server_fd);
    fdset(netlink_fd);
    for (int client : clients) fdset(client);

    if (select(max_fd + 1, &reads, nullptr, nullptr, nullptr) <= 0) continue;

    if (FD_ISSET(server_fd, &reads)) AcceptNewClient(server_fd, &clients);
    if (FD_ISSET(netlink_fd, &reads))
      RouteWIFIPacket(netlink_sock, family, &clients, &targets);

    // Process any client messages left. Drop any client that is no longer
    // talking with us.
    for (auto client = clients.begin(); client != clients.end();) {
      auto cfd = *client++;
      // Is our client sending us data?
      if (FD_ISSET(cfd, &reads)) {
        if (!HandleClientMessage(cfd, &targets)) {
          // Client should be disconnected.
          RemoveClient(cfd, &clients, &targets);
        }
      }
    }
  }
}

}  // namespace
}  // namespace cvd

int main(int argc, char* argv[]) {
  using namespace cvd;
  google::ParseCommandLineFlags(&argc, &argv, true);
#if !defined(ANDROID)
  // We should check for legitimate google logging here.
  google::InitGoogleLogging(argv[0]);
  google::InstallFailureSignalHandler();
#endif

  std::unique_ptr<nl_sock, void (*)(nl_sock*)> sock(nl_socket_alloc(),
                                                    nl_socket_free);

  auto res = nl_connect(sock.get(), NETLINK_GENERIC);
  if (res < 0) {
    LOG(ERROR) << "Could not connect to netlink generic: " << nl_geterror(res);
    exit(1);
  }

  auto mac80211_family = genl_ctrl_resolve(sock.get(), kWifiSimFamilyName);
  if (mac80211_family <= 0) {
    LOG(ERROR) << "Could not find MAC80211 HWSIM. Please make sure module "
               << "'mac80211_hwsim' is loaded on your system.";
    exit(1);
  }

  RegisterForHWSimNotifications(sock.get(), mac80211_family);
  auto server_fd = CreateWifiRouterServerSocket();
  ServerLoop(server_fd, sock.get(), mac80211_family);
}
<commit_msg>Re-register for HWSIM notifications upon creation of wifi interface.<commit_after>/*
 * Copyright (C) 2017 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 "host/commands/wifirouter/router.h"

#include <cerrno>
#include <cstddef>
#include <map>
#include <memory>
#include <set>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/genl.h>
#include <netlink/netlink.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

DEFINE_string(socket_name, "cvd-wifirouter",
              "Name of the unix-domain socket providing access for routing. "
              "Socket will be created in abstract namespace.");

namespace cvd {
namespace {
using MacHash = uint64_t;
using MacToClientsTable = std::multimap<MacHash, int>;
using ClientsTable = std::set<int>;

// Copied out of mac80211_hwsim.h header.
constexpr int HWSIM_CMD_REGISTER = 1;
constexpr int HWSIM_ATTR_ADDR_TRANSMITTER = 2;
constexpr int HWSIM_ATTR_MAX = 19;

// Name of the WIFI SIM Netlink Family.
constexpr char kWifiSimFamilyName[] = "MAC80211_HWSIM";
const int kMaxSupportedPacketSize = getpagesize();

class WifiRouter {
 public:
  using MacHash = uint16_t;
  using MacToClientsTable = std::multimap<MacHash, int>;
  using ClientsTable = std::set<int>;

  WifiRouter() : sock_(nullptr, nl_socket_free) {}
  ~WifiRouter() = default;

  void Init();
  void ServerLoop();

 private:
  MacHash GetMacHash(const void* macaddr);
  void CreateWifiRouterServerSocket();

  void RegisterForHWSimNotifications();
  void RouteWIFIPacket();

  void AcceptNewClient();
  bool HandleClientMessage(int client);
  void RemoveClient(int client);

  std::unique_ptr<nl_sock, void(*)(nl_sock*)> sock_;
  int server_fd_ = 0;
  int mac80211_family_ = 0;
  ClientsTable registered_clients_;
  MacToClientsTable registered_addresses_;
};

MacHash WifiRouter::GetMacHash(const void* macaddr) {
  const uint8_t* t = reinterpret_cast<const uint8_t*>(macaddr);

  // This is guaranteed to be unique. Address here is assigned at creation time
  // and is (well) non-mutable. This is a unique ID of the MAC80211 HWSIM
  // interface.
  return t[3] << 8 | t[4];
}

void WifiRouter::Init() {
  CreateWifiRouterServerSocket();
  RegisterForHWSimNotifications();
}

// Enable asynchronous notifications from MAC80211_HWSIM.
// - `sock` is a valid netlink socket connected to NETLINK_GENERIC,
// - `family` is MAC80211_HWSIM genl family number.
//
// Upon failure, this function will terminate execution of the program.
void WifiRouter::RegisterForHWSimNotifications() {
  sock_.reset(nl_socket_alloc());

  auto res = nl_connect(sock_.get(), NETLINK_GENERIC);
  if (res < 0) {
    LOG(ERROR) << "Could not connect to netlink generic: " << nl_geterror(res);
    exit(1);
  }

  mac80211_family_ = genl_ctrl_resolve(sock_.get(), kWifiSimFamilyName);
  if (mac80211_family_ <= 0) {
    LOG(ERROR) << "Could not find MAC80211 HWSIM. Please make sure module "
               << "'mac80211_hwsim' is loaded on your system.";
    exit(1);
  }

  std::unique_ptr<nl_msg, void (*)(nl_msg*)> msg(
      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
  genlmsg_put(msg.get(), NL_AUTO_PID, NL_AUTO_SEQ, mac80211_family_, 0,
              NLM_F_REQUEST, HWSIM_CMD_REGISTER, 0);
  nl_send_auto(sock_.get(), msg.get());

  res = nl_wait_for_ack(sock_.get());
  if (res < 0) {
    LOG(ERROR) << "Could not register for notifications: " << nl_geterror(res);
    exit(1);
  }
}

// Create and configure WIFI Router server socket.
// This function is guaranteed to success. If at any point an error is detected,
// the function will terminate execution of the program.
void WifiRouter::CreateWifiRouterServerSocket() {
  server_fd_ = socket(AF_UNIX, SOCK_SEQPACKET, 0);
  if (server_fd_ < 0) {
    LOG(ERROR) << "Could not create unix socket: " << strerror(-errno);
    exit(1);
  }

  sockaddr_un addr{};
  addr.sun_family = AF_UNIX;
  auto len = std::min(sizeof(addr.sun_path) - 2, FLAGS_socket_name.size());
  strncpy(&addr.sun_path[1], FLAGS_socket_name.c_str(), len);
  len += offsetof(sockaddr_un, sun_path) + 1;  // include heading \0 byte.
  auto res = bind(server_fd_, reinterpret_cast<sockaddr*>(&addr), len);

  if (res < 0) {
    LOG(ERROR) << "Could not bind unix socket: " << strerror(-errno);
    exit(1);
  }

  listen(server_fd_, 4);
}

// Accept new WIFI Router client. When successful, client will be placed in
// clients table.
void WifiRouter::AcceptNewClient() {
  auto client = accept(server_fd_, nullptr, nullptr);
  if (client < 0) {
    LOG(ERROR) << "Could not accept client: " << strerror(-errno);
    return;
  }

  registered_clients_.insert(client);
  LOG(INFO) << "Client " << client << " added.";
}

// Disconnect and remove client from list of registered clients and recipients
// of WLAN traffic.
void WifiRouter::RemoveClient(int client) {
  close(client);
  registered_clients_.erase(client);

  for (auto iter = registered_addresses_.begin();
       iter != registered_addresses_.end();) {
    if (iter->second == client) {
      iter = registered_addresses_.erase(iter);
    } else {
      ++iter;
    }
  }
  LOG(INFO) << "Client " << client << " removed.";
}

// Read MAC80211HWSIM packet, find the originating MAC address and redirect it
// to proper sink.
void WifiRouter::RouteWIFIPacket() {
  sockaddr_nl tmp;
  uint8_t* buf;

  const auto len = nl_recv(sock_.get(), &tmp, &buf, nullptr);
  if (len < 0) {
    LOG(ERROR) << "Could not read from netlink: " << nl_geterror(len);
    return;
  }

  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
      reinterpret_cast<nlmsghdr*>(buf), [](nlmsghdr* m) { free(m); });

  // Discard messages that originate from anything else than MAC80211_HWSIM.
  if (msg->nlmsg_type != mac80211_family_) return;

  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rep(
      nlmsg_alloc(), [](nl_msg* m) { nlmsg_free(m); });
  genlmsg_put(rep.get(), 0, 0, 0, 0, 0, WIFIROUTER_CMD_NOTIFY, 0);

  // Note, this is generic netlink message, and uses different parsing
  // technique.
  nlattr* attrs[HWSIM_ATTR_MAX + 1];
  if (genlmsg_parse(msg.get(), 0, attrs, HWSIM_ATTR_MAX, nullptr)) return;

  std::set<int> pending_removals;
  auto addr = attrs[HWSIM_ATTR_ADDR_TRANSMITTER];
  if (addr != nullptr) {
    nla_put(rep.get(), WIFIROUTER_ATTR_MAC, nla_len(addr), nla_data(addr));
    nla_put(rep.get(), WIFIROUTER_ATTR_PACKET, len, buf);
    auto hdr = nlmsg_hdr(rep.get());

    auto key = GetMacHash(nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]));
    LOG(INFO) << "Received netlink packet from " << std::hex << key;
    for (auto it = registered_addresses_.find(key);
         it != registered_addresses_.end() && it->first == key; ++it) {
      auto num_written =
          send(it->second, hdr, hdr->nlmsg_len, MSG_NOSIGNAL);
      if (num_written != static_cast<int64_t>(hdr->nlmsg_len)) {
        pending_removals.insert(it->second);
      }
    }

    for (auto client : pending_removals) RemoveClient(client);
  }
}

bool WifiRouter::HandleClientMessage(int client) {
  std::unique_ptr<nlmsghdr, void (*)(nlmsghdr*)> msg(
      reinterpret_cast<nlmsghdr*>(malloc(kMaxSupportedPacketSize)),
      [](nlmsghdr* h) { free(h); });
  int64_t size = recv(client, msg.get(), kMaxSupportedPacketSize, 0);

  // Invalid message or no data -> client invalid or disconnected.
  if (size == 0 || size != msg->nlmsg_len || size < sizeof(nlmsghdr)) {
    return false;
  }

  int result = -EINVAL;
  genlmsghdr* ghdr = reinterpret_cast<genlmsghdr*>(nlmsg_data(msg.get()));

  switch (ghdr->cmd) {
    case WIFIROUTER_CMD_REGISTER:
      // Register client to receive notifications for specified MAC address.
      nlattr* attrs[WIFIROUTER_ATTR_MAX];
      if (!nlmsg_parse(msg.get(), sizeof(genlmsghdr), attrs,
                       WIFIROUTER_ATTR_MAX - 1, nullptr)) {
        if (attrs[WIFIROUTER_ATTR_MAC] != nullptr) {
          LOG(INFO) << "Registering new client to receive data for " <<
                    GetMacHash(nla_data(attrs[WIFIROUTER_ATTR_MAC]));
          registered_addresses_.emplace(
              GetMacHash(nla_data(attrs[WIFIROUTER_ATTR_MAC])), client);
          // This is unfortunate, but it is a bug in mac80211_hwsim stack.
          // Apparently, the imperfect medium will not receive notifications for
          // newly created wifi interfaces. How about that...
          RegisterForHWSimNotifications();
          result = 0;
        }
      }
      break;

    default:
      break;
  }

  nlmsgerr err{.error = result};
  std::unique_ptr<nl_msg, void (*)(nl_msg*)> rsp(nlmsg_alloc(), nlmsg_free);
  nlmsg_put(rsp.get(), msg->nlmsg_pid, msg->nlmsg_seq, NLMSG_ERROR, 0, 0);
  nlmsg_append(rsp.get(), &err, sizeof(err), 0);
  auto hdr = nlmsg_hdr(rsp.get());
  if (send(client, hdr, hdr->nlmsg_len, MSG_NOSIGNAL) !=
      static_cast<int64_t>(hdr->nlmsg_len)) {
    return false;
  }
  return true;
}

// Process incoming requests from netlink, server or clients.
void WifiRouter::ServerLoop() {

  while (true) {
    auto max_fd = 0;
    fd_set reads{};

    auto fdset = [&max_fd, &reads](int fd) {
      FD_SET(fd, &reads);
      max_fd = std::max(max_fd, fd);
    };

    fdset(server_fd_);
    fdset(nl_socket_get_fd(sock_.get()));
    for (int client : registered_clients_) fdset(client);

    if (select(max_fd + 1, &reads, nullptr, nullptr, nullptr) <= 0) continue;

    if (FD_ISSET(server_fd_, &reads)) AcceptNewClient();
    if (FD_ISSET(nl_socket_get_fd(sock_.get()), &reads)) RouteWIFIPacket();

    // Process any client messages left. Drop any client that is no longer
    // talking with us.
    for (auto client = registered_clients_.begin();
         client != registered_clients_.end();) {
      auto cfd = *client++;
      // Is our client sending us data?
      if (FD_ISSET(cfd, &reads)) {
        if (!HandleClientMessage(cfd)) RemoveClient(cfd);
      }
    }
  }
}

}  // namespace
}  // namespace cvd

int main(int argc, char* argv[]) {
  using namespace cvd;
  google::ParseCommandLineFlags(&argc, &argv, true);
#if !defined(ANDROID)
  // We should check for legitimate google logging here.
  google::InitGoogleLogging(argv[0]);
  google::InstallFailureSignalHandler();
#endif

  WifiRouter r;
  r.Init();
  r.ServerLoop();
}
<|endoftext|>


<commit_before><commit_msg>Typo: s -> e<commit_after><|endoftext|>


<commit_before>#include "ostree_repo.h"

#include "logging/logging.h"

OSTreeObject::ptr OSTreeRepo::GetObject(const uint8_t sha256[32], const OstreeObjectType type) const {
  return GetObject(OSTreeHash(sha256), type);
}

OSTreeObject::ptr OSTreeRepo::GetObject(const OSTreeHash hash, const OstreeObjectType type) const {
  otable::const_iterator it;
  it = ObjectTable.find(hash);
  if (it != ObjectTable.end()) {
    return it->second;
  }

  const std::string exts[] = {".filez", ".dirtree", ".dirmeta", ".commit"};
  const std::string objpath = hash.string().insert(2, 1, '/');
  OSTreeObject::ptr object;
  int ext_index = -1;
  switch (type) {
    case OstreeObjectType::OSTREE_OBJECT_TYPE_FILE:
      ext_index = 0;
      break;
    case OstreeObjectType::OSTREE_OBJECT_TYPE_DIR_TREE:
      ext_index = 1;
      break;
    case OstreeObjectType::OSTREE_OBJECT_TYPE_DIR_META:
      ext_index = 2;
      break;
    case OstreeObjectType::OSTREE_OBJECT_TYPE_COMMIT:
      ext_index = 3;
      break;
    case OstreeObjectType::OSTREE_OBJECT_TYPE_UNKNOWN:
    default:
      break;
  }

  for (int i = 0; i < 3; ++i) {
    if (i > 0) {
      LOG_WARNING << "OSTree hash " << hash << " not found. Retrying (attempt " << i << " of 3)";
    }
    if (type != OstreeObjectType::OSTREE_OBJECT_TYPE_UNKNOWN) {
      if (CheckForObject(hash, objpath + exts[ext_index], object)) {
        return object;
      }
    } else {
      for (const std::string &ext : exts) {
        if (CheckForObject(hash, objpath + ext, object)) {
          return object;
        }
      }
    }
  }
  throw OSTreeObjectMissing(hash);
}

bool OSTreeRepo::CheckForObject(const OSTreeHash &hash, const std::string &path, OSTreeObject::ptr &object) const {
  if (FetchObject(std::string("objects/") + path)) {
    object = OSTreeObject::ptr(new OSTreeObject(*this, path));
    ObjectTable[hash] = object;
    LOG_DEBUG << "Fetched OSTree object " << path;
    return true;
  }
  return false;
}
<commit_msg>Refactor object type discovery to use a map.<commit_after>#include "ostree_repo.h"

#include "logging/logging.h"

OSTreeObject::ptr OSTreeRepo::GetObject(const uint8_t sha256[32], const OstreeObjectType type) const {
  return GetObject(OSTreeHash(sha256), type);
}

OSTreeObject::ptr OSTreeRepo::GetObject(const OSTreeHash hash, const OstreeObjectType type) const {
  otable::const_iterator obj_it = ObjectTable.find(hash);
  if (obj_it != ObjectTable.cend()) {
    return obj_it->second;
  }

  const std::map<OstreeObjectType, std::string> exts{{OstreeObjectType::OSTREE_OBJECT_TYPE_FILE, ".filez"},
                                                     {OstreeObjectType::OSTREE_OBJECT_TYPE_DIR_TREE, ".dirtree"},
                                                     {OstreeObjectType::OSTREE_OBJECT_TYPE_DIR_META, ".dirmeta"},
                                                     {OstreeObjectType::OSTREE_OBJECT_TYPE_COMMIT, ".commit"}};
  const std::string objpath = hash.string().insert(2, 1, '/');
  OSTreeObject::ptr object;

  for (int i = 0; i < 3; ++i) {
    if (i > 0) {
      LOG_WARNING << "OSTree hash " << hash << " not found. Retrying (attempt " << i << " of 3)";
    }
    if (type != OstreeObjectType::OSTREE_OBJECT_TYPE_UNKNOWN) {
      if (CheckForObject(hash, objpath + exts.at(type), object)) {
        return object;
      }
    } else {
      for (auto it = exts.cbegin(); it != exts.cend(); ++it) {
        if (CheckForObject(hash, objpath + it->second, object)) {
          return object;
        }
      }
    }
  }
  throw OSTreeObjectMissing(hash);
}

bool OSTreeRepo::CheckForObject(const OSTreeHash &hash, const std::string &path, OSTreeObject::ptr &object) const {
  if (FetchObject(std::string("objects/") + path)) {
    object = OSTreeObject::ptr(new OSTreeObject(*this, path));
    ObjectTable[hash] = object;
    LOG_DEBUG << "Fetched OSTree object " << path;
    return true;
  }
  return false;
}
<|endoftext|>