<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: VUser.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 02:11:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>

#ifndef _CONNECTIVITY_SDBCX_USER_HXX_
#include "connectivity/sdbcx/VUser.hxx"
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_
#include <com/sun/star/sdbcx/Privilege.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBCX_PRIVILEGEOBJECT_HPP_
#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
#endif
#ifndef CONNECTIVITY_CONNECTION_HXX
#include "TConnection.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLLECTION_HXX_
#include "connectivity/sdbcx/VCollection.hxx"
#endif
#ifndef _DBHELPER_DBEXCEPTION_HXX_
#include <connectivity/dbexception.hxx>
#endif
#ifndef _COMPHELPER_SEQUENCE_HXX_
#include <comphelper/sequence.hxx>
#endif

// -------------------------------------------------------------------------
using namespace connectivity;
using namespace connectivity::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;

IMPLEMENT_SERVICE_INFO(OUser,"com.sun.star.sdbcx.VUser","com.sun.star.sdbcx.User");
// -------------------------------------------------------------------------
OUser::OUser(sal_Bool _bCase)  : OUser_BASE(m_aMutex)
                , ODescriptor(OUser_BASE::rBHelper,_bCase,sal_True)
                , m_pGroups(NULL)
{
}
// -------------------------------------------------------------------------
OUser::OUser(const ::rtl::OUString& _Name,sal_Bool _bCase) :    OUser_BASE(m_aMutex)
                        ,ODescriptor(OUser_BASE::rBHelper,_bCase)
                        ,m_pGroups(NULL)
{
    m_Name = _Name;
}
// -------------------------------------------------------------------------
OUser::~OUser( )
{
    delete m_pGroups;
}
// -------------------------------------------------------------------------
void OUser::disposing(void)
{
    OPropertySetHelper::disposing();
    ::osl::MutexGuard aGuard(m_aMutex);
    if(m_pGroups)
        m_pGroups->disposing();
}
// -------------------------------------------------------------------------
Any SAL_CALL OUser::queryInterface( const Type & rType ) throw(RuntimeException)
{
    Any aRet = ODescriptor::queryInterface( rType);
    return aRet.hasValue() ? aRet : OUser_BASE::queryInterface( rType);
}
// -------------------------------------------------------------------------
Sequence< Type > SAL_CALL OUser::getTypes(  ) throw(RuntimeException)
{
    return ::comphelper::concatSequences(ODescriptor::getTypes(),OUser_BASE::getTypes());
}
// -------------------------------------------------------------------------
::cppu::IPropertyArrayHelper* OUser::createArrayHelper( ) const
{
        Sequence< Property > aProps;
    describeProperties(aProps);
    return new ::cppu::OPropertyArrayHelper(aProps);

}
// -------------------------------------------------------------------------
::cppu::IPropertyArrayHelper & OUser::getInfoHelper()
{
    return *const_cast<OUser*>(this)->getArrayHelper();
}
// -------------------------------------------------------------------------
// XUser
void SAL_CALL OUser::changePassword( const ::rtl::OUString& /*objPassword*/, const ::rtl::OUString& /*newPassword*/ ) throw(::com::sun::star::sdbc::SQLException, RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XUser::changePassword", *this );
}
// -------------------------------------------------------------------------
// XGroupsSupplier
Reference< XNameAccess > SAL_CALL OUser::getGroups(  ) throw(RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);

    try
    {
        if ( !m_pGroups )
            refreshGroups();
    }
    catch( const RuntimeException& )
    {
        // allowed to leave this method
        throw;
    }
    catch( const Exception& )
    {
        // allowed
    }

    return const_cast<OUser*>(this)->m_pGroups;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------

sal_Int32 SAL_CALL OUser::getPrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::changePassword", *this );
    return 0;
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL OUser::getGrantablePrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::getGrantablePrivileges", *this );
    return 0;
}
// -------------------------------------------------------------------------
void SAL_CALL OUser::grantPrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::grantPrivileges", *this );
}
// -------------------------------------------------------------------------
void SAL_CALL OUser::revokePrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::revokePrivileges", *this );
}
// -----------------------------------------------------------------------------
::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL OUser::getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException)
{
    return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
}
// -----------------------------------------------------------------------------
::rtl::OUString SAL_CALL OUser::getName(  ) throw(::com::sun::star::uno::RuntimeException)
{
    return m_Name;
}
// -----------------------------------------------------------------------------
void SAL_CALL OUser::setName( const ::rtl::OUString& /*aName*/ ) throw(::com::sun::star::uno::RuntimeException)
{
    OSL_ENSURE( false, "OUser::setName: not implemented!" );
        // not allowed to throw an SQLException here ...
}
// -----------------------------------------------------------------------------
// XInterface
void SAL_CALL OUser::acquire() throw()
{
    OUser_BASE::acquire();
}
// -----------------------------------------------------------------------------
void SAL_CALL OUser::release() throw()
{
    OUser_BASE::release();
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS pchfix02 (1.12.60); FILE MERGED 2006/09/01 17:22:37 kaib 1.12.60.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: VUser.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 03:12:47 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"

#include <stdio.h>

#ifndef _CONNECTIVITY_SDBCX_USER_HXX_
#include "connectivity/sdbcx/VUser.hxx"
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBCX_PRIVILEGE_HPP_
#include <com/sun/star/sdbcx/Privilege.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBCX_PRIVILEGEOBJECT_HPP_
#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
#endif
#ifndef CONNECTIVITY_CONNECTION_HXX
#include "TConnection.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLLECTION_HXX_
#include "connectivity/sdbcx/VCollection.hxx"
#endif
#ifndef _DBHELPER_DBEXCEPTION_HXX_
#include <connectivity/dbexception.hxx>
#endif
#ifndef _COMPHELPER_SEQUENCE_HXX_
#include <comphelper/sequence.hxx>
#endif

// -------------------------------------------------------------------------
using namespace connectivity;
using namespace connectivity::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;

IMPLEMENT_SERVICE_INFO(OUser,"com.sun.star.sdbcx.VUser","com.sun.star.sdbcx.User");
// -------------------------------------------------------------------------
OUser::OUser(sal_Bool _bCase)  : OUser_BASE(m_aMutex)
                , ODescriptor(OUser_BASE::rBHelper,_bCase,sal_True)
                , m_pGroups(NULL)
{
}
// -------------------------------------------------------------------------
OUser::OUser(const ::rtl::OUString& _Name,sal_Bool _bCase) :    OUser_BASE(m_aMutex)
                        ,ODescriptor(OUser_BASE::rBHelper,_bCase)
                        ,m_pGroups(NULL)
{
    m_Name = _Name;
}
// -------------------------------------------------------------------------
OUser::~OUser( )
{
    delete m_pGroups;
}
// -------------------------------------------------------------------------
void OUser::disposing(void)
{
    OPropertySetHelper::disposing();
    ::osl::MutexGuard aGuard(m_aMutex);
    if(m_pGroups)
        m_pGroups->disposing();
}
// -------------------------------------------------------------------------
Any SAL_CALL OUser::queryInterface( const Type & rType ) throw(RuntimeException)
{
    Any aRet = ODescriptor::queryInterface( rType);
    return aRet.hasValue() ? aRet : OUser_BASE::queryInterface( rType);
}
// -------------------------------------------------------------------------
Sequence< Type > SAL_CALL OUser::getTypes(  ) throw(RuntimeException)
{
    return ::comphelper::concatSequences(ODescriptor::getTypes(),OUser_BASE::getTypes());
}
// -------------------------------------------------------------------------
::cppu::IPropertyArrayHelper* OUser::createArrayHelper( ) const
{
        Sequence< Property > aProps;
    describeProperties(aProps);
    return new ::cppu::OPropertyArrayHelper(aProps);

}
// -------------------------------------------------------------------------
::cppu::IPropertyArrayHelper & OUser::getInfoHelper()
{
    return *const_cast<OUser*>(this)->getArrayHelper();
}
// -------------------------------------------------------------------------
// XUser
void SAL_CALL OUser::changePassword( const ::rtl::OUString& /*objPassword*/, const ::rtl::OUString& /*newPassword*/ ) throw(::com::sun::star::sdbc::SQLException, RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XUser::changePassword", *this );
}
// -------------------------------------------------------------------------
// XGroupsSupplier
Reference< XNameAccess > SAL_CALL OUser::getGroups(  ) throw(RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);

    try
    {
        if ( !m_pGroups )
            refreshGroups();
    }
    catch( const RuntimeException& )
    {
        // allowed to leave this method
        throw;
    }
    catch( const Exception& )
    {
        // allowed
    }

    return const_cast<OUser*>(this)->m_pGroups;
}
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------

sal_Int32 SAL_CALL OUser::getPrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::changePassword", *this );
    return 0;
}
// -------------------------------------------------------------------------
sal_Int32 SAL_CALL OUser::getGrantablePrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::getGrantablePrivileges", *this );
    return 0;
}
// -------------------------------------------------------------------------
void SAL_CALL OUser::grantPrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::grantPrivileges", *this );
}
// -------------------------------------------------------------------------
void SAL_CALL OUser::revokePrivileges( const ::rtl::OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard(m_aMutex);
    checkDisposed(OUser_BASE::rBHelper.bDisposed);
    ::dbtools::throwFeatureNotImplementedException( "XAuthorizable::revokePrivileges", *this );
}
// -----------------------------------------------------------------------------
::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL OUser::getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException)
{
    return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
}
// -----------------------------------------------------------------------------
::rtl::OUString SAL_CALL OUser::getName(  ) throw(::com::sun::star::uno::RuntimeException)
{
    return m_Name;
}
// -----------------------------------------------------------------------------
void SAL_CALL OUser::setName( const ::rtl::OUString& /*aName*/ ) throw(::com::sun::star::uno::RuntimeException)
{
    OSL_ENSURE( false, "OUser::setName: not implemented!" );
        // not allowed to throw an SQLException here ...
}
// -----------------------------------------------------------------------------
// XInterface
void SAL_CALL OUser::acquire() throw()
{
    OUser_BASE::acquire();
}
// -----------------------------------------------------------------------------
void SAL_CALL OUser::release() throw()
{
    OUser_BASE::release();
}
// -----------------------------------------------------------------------------

<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2021-present ScyllaDB
 */

#pragma once

#include <seastar/core/coroutine.hh>

namespace seastar {

namespace internal {

struct exception_awaiter {
    std::exception_ptr eptr;

    explicit exception_awaiter(std::exception_ptr&& eptr) noexcept : eptr(std::move(eptr)) {}

    exception_awaiter(const exception_awaiter&) = delete;
    exception_awaiter(exception_awaiter&&) = delete;

    bool await_ready() const noexcept {
        return false;
    }

    template<typename U>
    void await_suspend(SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<U> hndl) noexcept {
        hndl.promise().set_exception(std::move(eptr));
        hndl.destroy();
    }

    void await_resume() noexcept {}
};

} // internal

namespace coroutine {

/// Wrapper for propagating an exception directly rather than
/// throwing it. The wrapper can be used with both co_await and co_return.
///
/// \note It is not possible to co_return the wrapper in coroutines which
/// return future<> due to language limitations (it's not possible to specify
/// both return_value and return_void in the promise_type). You can use co_await
/// instead which works in coroutines which return either future<> or future<T>.
///
/// Example usage:
///
/// ```
/// co_await coroutine::exception(std::make_exception_ptr(std::runtime_error("something failed miserably")));
/// co_return coroutine::exception(std::make_exception_ptr(std::runtime_error("something failed miserably")));
/// ```
struct exception {
    std::exception_ptr eptr;
    explicit exception(std::exception_ptr eptr) noexcept : eptr(std::move(eptr)) {}
};

/// Allows propagating an exception from a coroutine directly rather than
/// throwing it.
///
/// `make_exception()` returns an object which must be co_returned.
/// Co_returning the object will immediately resolve the current coroutine
/// to the given exception.
///
/// \note Due to language limitations, this function doesn't work in coroutines
/// which return future<>. Consider using return_exception instead.
///
/// Example usage:
///
/// ```
/// co_return coroutine::make_exception(std::runtime_error("something failed miserably"));
/// ```
[[deprecated("Use co_await coroutine::return_exception or co_return coroutine::exception instead")]]
[[nodiscard]]
inline exception make_exception(std::exception_ptr ex) noexcept {
    return exception(std::move(ex));
}

template<typename T>
[[deprecated("Use co_await coroutine::return_exception or co_return coroutine::exception instead")]]
[[nodiscard]]
exception make_exception(T&& t) noexcept {
    log_exception_trace();
    return exception(std::make_exception_ptr(std::forward<T>(t)));
}

/// Allows propagating an exception from a coroutine directly rather than
/// throwing it.
///
/// `return_exception()` returns an object which must be co_awaited.
/// Co_awaiting the object will immediately resolve the current coroutine
/// to the given exception.
///
/// Example usage:
///
/// ```
/// co_await coroutine::return_exception(std::runtime_error("something failed miserably"));
/// ```
[[nodiscard]]
inline exception return_exception_ptr(std::exception_ptr ex) noexcept {
    return exception(std::move(ex));
}

template<typename T>
[[nodiscard]]
exception return_exception(T&& t) noexcept {
    log_exception_trace();
    return exception(std::make_exception_ptr(std::forward<T>(t)));
}

} // coroutine

inline auto operator co_await(coroutine::exception ex) noexcept {
    return internal::exception_awaiter(std::move(ex.eptr));
}

} // seastar
<commit_msg>coroutine: exception: deprecate return_exception(exception_ptr)<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2021-present ScyllaDB
 */

#pragma once

#include <seastar/core/coroutine.hh>

namespace seastar {

namespace internal {

struct exception_awaiter {
    std::exception_ptr eptr;

    explicit exception_awaiter(std::exception_ptr&& eptr) noexcept : eptr(std::move(eptr)) {}

    exception_awaiter(const exception_awaiter&) = delete;
    exception_awaiter(exception_awaiter&&) = delete;

    bool await_ready() const noexcept {
        return false;
    }

    template<typename U>
    void await_suspend(SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<U> hndl) noexcept {
        hndl.promise().set_exception(std::move(eptr));
        hndl.destroy();
    }

    void await_resume() noexcept {}
};

} // internal

namespace coroutine {

/// Wrapper for propagating an exception directly rather than
/// throwing it. The wrapper can be used with both co_await and co_return.
///
/// \note It is not possible to co_return the wrapper in coroutines which
/// return future<> due to language limitations (it's not possible to specify
/// both return_value and return_void in the promise_type). You can use co_await
/// instead which works in coroutines which return either future<> or future<T>.
///
/// Example usage:
///
/// ```
/// co_await coroutine::exception(std::make_exception_ptr(std::runtime_error("something failed miserably")));
/// co_return coroutine::exception(std::make_exception_ptr(std::runtime_error("something failed miserably")));
/// ```
struct exception {
    std::exception_ptr eptr;
    explicit exception(std::exception_ptr eptr) noexcept : eptr(std::move(eptr)) {}
};

/// Allows propagating an exception from a coroutine directly rather than
/// throwing it.
///
/// `make_exception()` returns an object which must be co_returned.
/// Co_returning the object will immediately resolve the current coroutine
/// to the given exception.
///
/// \note Due to language limitations, this function doesn't work in coroutines
/// which return future<>. Consider using return_exception instead.
///
/// Example usage:
///
/// ```
/// co_return coroutine::make_exception(std::runtime_error("something failed miserably"));
/// ```
[[deprecated("Use co_await coroutine::return_exception or co_return coroutine::exception instead")]]
[[nodiscard]]
inline exception make_exception(std::exception_ptr ex) noexcept {
    return exception(std::move(ex));
}

template<typename T>
[[deprecated("Use co_await coroutine::return_exception or co_return coroutine::exception instead")]]
[[nodiscard]]
exception make_exception(T&& t) noexcept {
    log_exception_trace();
    return exception(std::make_exception_ptr(std::forward<T>(t)));
}

/// Allows propagating an exception from a coroutine directly rather than
/// throwing it.
///
/// `return_exception()` returns an object which must be co_awaited.
/// Co_awaiting the object will immediately resolve the current coroutine
/// to the given exception.
///
/// Example usage:
///
/// ```
/// co_await coroutine::return_exception(std::runtime_error("something failed miserably"));
/// ```
[[nodiscard]]
inline exception return_exception_ptr(std::exception_ptr ex) noexcept {
    return exception(std::move(ex));
}

[[deprecated("Use co_await coroutine::return_exception_ptr instead")]]
[[nodiscard]]
inline exception return_exception(std::exception_ptr ex) noexcept {
    return exception(std::move(ex));
}

template<typename T>
[[nodiscard]]
exception return_exception(T&& t) noexcept {
    log_exception_trace();
    return exception(std::make_exception_ptr(std::forward<T>(t)));
}

} // coroutine

inline auto operator co_await(coroutine::exception ex) noexcept {
    return internal::exception_awaiter(std::move(ex.eptr));
}

} // seastar
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkNumericTraits.h"

namespace itk
{

/* Explicit definitions for static inline initialized integer members.
 *
 * MSVC gives duplicate symbol definition errors if the explicit
 * definitions are defined. Other compilers (GCC) seem not to care, while
 * still others (Clang) require it.
 */
constexpr bool NumericTraits< bool >:: Zero;
constexpr bool NumericTraits< bool >:: One;

constexpr unsigned char NumericTraits< unsigned char >:: Zero;
constexpr unsigned char NumericTraits< unsigned char >:: One;

constexpr signed char NumericTraits< signed char >:: Zero;
constexpr signed char NumericTraits< signed char >:: One;

constexpr char NumericTraits< char >:: Zero;
constexpr char NumericTraits< char >:: One;

constexpr unsigned short NumericTraits< unsigned short >:: Zero;
constexpr unsigned short NumericTraits< unsigned short >:: One;

constexpr short NumericTraits< short >:: Zero;
constexpr short NumericTraits< short >:: One;

constexpr unsigned int NumericTraits< unsigned int >:: Zero;
constexpr unsigned int NumericTraits< unsigned int >:: One;

constexpr int NumericTraits< int >:: Zero;
constexpr int NumericTraits< int >:: One;

constexpr unsigned long NumericTraits< unsigned long >:: Zero;
constexpr unsigned long NumericTraits< unsigned long >:: One;

constexpr long NumericTraits< long >:: Zero;
constexpr long NumericTraits< long >:: One;

constexpr long long NumericTraits< long long >:: Zero;
constexpr long long NumericTraits< long long >:: One;

constexpr unsigned long long NumericTraits< unsigned long long >:: Zero;
constexpr unsigned long long NumericTraits< unsigned long long >:: One;

const std::complex< char >  NumericTraits< std::complex< char > >:: Zero = std::complex< char >(0, 0);
const std::complex< char >  NumericTraits< std::complex< char > >:: One  = std::complex< char >(1, 0);

const std::complex< unsigned char >  NumericTraits< std::complex< unsigned char > >:: Zero = std::complex< unsigned char >(0, 0);
const std::complex< unsigned char >  NumericTraits< std::complex< unsigned char > >:: One  = std::complex< unsigned char >(1, 0);

const std::complex< short >  NumericTraits< std::complex< short > >:: Zero = std::complex< short >(0, 0);
const std::complex< short >  NumericTraits< std::complex< short > >:: One  = std::complex< short >(1, 0);

const std::complex< unsigned short >  NumericTraits< std::complex< unsigned short > >:: Zero = std::complex< unsigned short >(0, 0);
const std::complex< unsigned short >  NumericTraits< std::complex< unsigned short > >:: One  = std::complex< unsigned short >(1, 0);

const std::complex< int >  NumericTraits< std::complex< int > >:: Zero = std::complex< int >(0, 0);
const std::complex< int >  NumericTraits< std::complex< int > >:: One  = std::complex< int >(1, 0);

const std::complex< unsigned int >  NumericTraits< std::complex< unsigned int > >:: Zero = std::complex< unsigned int >(0, 0);
const std::complex< unsigned int >  NumericTraits< std::complex< unsigned int > >:: One  = std::complex< unsigned int >(1, 0);

const std::complex< long >  NumericTraits< std::complex< long > >:: Zero = std::complex< long >(0L, 0L);
const std::complex< long >  NumericTraits< std::complex< long > >:: One  = std::complex< long >(1L, 0L);

const std::complex< unsigned long >  NumericTraits< std::complex< unsigned long > >:: Zero = std::complex< unsigned long >(0UL, 0UL);
const std::complex< unsigned long >  NumericTraits< std::complex< unsigned long > >:: One  = std::complex< unsigned long >(1UL, 0UL);

const std::complex< float >  NumericTraits< std::complex< float > >:: Zero = std::complex< float >(0.0f, 0.0f);
const std::complex< float >  NumericTraits< std::complex< float > >:: One  = std::complex< float >(1.0f, 0.0f);

const std::complex< double >  NumericTraits< std::complex< double > >:: Zero = std::complex< double >(0.0, 0.0);
const std::complex< double >  NumericTraits< std::complex< double > >:: One  = std::complex< double >(1.0, 0.0);

const std::complex< long double >  NumericTraits< std::complex< long double > >:: Zero = std::complex< long double >(0.0, 0.0);
const std::complex< long double >  NumericTraits< std::complex< long double > >:: One  = std::complex< long double >(1.0, 0.0);

} // end namespace itk
<commit_msg>BUG: Missing external linkage options for float and double.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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 "itkNumericTraits.h"

namespace itk
{

/* Explicit definitions for static inline initialized integer members.
 *
 * MSVC gives duplicate symbol definition errors if the explicit
 * definitions are defined. Other compilers (GCC) seem not to care, while
 * still others (Clang) require it.
 */
constexpr bool NumericTraits< bool >:: Zero;
constexpr bool NumericTraits< bool >:: One;

constexpr unsigned char NumericTraits< unsigned char >:: Zero;
constexpr unsigned char NumericTraits< unsigned char >:: One;

constexpr signed char NumericTraits< signed char >:: Zero;
constexpr signed char NumericTraits< signed char >:: One;

constexpr char NumericTraits< char >:: Zero;
constexpr char NumericTraits< char >:: One;

constexpr unsigned short NumericTraits< unsigned short >:: Zero;
constexpr unsigned short NumericTraits< unsigned short >:: One;

constexpr short NumericTraits< short >:: Zero;
constexpr short NumericTraits< short >:: One;

constexpr unsigned int NumericTraits< unsigned int >:: Zero;
constexpr unsigned int NumericTraits< unsigned int >:: One;

constexpr int NumericTraits< int >:: Zero;
constexpr int NumericTraits< int >:: One;

constexpr unsigned long NumericTraits< unsigned long >:: Zero;
constexpr unsigned long NumericTraits< unsigned long >:: One;

constexpr long NumericTraits< long >:: Zero;
constexpr long NumericTraits< long >:: One;

constexpr long long NumericTraits< long long >:: Zero;
constexpr long long NumericTraits< long long >:: One;

constexpr unsigned long long NumericTraits< unsigned long long >:: Zero;
constexpr unsigned long long NumericTraits< unsigned long long >:: One;

constexpr float NumericTraits< float >:: Zero;
constexpr float NumericTraits< float >:: One;

constexpr double NumericTraits< double >:: Zero;
constexpr double NumericTraits< double >:: One;

constexpr long double NumericTraits< long double >:: Zero;
constexpr long double NumericTraits< long double >:: One;

const std::complex< char >  NumericTraits< std::complex< char > >:: Zero = std::complex< char >(0, 0);
const std::complex< char >  NumericTraits< std::complex< char > >:: One  = std::complex< char >(1, 0);

const std::complex< unsigned char >  NumericTraits< std::complex< unsigned char > >:: Zero = std::complex< unsigned char >(0, 0);
const std::complex< unsigned char >  NumericTraits< std::complex< unsigned char > >:: One  = std::complex< unsigned char >(1, 0);

const std::complex< short >  NumericTraits< std::complex< short > >:: Zero = std::complex< short >(0, 0);
const std::complex< short >  NumericTraits< std::complex< short > >:: One  = std::complex< short >(1, 0);

const std::complex< unsigned short >  NumericTraits< std::complex< unsigned short > >:: Zero = std::complex< unsigned short >(0, 0);
const std::complex< unsigned short >  NumericTraits< std::complex< unsigned short > >:: One  = std::complex< unsigned short >(1, 0);

const std::complex< int >  NumericTraits< std::complex< int > >:: Zero = std::complex< int >(0, 0);
const std::complex< int >  NumericTraits< std::complex< int > >:: One  = std::complex< int >(1, 0);

const std::complex< unsigned int >  NumericTraits< std::complex< unsigned int > >:: Zero = std::complex< unsigned int >(0, 0);
const std::complex< unsigned int >  NumericTraits< std::complex< unsigned int > >:: One  = std::complex< unsigned int >(1, 0);

const std::complex< long >  NumericTraits< std::complex< long > >:: Zero = std::complex< long >(0L, 0L);
const std::complex< long >  NumericTraits< std::complex< long > >:: One  = std::complex< long >(1L, 0L);

const std::complex< unsigned long >  NumericTraits< std::complex< unsigned long > >:: Zero = std::complex< unsigned long >(0UL, 0UL);
const std::complex< unsigned long >  NumericTraits< std::complex< unsigned long > >:: One  = std::complex< unsigned long >(1UL, 0UL);

const std::complex< float >  NumericTraits< std::complex< float > >:: Zero = std::complex< float >(0.0f, 0.0f);
const std::complex< float >  NumericTraits< std::complex< float > >:: One  = std::complex< float >(1.0f, 0.0f);

const std::complex< double >  NumericTraits< std::complex< double > >:: Zero = std::complex< double >(0.0, 0.0);
const std::complex< double >  NumericTraits< std::complex< double > >:: One  = std::complex< double >(1.0, 0.0);

const std::complex< long double >  NumericTraits< std::complex< long double > >:: Zero = std::complex< long double >(0.0, 0.0);
const std::complex< long double >  NumericTraits< std::complex< long double > >:: One  = std::complex< long double >(1.0, 0.0);

} // end namespace itk
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-tsdb/TSDBClient.h>
#include <fnord-base/util/binarymessagereader.h>
#include <fnord-msg/msg.h>

namespace fnord {
namespace tsdb {

TSDBClient::TSDBClient(
    const String& uri,
    http::HTTPConnectionPool* http) :
    uri_(uri),
    http_(http) {}

Vector<String> TSDBClient::listPartitions(
    const String& stream_key,
    const DateTime& from,
    const DateTime& until) {
  auto uri = StringUtil::format(
      "$0/list_chunks?stream=$1&from=$2&until=$3",
      uri_,
      URI::urlEncode(stream_key),
      from.unixMicros(),
      until.unixMicros());

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  Vector<String> partitions;
  const auto& body = r.body();
  util::BinaryMessageReader reader(body.data(), body.size());
  while (reader.remaining() > 0) {
    partitions.emplace_back(reader.readLenencString());
  }

  return partitions;
}

void TSDBClient::fetchPartition(
    const String& stream_key,
    const String& partition,
    Function<void (const Buffer& record)> fn) {
  fetchPartitionWithSampling(stream_key, partition, 0, 0, fn);
}

void TSDBClient::fetchPartitionWithSampling(
    const String& stream_key,
    const String& partition,
    size_t sample_modulo,
    size_t sample_index,
    Function<void (const Buffer& record)> fn) {
  auto uri = StringUtil::format(
      "$0/fetch_chunk?chunk=$1",
      uri_,
      URI::urlEncode(partition));

  if (sample_modulo > 0) {
    uri += StringUtil::format("&sample=$0:$1", sample_modulo, sample_index);
  }

  Buffer buffer;
  std::mutex m;
  std::condition_variable cv;
  bool done = false;
  bool eos = false;
  auto handler = [&buffer, &fn, &m, &cv] (const void* data, size_t size) {
    std::unique_lock<std::mutex> lk(m);
    buffer.append(data, size);
    lk.unlock();
    cv.notify_all();
  };

  auto handler_factory = [&handler] (const Promise<http::HTTPResponse> promise)
      -> http::HTTPResponseFuture* {
    return new http::StreamingResponseFuture(promise, handler);
  };

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req, handler_factory);
  res.onReady([&cv, &m, &done] () {
    std::unique_lock<std::mutex> lk(m);
    done = true;
    lk.unlock();
    cv.notify_all();
  });

  for (;;) {
    std::unique_lock<std::mutex> lk(m);
    auto buf = buffer;
    lk.unlock();

    size_t consumed = 0;
    util::BinaryMessageReader reader(buf.data(), buf.size());
    while (reader.remaining() >= sizeof(uint64_t)) {
      auto rec_len = *reader.readUInt64();

      if (rec_len > reader.remaining()) {
        break;
      }

      if (rec_len == 0) {
        eos = true;
      } else {
        fn(Buffer(reader.read(rec_len), rec_len));
        consumed = reader.position();
      }
    }

    lk.lock();
    Buffer remaining((char*) buffer.data() + consumed, buffer.size() - consumed);
    buffer.clear();
    buffer.append(remaining);

    if (done) {
      if (!eos) {
        RAISE(kRuntimeError, "unexpected EOF");
      }

      break;
    } else {
      cv.wait(lk);
    }
  }

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return;
}

PartitionInfo TSDBClient::fetchPartitionInfo(
    const String& stream_key,
    const String& partition_key) {
  auto uri = StringUtil::format(
      "$0/fetch_partition_info?partition=$1",
      uri_,
      URI::urlEncode(partition_key));

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return msg::decode<PartitionInfo>(r.body());
}

Buffer TSDBClient::fetchDerivedDataset(
    const String& stream_key,
    const String& partition,
    const String& derived_dataset_name) {
  auto uri = StringUtil::format(
      "$0/fetch_derived_dataset?chunk=$1&derived_dataset=$2",
      uri_,
      URI::urlEncode(partition),
      URI::urlEncode(derived_dataset_name));

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return r.body();
}

} // namespace tdsb
} // namespace fnord
<commit_msg>wait for buffer drain<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-tsdb/TSDBClient.h>
#include <fnord-base/util/binarymessagereader.h>
#include <fnord-msg/msg.h>

namespace fnord {
namespace tsdb {

TSDBClient::TSDBClient(
    const String& uri,
    http::HTTPConnectionPool* http) :
    uri_(uri),
    http_(http) {}

Vector<String> TSDBClient::listPartitions(
    const String& stream_key,
    const DateTime& from,
    const DateTime& until) {
  auto uri = StringUtil::format(
      "$0/list_chunks?stream=$1&from=$2&until=$3",
      uri_,
      URI::urlEncode(stream_key),
      from.unixMicros(),
      until.unixMicros());

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  Vector<String> partitions;
  const auto& body = r.body();
  util::BinaryMessageReader reader(body.data(), body.size());
  while (reader.remaining() > 0) {
    partitions.emplace_back(reader.readLenencString());
  }

  return partitions;
}

void TSDBClient::fetchPartition(
    const String& stream_key,
    const String& partition,
    Function<void (const Buffer& record)> fn) {
  fetchPartitionWithSampling(stream_key, partition, 0, 0, fn);
}

void TSDBClient::fetchPartitionWithSampling(
    const String& stream_key,
    const String& partition,
    size_t sample_modulo,
    size_t sample_index,
    Function<void (const Buffer& record)> fn) {
  auto uri = StringUtil::format(
      "$0/fetch_chunk?chunk=$1",
      uri_,
      URI::urlEncode(partition));

  if (sample_modulo > 0) {
    uri += StringUtil::format("&sample=$0:$1", sample_modulo, sample_index);
  }

  Buffer buffer;
  std::mutex m;
  std::condition_variable cv;
  bool done = false;
  bool eos = false;
  auto handler = [&buffer, &fn, &m, &cv] (const void* data, size_t size) {
    std::unique_lock<std::mutex> lk(m);
    buffer.append(data, size);
    lk.unlock();
    cv.notify_all();
  };

  auto handler_factory = [&handler] (const Promise<http::HTTPResponse> promise)
      -> http::HTTPResponseFuture* {
    return new http::StreamingResponseFuture(promise, handler);
  };

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req, handler_factory);
  res.onReady([&cv, &m, &done] () {
    std::unique_lock<std::mutex> lk(m);
    done = true;
    lk.unlock();
    cv.notify_all();
  });

  for (;;) {
    std::unique_lock<std::mutex> lk(m);
    auto buf = buffer;
    lk.unlock();

    size_t consumed = 0;
    util::BinaryMessageReader reader(buf.data(), buf.size());
    while (reader.remaining() >= sizeof(uint64_t)) {
      auto rec_len = *reader.readUInt64();

      if (rec_len > reader.remaining()) {
        break;
      }

      if (rec_len == 0) {
        eos = true;
      } else {
        fn(Buffer(reader.read(rec_len), rec_len));
        consumed = reader.position();
      }
    }

    lk.lock();
    Buffer remaining((char*) buffer.data() + consumed, buffer.size() - consumed);
    buffer.clear();
    buffer.append(remaining);

    if (done) {
      if (buffer.size() == 0 && !eos) {
        RAISE(kRuntimeError, "unexpected EOF");
      }

      break;
    } else {
      cv.wait(lk);
    }
  }

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return;
}

PartitionInfo TSDBClient::fetchPartitionInfo(
    const String& stream_key,
    const String& partition_key) {
  auto uri = StringUtil::format(
      "$0/fetch_partition_info?partition=$1",
      uri_,
      URI::urlEncode(partition_key));

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return msg::decode<PartitionInfo>(r.body());
}

Buffer TSDBClient::fetchDerivedDataset(
    const String& stream_key,
    const String& partition,
    const String& derived_dataset_name) {
  auto uri = StringUtil::format(
      "$0/fetch_derived_dataset?chunk=$1&derived_dataset=$2",
      uri_,
      URI::urlEncode(partition),
      URI::urlEncode(derived_dataset_name));

  auto req = http::HTTPRequest::mkGet(uri);
  auto res = http_->executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 200) {
    RAISEF(kRuntimeError, "received non-200 response: $0", r.body().toString());
  }

  return r.body();
}

} // namespace tdsb
} // namespace fnord
<|endoftext|>


<commit_before>#ifndef YAMAIL_RESOURCE_POOL_ERROR_HPP
#define YAMAIL_RESOURCE_POOL_ERROR_HPP

#include <boost/system/error_code.hpp>

#include <sstream>

namespace yamail {
namespace resource_pool {
namespace error {

struct empty_handle : std::logic_error {
    empty_handle() : std::logic_error("handle is empty") {}
};

struct unusable_handle : std::logic_error {
    unusable_handle() : std::logic_error("handle is unusable") {}
};

struct zero_pool_capacity : std::logic_error {
    zero_pool_capacity() : std::logic_error("pool capacity is 0") {}
};

enum code {
    ok,
    get_resource_timeout,
    request_queue_overflow,
    disabled,
};

namespace detail {

class category : public boost::system::error_category {
public:
    const char* name() const throw() { return "yamail::resource_pool::error::detail::category"; }

    std::string message(int value) const {
        switch (code(value)) {
            case ok:
                return "no error";
            case get_resource_timeout:
                return "get resource timeout";
            case request_queue_overflow:
                return "request queue overflow";
            case disabled:
                return "resource pool is disabled";
        }
        std::ostringstream error;
        error << "no message for yamail::resource_pool::error: " << value;
        throw std::logic_error(error.str());
    }
};

}

inline const boost::system::error_category& get_category() {
    static detail::category instance;
    return instance;
}

}
}
}

namespace boost {
namespace system {

template <>
struct is_error_code_enum<yamail::resource_pool::error::code> {
    static const bool value = true;
};

}
}

namespace yamail {
namespace resource_pool {

inline boost::system::error_code make_error_code(const error::code e) {
    return boost::system::error_code(static_cast<int>(e), error::get_category());
}

}
}

#endif
<commit_msg>Repace throw() by noexcept<commit_after>#ifndef YAMAIL_RESOURCE_POOL_ERROR_HPP
#define YAMAIL_RESOURCE_POOL_ERROR_HPP

#include <boost/system/error_code.hpp>

#include <sstream>

namespace yamail {
namespace resource_pool {
namespace error {

struct empty_handle : std::logic_error {
    empty_handle() : std::logic_error("handle is empty") {}
};

struct unusable_handle : std::logic_error {
    unusable_handle() : std::logic_error("handle is unusable") {}
};

struct zero_pool_capacity : std::logic_error {
    zero_pool_capacity() : std::logic_error("pool capacity is 0") {}
};

enum code {
    ok,
    get_resource_timeout,
    request_queue_overflow,
    disabled,
};

namespace detail {

class category : public boost::system::error_category {
public:
    const char* name() const noexcept { return "yamail::resource_pool::error::detail::category"; }

    std::string message(int value) const {
        switch (code(value)) {
            case ok:
                return "no error";
            case get_resource_timeout:
                return "get resource timeout";
            case request_queue_overflow:
                return "request queue overflow";
            case disabled:
                return "resource pool is disabled";
        }
        std::ostringstream error;
        error << "no message for yamail::resource_pool::error: " << value;
        throw std::logic_error(error.str());
    }
};

}

inline const boost::system::error_category& get_category() {
    static detail::category instance;
    return instance;
}

}
}
}

namespace boost {
namespace system {

template <>
struct is_error_code_enum<yamail::resource_pool::error::code> {
    static const bool value = true;
};

}
}

namespace yamail {
namespace resource_pool {

inline boost::system::error_code make_error_code(const error::code e) {
    return boost::system::error_code(static_cast<int>(e), error::get_category());
}

}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "Url.h"
#include "Convert.h"

using namespace std;
using namespace db::net;
using namespace db::util;

Url::Url(const string& url) throw(MalformedUrlException)
{
   // find the first colon
   string::size_type index = url.find_first_of(':');
   if(index == string::npos)
   {
      // no colon found
      throw MalformedUrlException("Url is missing a colon!");
   }

   // split string into the scheme and scheme-specific-part
   mScheme = url.substr(0, index);

   // check scheme for validity
   char c;
   for(string::iterator i = mScheme.begin(); i != mScheme.end(); i++)
   {
      // character must be 'a'-'z', '+', '.', or '-'
      c = *i;
      if(c > 'z')
      {
         throw MalformedUrlException(
            "Url scheme contains invalid characters!");
      }

      if(c < 'a' && (c != '+' || c != '.' || c != '-'))
      {
         throw MalformedUrlException(
            "Url scheme contains invalid characters!");
      }
   }

   if(index != url.length() - 1)
   {
      // get scheme specific part
      mSchemeSpecificPart = url.substr(index + 1);

      // get authority, path, and query:

      // authority is preceeded by double slash "//" and
      // is terminated by single slash "/", a question mark "?", or
      // the end of the url
      index = mSchemeSpecificPart.find_first_of("//");
      if(index == 0 && mSchemeSpecificPart.length() > 2)
      {
         string::size_type slash = mSchemeSpecificPart.find_first_of('/', 2);
         string::size_type qMark = mSchemeSpecificPart.find_first_of('?', 2);

         // see if a query exists
         if(qMark != string::npos)
         {
            // a query exists

            // get the path
            if(slash != string::npos && slash < qMark)
            {
               // get authority
               mAuthority = mSchemeSpecificPart.substr(2, slash - 2);

               // get path
               mPath = mSchemeSpecificPart.substr(slash, qMark - slash);
            }
            else
            {
               // get authority
               mAuthority = mSchemeSpecificPart.substr(2, qMark - 2);

               // use base path
               mPath = "/";
            }

            // get query
            if(qMark != mSchemeSpecificPart.length() - 1)
            {
               mQuery = mSchemeSpecificPart.substr(qMark + 1);
            }
         }
         else if(slash != string::npos)
         {
            // no query -- just authority and path

            // get authority
            mAuthority = mSchemeSpecificPart.substr(2, slash - 2);

            // get path
            mPath = mSchemeSpecificPart.substr(slash);
         }
         else
         {
            // no path or query, just authority

            // get authority
            mAuthority = mSchemeSpecificPart.substr(2);
         }
      }
   }
}

Url::~Url()
{
}

const string& Url::getScheme()
{
   return mScheme;
}

const string& Url::getSchemeSpecificPart()
{
   return mSchemeSpecificPart;
}

const string& Url::getAuthority()
{
   return mAuthority;
}

const string& Url::getPath()
{
   return mPath;
}

const string& Url::getQuery()
{
   return mQuery;
}

std::string Url::toString()
{
   return mScheme + ":" + mSchemeSpecificPart;
}

string Url::encode(const char* str, unsigned int length)
{
   string rval;

   char c;
   for(unsigned int i = 0; i < length; i++)
   {
      c = str[i];

      // see if the character is "safe" (0-9, A-Z, or a-z)
      if(c >= '0' && c <= '9')
      {
         rval += c;
      }
      else if(c >= 'A' && c <= 'Z')
      {
         rval += c;
      }
      else if(c >= 'a' && c <= 'z')
      {
         rval += c;
      }
      else if(c == ' ')
      {
         // substitute pluses for spaces
         rval += '+';
      }
      else
      {
         // character is unsafe, so add a '%' and convert to hex
         rval += '%';
         rval += Convert::bytesToUpperHex(&c, 1);
      }
   }

   return rval;
}

string Url::decode(const char* str, unsigned int length)
{
   string rval;

   char c;
   unsigned int cLength;
   for(unsigned int i = 0; i < length; i++)
   {
      c = str[i];

      // see if the character is "safe" (0-9, A-Z, or a-z)
      if(c >= '0' && c <= '9')
      {
         rval += c;
      }
      else if(c >= 'A' && c <= 'Z')
      {
         rval += c;
      }
      else if(c >= 'a' && c <= 'z')
      {
         rval += c;
      }
      else if(c == '+')
      {
         // substitute spaces for pluses
         rval += ' ';
      }
      else if(c == '%')
      {
         // looking for 3 characters
         if(i + 2 < length)
         {
            Convert::hexToBytes(str + i + 1, 2, &c, cLength);
            rval += c;
         }

         // skip two characters
         i += 2;
      }
   }

   return rval;
}
<commit_msg>Added code to automatically decapitalize url schemes.<commit_after>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "Url.h"
#include "Convert.h"

using namespace std;
using namespace db::net;
using namespace db::util;

Url::Url(const string& url) throw(MalformedUrlException)
{
   // find the first colon
   string::size_type index = url.find_first_of(':');
   if(index == string::npos)
   {
      // no colon found
      throw MalformedUrlException("Url is missing a colon!");
   }

   // split string into the scheme and scheme-specific-part
   mScheme = url.substr(0, index);

   // make scheme lower case
   transform(mScheme.begin(), mScheme.end(), mScheme.begin(), tolower);

   // check scheme for validity
   char c;
   for(string::iterator i = mScheme.begin(); i != mScheme.end(); i++)
   {
      // character must be 'a'-'z', '+', '.', or '-'
      c = *i;
      if(c > 'z')
      {
         throw MalformedUrlException(
            "Url scheme contains invalid characters!");
      }

      if(c < 'a' && (c != '+' || c != '.' || c != '-'))
      {
         throw MalformedUrlException(
            "Url scheme contains invalid characters!");
      }
   }

   if(index != url.length() - 1)
   {
      // get scheme specific part
      mSchemeSpecificPart = url.substr(index + 1);

      // get authority, path, and query:

      // authority is preceeded by double slash "//" and
      // is terminated by single slash "/", a question mark "?", or
      // the end of the url
      index = mSchemeSpecificPart.find_first_of("//");
      if(index == 0 && mSchemeSpecificPart.length() > 2)
      {
         string::size_type slash = mSchemeSpecificPart.find_first_of('/', 2);
         string::size_type qMark = mSchemeSpecificPart.find_first_of('?', 2);

         // see if a query exists
         if(qMark != string::npos)
         {
            // a query exists

            // get the path
            if(slash != string::npos && slash < qMark)
            {
               // get authority
               mAuthority = mSchemeSpecificPart.substr(2, slash - 2);

               // get path
               mPath = mSchemeSpecificPart.substr(slash, qMark - slash);
            }
            else
            {
               // get authority
               mAuthority = mSchemeSpecificPart.substr(2, qMark - 2);

               // use base path
               mPath = "/";
            }

            // get query
            if(qMark != mSchemeSpecificPart.length() - 1)
            {
               mQuery = mSchemeSpecificPart.substr(qMark + 1);
            }
         }
         else if(slash != string::npos)
         {
            // no query -- just authority and path

            // get authority
            mAuthority = mSchemeSpecificPart.substr(2, slash - 2);

            // get path
            mPath = mSchemeSpecificPart.substr(slash);
         }
         else
         {
            // no path or query, just authority

            // get authority
            mAuthority = mSchemeSpecificPart.substr(2);
         }
      }
   }
}

Url::~Url()
{
}

const string& Url::getScheme()
{
   return mScheme;
}

const string& Url::getSchemeSpecificPart()
{
   return mSchemeSpecificPart;
}

const string& Url::getAuthority()
{
   return mAuthority;
}

const string& Url::getPath()
{
   return mPath;
}

const string& Url::getQuery()
{
   return mQuery;
}

std::string Url::toString()
{
   return mScheme + ":" + mSchemeSpecificPart;
}

string Url::encode(const char* str, unsigned int length)
{
   string rval;

   char c;
   for(unsigned int i = 0; i < length; i++)
   {
      c = str[i];

      // see if the character is "safe" (0-9, A-Z, or a-z)
      if(c >= '0' && c <= '9')
      {
         rval += c;
      }
      else if(c >= 'A' && c <= 'Z')
      {
         rval += c;
      }
      else if(c >= 'a' && c <= 'z')
      {
         rval += c;
      }
      else if(c == ' ')
      {
         // substitute pluses for spaces
         rval += '+';
      }
      else
      {
         // character is unsafe, so add a '%' and convert to hex
         rval += '%';
         rval += Convert::bytesToUpperHex(&c, 1);
      }
   }

   return rval;
}

string Url::decode(const char* str, unsigned int length)
{
   string rval;

   char c;
   unsigned int cLength;
   for(unsigned int i = 0; i < length; i++)
   {
      c = str[i];

      // see if the character is "safe" (0-9, A-Z, or a-z)
      if(c >= '0' && c <= '9')
      {
         rval += c;
      }
      else if(c >= 'A' && c <= 'Z')
      {
         rval += c;
      }
      else if(c >= 'a' && c <= 'z')
      {
         rval += c;
      }
      else if(c == '+')
      {
         // substitute spaces for pluses
         rval += ' ';
      }
      else if(c == '%')
      {
         // looking for 3 characters
         if(i + 2 < length)
         {
            Convert::hexToBytes(str + i + 1, 2, &c, cLength);
            rval += c;
         }

         // skip two characters
         i += 2;
      }
   }

   return rval;
}
<|endoftext|>


<commit_before>#include <bfcp/client/base_client.h>

#include <boost/bind.hpp>
#include <muduo/base/Logging.h>

#include <bfcp/common/bfcp_conn.h>

using namespace muduo;
using namespace muduo::net;

namespace bfcp
{

namespace client
{

BaseClient::BaseClient(muduo::net::EventLoop* loop,
                       const muduo::net::InetAddress& serverAddr,
                       uint32_t conferenceID,
                       uint16_t userID)
    : loop_(loop),
      client_(loop, serverAddr, "BfcpClient"),
      serverAddr_(serverAddr),
      conferenceID_(conferenceID),
      userID_(userID),
      state_(kDisconnected)
{
  client_.setMessageCallback(
    boost::bind(&BaseClient::onMessage, this, _1, _2, _3, _4));
  client_.setStartedRecvCallback(
    boost::bind(&BaseClient::onStartedRecv, this, _1));
  client_.setWriteCompleteCallback(
    boost::bind(&BaseClient::onWriteComplete, this, _1, _2));

  initResponseHandlers();
}

void BaseClient::initResponseHandlers()
{
  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_REQUEST,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_RELEASE,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_REQUEST_QUERY,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_USER_QUERY,
    boost::bind(&BaseClient::handleUserStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_QUERY,
    boost::bind(&BaseClient::handleFloorStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_CHAIR_ACTION,
    boost::bind(&BaseClient::handleChairAcionAck, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_HELLO,
    boost::bind(&BaseClient::handleHelloAck, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_GOODBYE,
    boost::bind(&BaseClient::handleGoodbyeAck, this, _1)));
}

void BaseClient::connect()
{
  if (state_ == kDisconnected)
  {
    client_.connect();
    changeState(kConnecting);
  }
}

void BaseClient::disconnect()
{
  if (state_ == kConnected)
  {
    changeState(kDisconnecting);
  }
}

void BaseClient::forceDisconnect()
{
  client_.disconnect();
  changeState(kDisconnected);
}

void BaseClient::changeState( State state )
{
  if (state_ != state)
  {
    state_ = state;
    LOG_TRACE << "BfcpClient change state to " << toString(state);
    if (stateChangedCallback_)
      stateChangedCallback_(state);
  }
}

const char* BaseClient::toString( State state ) const
{
  switch (state)
  {
    case kDisconnecting: return "disconnecting";
    case kDisconnected: return "disconnected";
    case kConnecting: return "connecting";
    case kConnected: return "connected";
    default: return "???";
  }
}

void BaseClient::onStartedRecv( const UdpSocketPtr& socket )
{
  LOG_TRACE << socket->getLocalAddr().toIpPort() << " started receiving data from "
            << socket->getPeerAddr().toIpPort();

  assert(socket == client_.socket());
  if (!connection_)
  {
    connection_ = boost::make_shared<BfcpConnection>(loop_, client_.socket());
    connection_->setNewRequestCallback(
      boost::bind(&BaseClient::onNewRequest, this, _1));
  }
  if (state_ == kConnecting)
  {
    sendHello();
  }
}

void BaseClient::sendFloorRequest( const FloorRequestParam &floorRequest )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorRequest(
    generateBasicParam(BFCP_FLOOR_REQUEST),
    floorRequest);
}

void BaseClient::sendFloorRelease( uint16_t floorRequestID )
{
  assert(client_.isConnected());
  assert(connection_);
  connection_->sendFloorRelease(
    generateBasicParam(BFCP_FLOOR_RELEASE),
    floorRequestID);
}

void BaseClient::sendFloorRequestQuery( uint16_t floorRequestID )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorRequestQuery(
    generateBasicParam(BFCP_FLOOR_REQUEST_QUERY),
    floorRequestID);
}

void BaseClient::sendUserQuery( const UserQueryParam userQuery )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendUserQuery(
    generateBasicParam(BFCP_USER_QUERY),
    userQuery);
}

void BaseClient::sendFloorQuery( const bfcp_floor_id_list &floorIDs )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorQuery(
    generateBasicParam(BFCP_FLOOR_QUERY),
    floorIDs);
}

void BaseClient::sendChairAction( const FloorRequestInfoParam &frqInfo )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendChairAction(
    generateBasicParam(BFCP_CHAIR_ACTION),
    frqInfo);
}

void BaseClient::sendHello()
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendHello(generateBasicParam(BFCP_HELLO));
}

void BaseClient::sendGoodBye()
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendGoodBye(generateBasicParam(BFCP_GOODBYE));
}

BasicRequestParam BaseClient::generateBasicParam( bfcp_prim primitive )
{
  BasicRequestParam param;
  param.cb = boost::bind(&BaseClient::onResponse, this, primitive, _1, _2);
  param.conferenceID = conferenceID_;
  param.userID = userID_;
  param.dst = serverAddr_;
  return param;
}

void BaseClient::onMessage(const UdpSocketPtr& socket,
                           Buffer* buf,
                           const InetAddress &src,
                           Timestamp time)
{
  LOG_TRACE << client_.name() << " recv " << buf->readableBytes()
            << " bytes at " << time.toString()
            << " from " << src.toIpPort();

  if (connection_)
  {
    connection_->onMessage(buf, src);
  }
}

void BaseClient::onWriteComplete( const UdpSocketPtr& socket, int messageId )
{
  LOG_TRACE << "message " << messageId << " write completed";
}

void BaseClient::onNewRequest( const BfcpMsg &msg )
{
  LOG_TRACE << "BfcpClient received new request "
            << bfcp_prim_name(msg.primitive());

  switch (msg.primitive())
  {
    case BFCP_FLOOR_STATUS:
      handleFloorStatus(msg); break;

    case BFCP_FLOOR_REQUEST_STATUS:
      handleFloorRequestStatus(msg); break;

    default:
      LOG_ERROR << "Ignore unexpected BFCP request message "
                << msg.primitive();
      break;
  }
}

void BaseClient::onResponse(bfcp_prim requestPrimitive,
                            ResponseError err,
                            const BfcpMsg &msg)
{
  if (err != kNoError)
  {
    LOG_TRACE << "BfcpClient received response with error "
              << responce_error_name(err);
    changeState(kDisconnected);
  }
  else
  {
    LOG_TRACE << "BfcpClient received response "
              << bfcp_prim_name(msg.primitive());
    if (msg.primitive() == BFCP_ERROR)
    {
      handleError(msg);
    }
    else
    {
      auto it = responseHandlers_.find(requestPrimitive);
      assert(it != responseHandlers_.end());
      (*it).second(msg);
    }
  }
}

void BaseClient::handleFloorRequestStatus( const BfcpMsg &msg )
{
  if (!checkMsg(msg, BFCP_FLOOR_REQUEST_STATUS)) return;

  if (!msg.isResponse())
  {
    connection_->replyWithFloorRequestStatusAck(msg);
  }

  auto attr = msg.findAttribute(BFCP_FLOOR_REQ_INFO);
  if (!attr)
  {
    LOG_ERROR << "No FLOOR-REQUEST-INFORMATION found in BFCP FloorRequestStatus message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_FLOOR_REQUEST_STATUS, nullptr);
  }
  else
  {
    BfcpAttr frqInfoAttr(*attr);
    bfcp_floor_request_info info = frqInfoAttr.getFloorRequestInfo();

    FloorRequestInfoParam param;
    param.set(info);

    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_REQUEST_STATUS, &param);
  }
}

void BaseClient::handleUserStatus( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_USER_STATUS)) return;

  UserStatusParam param;
  auto attr = msg.findAttribute(BFCP_BENEFICIARY_INFO);
  if (attr)
  {
    BfcpAttr beneficiaryInfoAttr(*attr);
    bfcp_user_info info = beneficiaryInfoAttr.getBeneficiaryInfo();
    param.setBeneficiary(info);
  }

  auto attrs = msg.findAttributes(BFCP_FLOOR_REQ_INFO);
  param.frqInfoList.reserve(attrs.size());
  for (auto &attr : attrs)
  {
    bfcp_floor_request_info frqInfo = attr.getFloorRequestInfo();
    param.addFloorRequestInfo(frqInfo);
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_USER_STATUS, &param);
}

void BaseClient::handleFloorStatus( const BfcpMsg &msg )
{
  if (!checkMsg(msg, BFCP_FLOOR_STATUS)) return;

  if (!msg.isResponse())
  {
    connection_->replyWithFloorStatusAck(msg);
  }

  auto attr = msg.findAttribute(BFCP_FLOOR_ID);
  if (!attr)
  {
    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_STATUS, nullptr);
  }
  else
  {
    BfcpAttr floorIDAttr(*attr);
    FloorStatusParam param;
    param.floorID = floorIDAttr.getFloorID();

    auto attrs = msg.findAttributes(BFCP_FLOOR_REQ_INFO);
    param.frqInfoList.reserve(attrs.size());
    for (auto &attr : attrs)
    {
      bfcp_floor_request_info info = attr.getFloorRequestInfo();
      param.addFloorRequestInfo(info);
    }

    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_STATUS, &param);
  }
}

void BaseClient::handleChairAcionAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_CHAIR_ACTION_ACK)) return;
  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_CHAIR_ACTION_ACK, nullptr);
}

void BaseClient::handleHelloAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_HELLO_ACK)) return;

  changeState(kConnected);

  auto attr = msg.findAttribute(BFCP_SUPPORTED_PRIMS);
  if (!attr)
  {
    LOG_ERROR << "No SUPPORTED-PRIMITIVES found in BFCP HelloAck message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_HELLO_ACK, nullptr);
    return;
  }
  else
  {
    BfcpAttr supportedPrimsAttr(*attr);
    auto &supPrims = supportedPrimsAttr.getSupportedPrims();
    // TODO: check supported primitives
  }

  attr = msg.findAttribute(BFCP_SUPPORTED_ATTRS);
  if (!attr)
  {
    LOG_ERROR << "No SUPPORTED-ATTRIBUTES found in BFCP HelloAck message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_HELLO_ACK, nullptr);
    return;
  }
  else
  {
    BfcpAttr supportedAttrsAttr(*attr);
    auto &supAttrs = supportedAttrsAttr.getSupportedAttrs();
    // TODO: check supported attributes
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_HELLO_ACK, nullptr);
}

void BaseClient::handleGoodbyeAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_GOODBYE_ACK)) return;

  if (state_ == kDisconnecting)
  {
    client_.disconnect();
    changeState(kDisconnected);
  }
}

void BaseClient::handleError( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_ERROR)) return;

  ErrorParam param;
  auto attr = msg.findAttribute(BFCP_ERROR_CODE);
  if (!attr)
  {
    LOG_ERROR << "No ERROR-CODE found in BFCP Error message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_ERROR, nullptr);
    return;
  }

  BfcpAttr errorCodeAttr(*attr);
  bfcp_errcode errcode = errorCodeAttr.getErrorCode();
  param.errorCode.set(errcode);

  attr = msg.findAttribute(BFCP_ERROR_INFO);
  if (attr)
  {
    BfcpAttr errorInfoAttr(*attr);
    const char *errorInfo = errorInfoAttr.getErrorInfo();
    param.setErrorInfo(errorInfo);
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_ERROR, &param);
}

bool BaseClient::checkMsg( const BfcpMsg &msg, bfcp_prim expectedPrimitive ) const
{
  if (msg.getConferenceID() != conferenceID_)
  {
    LOG_ERROR << "Expected BFCP conference ID is " << conferenceID_
              << " but get " << msg.getConferenceID();
    return false;
  }

  if (msg.getUserID() != userID_)
  {
    LOG_ERROR << "Expected BFCP user ID is " << userID_
              << " but get " << msg.getUserID();
    return false;
  }

  if (msg.primitive() != expectedPrimitive)
  {
    LOG_ERROR << "Expected BFCP " << bfcp_prim_name(expectedPrimitive)
              << " but get " << bfcp_prim_name(msg.primitive());
    return false;
  }

  auto &unknownAttrs = msg.getUnknownAttrs();
  if (unknownAttrs.typec != 0)
  {
    LOG_WARN << "Ignore " << unknownAttrs.typec
             << " unknown attribute(s) in the received "
             << bfcp_prim_name(msg.primitive());
  }

  return true;
}

} // namespace client
} // namespace bfcp<commit_msg>fix BaseClient<commit_after>#include <bfcp/client/base_client.h>

#include <boost/bind.hpp>
#include <muduo/base/Logging.h>

#include <bfcp/common/bfcp_conn.h>

using namespace muduo;
using namespace muduo::net;

namespace bfcp
{

namespace client
{

BaseClient::BaseClient(muduo::net::EventLoop* loop,
                       const muduo::net::InetAddress& serverAddr,
                       uint32_t conferenceID,
                       uint16_t userID)
    : loop_(loop),
      client_(loop, serverAddr, "BfcpClient"),
      serverAddr_(serverAddr),
      conferenceID_(conferenceID),
      userID_(userID),
      state_(kDisconnected)
{
  client_.setMessageCallback(
    boost::bind(&BaseClient::onMessage, this, _1, _2, _3, _4));
  client_.setStartedRecvCallback(
    boost::bind(&BaseClient::onStartedRecv, this, _1));
  client_.setWriteCompleteCallback(
    boost::bind(&BaseClient::onWriteComplete, this, _1, _2));

  initResponseHandlers();
}

void BaseClient::initResponseHandlers()
{
  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_REQUEST,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_RELEASE,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_REQUEST_QUERY,
    boost::bind(&BaseClient::handleFloorRequestStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_USER_QUERY,
    boost::bind(&BaseClient::handleUserStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_FLOOR_QUERY,
    boost::bind(&BaseClient::handleFloorStatus, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_CHAIR_ACTION,
    boost::bind(&BaseClient::handleChairAcionAck, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_HELLO,
    boost::bind(&BaseClient::handleHelloAck, this, _1)));

  responseHandlers_.insert(std::make_pair(
    BFCP_GOODBYE,
    boost::bind(&BaseClient::handleGoodbyeAck, this, _1)));
}

void BaseClient::connect()
{
  if (state_ == kDisconnected)
  {
    client_.connect();
    changeState(kConnecting);
  }
}

void BaseClient::disconnect()
{
  if (state_ == kConnected)
  {
    changeState(kDisconnecting);
  }
}

void BaseClient::forceDisconnect()
{
  client_.disconnect();
  changeState(kDisconnected);
}

void BaseClient::changeState( State state )
{
  if (state_ != state)
  {
    LOG_TRACE << "BfcpClient change state to " << toString(state);
    state_ = state;
    if (stateChangedCallback_)
      stateChangedCallback_(state);
  }
}

const char* BaseClient::toString( State state ) const
{
  switch (state)
  {
    case kDisconnecting: return "disconnecting";
    case kDisconnected: return "disconnected";
    case kConnecting: return "connecting";
    case kConnected: return "connected";
    default: return "???";
  }
}

void BaseClient::onStartedRecv( const UdpSocketPtr& socket )
{
  LOG_TRACE << socket->getLocalAddr().toIpPort() << " started receiving data from "
            << socket->getPeerAddr().toIpPort();

  assert(socket == client_.socket());
  if (!connection_)
  {
    connection_ = boost::make_shared<BfcpConnection>(loop_, client_.socket());
    connection_->setNewRequestCallback(
      boost::bind(&BaseClient::onNewRequest, this, _1));
  }
  if (state_ == kConnecting)
  {
    sendHello();
  }
}

void BaseClient::sendFloorRequest( const FloorRequestParam &floorRequest )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorRequest(
    generateBasicParam(BFCP_FLOOR_REQUEST),
    floorRequest);
}

void BaseClient::sendFloorRelease( uint16_t floorRequestID )
{
  assert(client_.isConnected());
  assert(connection_);
  connection_->sendFloorRelease(
    generateBasicParam(BFCP_FLOOR_RELEASE),
    floorRequestID);
}

void BaseClient::sendFloorRequestQuery( uint16_t floorRequestID )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorRequestQuery(
    generateBasicParam(BFCP_FLOOR_REQUEST_QUERY),
    floorRequestID);
}

void BaseClient::sendUserQuery( const UserQueryParam userQuery )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendUserQuery(
    generateBasicParam(BFCP_USER_QUERY),
    userQuery);
}

void BaseClient::sendFloorQuery( const bfcp_floor_id_list &floorIDs )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendFloorQuery(
    generateBasicParam(BFCP_FLOOR_QUERY),
    floorIDs);
}

void BaseClient::sendChairAction( const FloorRequestInfoParam &frqInfo )
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendChairAction(
    generateBasicParam(BFCP_CHAIR_ACTION),
    frqInfo);
}

void BaseClient::sendHello()
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendHello(generateBasicParam(BFCP_HELLO));
}

void BaseClient::sendGoodBye()
{
  assert(client_.isConnected());
  assert(connection_);

  connection_->sendGoodBye(generateBasicParam(BFCP_GOODBYE));
}

BasicRequestParam BaseClient::generateBasicParam( bfcp_prim primitive )
{
  BasicRequestParam param;
  param.cb = boost::bind(&BaseClient::onResponse, this, primitive, _1, _2);
  param.conferenceID = conferenceID_;
  param.userID = userID_;
  param.dst = serverAddr_;
  return param;
}

void BaseClient::onMessage(const UdpSocketPtr& socket,
                           Buffer* buf,
                           const InetAddress &src,
                           Timestamp time)
{
  LOG_TRACE << client_.name() << " recv " << buf->readableBytes()
            << " bytes at " << time.toString()
            << " from " << src.toIpPort();

  assert(connection_);
  connection_->onMessage(buf, src);
}

void BaseClient::onWriteComplete( const UdpSocketPtr& socket, int messageId )
{
  LOG_TRACE << "message " << messageId << " write completed";
}

void BaseClient::onNewRequest( const BfcpMsg &msg )
{
  LOG_TRACE << "BfcpClient received new request "
            << bfcp_prim_name(msg.primitive());

  switch (msg.primitive())
  {
    case BFCP_FLOOR_STATUS:
      handleFloorStatus(msg); break;

    case BFCP_FLOOR_REQUEST_STATUS:
      handleFloorRequestStatus(msg); break;

    default:
      LOG_ERROR << "Ignore unexpected BFCP request message "
                << msg.primitive();
      break;
  }
}

void BaseClient::onResponse(bfcp_prim requestPrimitive,
                            ResponseError err,
                            const BfcpMsg &msg)
{
  if (err != kNoError)
  {
    LOG_TRACE << "BfcpClient received response with error "
              << response_error_name(err);
    changeState(kDisconnected);
  }
  else
  {
    LOG_TRACE << "BfcpClient received response "
              << bfcp_prim_name(msg.primitive());
    if (msg.primitive() == BFCP_ERROR)
    {
      handleError(msg);
    }
    else
    {
      auto it = responseHandlers_.find(requestPrimitive);
      assert(it != responseHandlers_.end());
      (*it).second(msg);
    }
  }
}

void BaseClient::handleFloorRequestStatus( const BfcpMsg &msg )
{
  if (!checkMsg(msg, BFCP_FLOOR_REQUEST_STATUS)) return;

  if (!msg.isResponse())
  {
    connection_->replyWithFloorRequestStatusAck(msg);
  }

  auto attr = msg.findAttribute(BFCP_FLOOR_REQ_INFO);
  if (!attr)
  {
    LOG_ERROR << "No FLOOR-REQUEST-INFORMATION found in BFCP FloorRequestStatus message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_FLOOR_REQUEST_STATUS, nullptr);
  }
  else
  {
    BfcpAttr frqInfoAttr(*attr);
    bfcp_floor_request_info info = frqInfoAttr.getFloorRequestInfo();

    FloorRequestInfoParam param;
    param.set(info);

    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_REQUEST_STATUS, &param);
  }
}

void BaseClient::handleUserStatus( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_USER_STATUS)) return;

  UserStatusParam param;
  auto attr = msg.findAttribute(BFCP_BENEFICIARY_INFO);
  if (attr)
  {
    BfcpAttr beneficiaryInfoAttr(*attr);
    bfcp_user_info info = beneficiaryInfoAttr.getBeneficiaryInfo();
    param.setBeneficiary(info);
  }

  auto attrs = msg.findAttributes(BFCP_FLOOR_REQ_INFO);
  for (auto &attr : attrs)
  {
    bfcp_floor_request_info frqInfo = attr.getFloorRequestInfo();
    param.addFloorRequestInfo(frqInfo);
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_USER_STATUS, &param);
}

void BaseClient::handleFloorStatus( const BfcpMsg &msg )
{
  if (!checkMsg(msg, BFCP_FLOOR_STATUS)) return;

  if (!msg.isResponse())
  {
    connection_->replyWithFloorStatusAck(msg);
  }

  auto attr = msg.findAttribute(BFCP_FLOOR_ID);
  if (!attr)
  {
    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_STATUS, nullptr);
  }
  else
  {
    BfcpAttr floorIDAttr(*attr);
    FloorStatusParam param;
    param.floorID = floorIDAttr.getFloorID();

    auto attrs = msg.findAttributes(BFCP_FLOOR_REQ_INFO);
    for (auto &attr : attrs)
    {
      bfcp_floor_request_info info = attr.getFloorRequestInfo();
      param.addFloorRequestInfo(info);
    }

    if (responseReceivedCallback_)
      responseReceivedCallback_(kNoError, BFCP_FLOOR_STATUS, &param);
  }
}

void BaseClient::handleChairAcionAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_CHAIR_ACTION_ACK)) return;
  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_CHAIR_ACTION_ACK, nullptr);
}

void BaseClient::handleHelloAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_HELLO_ACK)) return;

  changeState(kConnected);

  auto attr = msg.findAttribute(BFCP_SUPPORTED_PRIMS);
  if (!attr)
  {
    LOG_ERROR << "No SUPPORTED-PRIMITIVES found in BFCP HelloAck message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_HELLO_ACK, nullptr);
    return;
  }
  else
  {
    BfcpAttr supportedPrimsAttr(*attr);
    auto &supPrims = supportedPrimsAttr.getSupportedPrims();
    // TODO: check supported primitives
  }

  attr = msg.findAttribute(BFCP_SUPPORTED_ATTRS);
  if (!attr)
  {
    LOG_ERROR << "No SUPPORTED-ATTRIBUTES found in BFCP HelloAck message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_HELLO_ACK, nullptr);
    return;
  }
  else
  {
    BfcpAttr supportedAttrsAttr(*attr);
    auto &supAttrs = supportedAttrsAttr.getSupportedAttrs();
    // TODO: check supported attributes
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_HELLO_ACK, nullptr);
}

void BaseClient::handleGoodbyeAck( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_GOODBYE_ACK)) return;

  if (state_ == kDisconnecting)
  {
    client_.disconnect();
    changeState(kDisconnected);
  }
}

void BaseClient::handleError( const BfcpMsg &msg )
{
  assert(msg.isResponse());
  if (!checkMsg(msg, BFCP_ERROR)) return;

  ErrorParam param;
  auto attr = msg.findAttribute(BFCP_ERROR_CODE);
  if (!attr)
  {
    LOG_ERROR << "No ERROR-CODE found in BFCP Error message";
    if (responseReceivedCallback_)
      responseReceivedCallback_(kMissingMandatoryAttr, BFCP_ERROR, nullptr);
    return;
  }

  BfcpAttr errorCodeAttr(*attr);
  bfcp_errcode errcode = errorCodeAttr.getErrorCode();
  param.errorCode.set(errcode);

  attr = msg.findAttribute(BFCP_ERROR_INFO);
  if (attr)
  {
    BfcpAttr errorInfoAttr(*attr);
    const char *errorInfo = errorInfoAttr.getErrorInfo();
    param.setErrorInfo(errorInfo);
  }

  if (responseReceivedCallback_)
    responseReceivedCallback_(kNoError, BFCP_ERROR, &param);
}

bool BaseClient::checkMsg( const BfcpMsg &msg, bfcp_prim expectedPrimitive ) const
{
  if (msg.getConferenceID() != conferenceID_)
  {
    LOG_ERROR << "Expected BFCP Conference ID is " << conferenceID_
              << " but get " << msg.getConferenceID();
    return false;
  }

  if (msg.getUserID() != userID_)
  {
    LOG_ERROR << "Expected BFCP User ID is " << userID_
              << " but get " << msg.getUserID();
    return false;
  }

  if (msg.primitive() != expectedPrimitive)
  {
    LOG_ERROR << "Expected BFCP " << bfcp_prim_name(expectedPrimitive)
              << " but get " << bfcp_prim_name(msg.primitive());
    return false;
  }

  auto &unknownAttrs = msg.getUnknownAttrs();
  if (unknownAttrs.typec != 0)
  {
    LOG_WARN << "Ignore " << unknownAttrs.typec
             << " unknown attribute(s) in the received "
             << bfcp_prim_name(msg.primitive());
  }

  return true;
}

} // namespace client
} // namespace bfcp<|endoftext|>