<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Red Hat, Inc., Eike Rathke <erack@redhat.com>
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <sal/precppunit.hxx>

#include <tubes/contact-list.hxx>
#include <tubes/manager.hxx>

#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <rtl/bootstrap.hxx>
#include <unotest/bootstrapfixturebase.hxx>

namespace {

class TestTeleTubes: public test::BootstrapFixtureBase
{
public:

    TestTeleTubes();
    ~TestTeleTubes();
    void testSetupManager1();
    void testSetupManager2();
    void testConnect1();
    void testConnect2();
    void testContactList();
    void testPrepareAccountManager1();
    void testPrepareAccountManager2();
    void testStartBuddySession1();
    void testStartBuddySession2();
    void testSendPacket();
    void testReceivePacket();
    void testFlushLoops();
    void testDestroyManager1();
    void testDestroyManager2();
    void testDestroyAccepterContact();
    void testFailAlways();

    GMainLoop*                  mpMainLoop;

    // Order is significant.
    CPPUNIT_TEST_SUITE( TestTeleTubes );
    CPPUNIT_TEST( testSetupManager1 );
    CPPUNIT_TEST( testSetupManager2 );
    CPPUNIT_TEST( testConnect1 );
    CPPUNIT_TEST( testConnect2 );
    CPPUNIT_TEST( testContactList );
    CPPUNIT_TEST( testPrepareAccountManager1 );
    CPPUNIT_TEST( testPrepareAccountManager2 );
    CPPUNIT_TEST( testStartBuddySession1 );
    CPPUNIT_TEST( testStartBuddySession2 );
    CPPUNIT_TEST( testSendPacket );
    CPPUNIT_TEST( testReceivePacket );
    CPPUNIT_TEST( testFlushLoops );
    CPPUNIT_TEST( testDestroyManager1 );
    CPPUNIT_TEST( testDestroyManager2 );
    CPPUNIT_TEST( testDestroyAccepterContact );
    CPPUNIT_TEST( testFailAlways );     // need failure to display SAL_LOG, comment out for real builds
    CPPUNIT_TEST_SUITE_END();

private:
// XXX The Jabber accounts specified in test-config.ini need to be setup in
// Empathy, enabled, connected, and on each other's rosters.
    rtl::OUString             maTestConfigIniURL;
    rtl::Bootstrap            maTestConfig;

    rtl::OString              maOffererIdentifier;
    rtl::OString              maAccepterIdentifier;
};

// static, not members, so they actually survive cppunit test iteration
static TeleManager* mpManager1 = NULL;
static TeleManager* mpManager2 = NULL;

static TpContact*   mpAccepterContact = NULL;

static sal_uInt32 nSentPackets = 0;

TestTeleTubes::TestTeleTubes()
    : maTestConfigIniURL(getURLFromSrc("/tubes/qa/test-config.ini")),
      maTestConfig(maTestConfigIniURL)
{
    TeleManager::addSuffixToNames( "TeleTest");

    rtl::OUString aOffererIdentifier;
    CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini",
        maTestConfig.getFrom("offerer", aOffererIdentifier));
    maOffererIdentifier = OUStringToOString( aOffererIdentifier, RTL_TEXTENCODING_UTF8);

    rtl::OUString aAccepterIdentifier;
    CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini",
        maTestConfig.getFrom("accepter", aAccepterIdentifier));
    maAccepterIdentifier = OUStringToOString( aAccepterIdentifier, RTL_TEXTENCODING_UTF8);
}

TestTeleTubes::~TestTeleTubes()
{
}

static void TeleTestTubes_ContactListPrepared( GError *errorOr0, void *user_data )
{
    TestTeleTubes *self = reinterpret_cast<TestTeleTubes *>(user_data);

    CPPUNIT_ASSERT( errorOr0 == 0 );

    g_main_loop_quit (self->mpMainLoop);
}

static gboolean
timed_out (void *user_data)
{
    CPPUNIT_ASSERT( false);

    GMainLoop *loop = reinterpret_cast<GMainLoop *>(user_data);

    g_main_loop_quit (loop);
    return FALSE;
}

void TestTeleTubes::testContactList()
{
    mpMainLoop = g_main_loop_new (NULL, FALSE);

    ContactList cl;
    cl.prepare( TeleTestTubes_ContactListPrepared, this );
    g_timeout_add_seconds (5, timed_out, mpMainLoop);
    g_main_loop_run (mpMainLoop);
    g_main_loop_unref (mpMainLoop);
    mpMainLoop = NULL;

    /* Okay, now everything's prepared, we can get contacts synchronously. */
    AccountContactPairV pairs;

    pairs = cl.getContacts();
    guint i;

    /* FIXME: this is racy, because we can't be 100% sure that MC has finished
     * discovering what we support and passing that on to the connection
     * manager...
     */

    /* Both our accounts are meant to be signed in, and they both should be
     * capable of LibreOffice tubes because this test runs after we register
     * our handler. */
    CPPUNIT_ASSERT_MESSAGE(
        "Make sure both your test accounts are signed in "
        "and are on each other's contact lists",
        pairs.size() > 0 );
    CPPUNIT_ASSERT(!mpAccepterContact);

    for (i = 0; i < pairs.size(); i++)
    {
        AccountContactPair pair = pairs[i];

        /* FIXME: verify that pair.first is the offerer account */
        if (tp_contact_get_identifier(pair.second) == maAccepterIdentifier) {
            mpAccepterContact = pair.second;
            g_object_ref(mpAccepterContact);
        }
        g_object_unref (pair.first);
        g_object_unref (pair.second);
    }

    CPPUNIT_ASSERT_MESSAGE(
        "Couldn't find accepter contact. "
        "Make sure both your test accounts are signed in "
        "and are on each other's contact lists",
        mpAccepterContact);
}

void TestTeleTubes::testSetupManager1()
{
    mpManager1 = new TeleManager( true);
}

void TestTeleTubes::testSetupManager2()
{
    mpManager2 = new TeleManager;
}

void TestTeleTubes::testPrepareAccountManager1()
{
    mpManager1->prepareAccountManager();
    TeleManager::AccountManagerStatus eStatus = mpManager1->getAccountManagerStatus();
    CPPUNIT_ASSERT( eStatus == TeleManager::AMS_PREPARED);
}

void TestTeleTubes::testPrepareAccountManager2()
{
    mpManager2->prepareAccountManager();
    TeleManager::AccountManagerStatus eStatus = mpManager2->getAccountManagerStatus();
    CPPUNIT_ASSERT( eStatus == TeleManager::AMS_PREPARED);
}

void TestTeleTubes::testStartBuddySession1()
{
    TpAccount *pAcc1 = mpManager1->getAccount(maOffererIdentifier);
    CPPUNIT_ASSERT( pAcc1 != 0);
    /* This has to run after testContactList has run successfully. */
    CPPUNIT_ASSERT( mpAccepterContact != 0);
    bool bStarted = mpManager1->startBuddySession( pAcc1, mpAccepterContact);
    CPPUNIT_ASSERT( bStarted == true);
}

void TestTeleTubes::testStartBuddySession2()
{
    //bool bStarted = mpManager2->startBuddySession( sAcc2, sAcc1);
    //CPPUNIT_ASSERT( bStarted == true);
}

void TestTeleTubes::testConnect1()
{
    bool bConnected = mpManager1->connect();
    CPPUNIT_ASSERT( bConnected == true);
}

void TestTeleTubes::testConnect2()
{
    bool bConnected = mpManager2->connect();
    CPPUNIT_ASSERT( bConnected == true);
}

void TestTeleTubes::testSendPacket()
{
    TelePacket aPacket( "", RTL_CONSTASCII_STRINGPARAM( "from 1 to 2"));
    nSentPackets = mpManager1->sendPacket( aPacket);
    CPPUNIT_ASSERT( nSentPackets == 2); // expect out+in conference, as own instance accepted self
}

void TestTeleTubes::testReceivePacket()
{
    TelePacket aPacket( "", RTL_CONSTASCII_STRINGPARAM( "from 1 to 2"));
    TelePacket aReceived;
    sal_uInt32 nReceivedPackets = 0;
    bool bOk;
    do
    {
        do
        {
            bOk = mpManager1->popPacket( aReceived);
            if (bOk)
            {
                ++nReceivedPackets;
                CPPUNIT_ASSERT( aPacket == aReceived);
            }
        } while (bOk);
        if (nReceivedPackets < nSentPackets)
            mpManager1->iterateLoop();
    } while (nReceivedPackets < nSentPackets);
    CPPUNIT_ASSERT( nReceivedPackets == nSentPackets);
}

void TestTeleTubes::testFlushLoops()
{
    mpManager1->flushLoop();
    mpManager2->flushLoop();
}

void TestTeleTubes::testDestroyManager1()
{
    delete mpManager1;
    mpManager1 = NULL;
}

void TestTeleTubes::testDestroyManager2()
{
    delete mpManager2;
    mpManager2 = NULL;
}

void TestTeleTubes::testDestroyAccepterContact()
{
    if (mpAccepterContact) {
        g_object_unref(mpAccepterContact);
        mpAccepterContact = NULL;
    }
}

void TestTeleTubes::testFailAlways()
{
    CPPUNIT_ASSERT( false);
}

CPPUNIT_TEST_SUITE_REGISTRATION( TestTeleTubes);

}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>tubes test: refactor spinning mainloop<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012 Red Hat, Inc., Eike Rathke <erack@redhat.com>
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <sal/precppunit.hxx>

#include <tubes/contact-list.hxx>
#include <tubes/manager.hxx>

#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <rtl/bootstrap.hxx>
#include <unotest/bootstrapfixturebase.hxx>

namespace {

class TestTeleTubes: public test::BootstrapFixtureBase
{
public:

    TestTeleTubes();
    ~TestTeleTubes();
    void testSetupManager1();
    void testSetupManager2();
    void testConnect1();
    void testConnect2();
    void testContactList();
    void testPrepareAccountManager1();
    void testPrepareAccountManager2();
    void testStartBuddySession1();
    void testStartBuddySession2();
    void testSendPacket();
    void testReceivePacket();
    void testFlushLoops();
    void testDestroyManager1();
    void testDestroyManager2();
    void testDestroyAccepterContact();
    void testFailAlways();

    GMainLoop*                  mpMainLoop;
    void spinMainLoop();

    // Order is significant.
    CPPUNIT_TEST_SUITE( TestTeleTubes );
    CPPUNIT_TEST( testSetupManager1 );
    CPPUNIT_TEST( testSetupManager2 );
    CPPUNIT_TEST( testConnect1 );
    CPPUNIT_TEST( testConnect2 );
    CPPUNIT_TEST( testContactList );
    CPPUNIT_TEST( testPrepareAccountManager1 );
    CPPUNIT_TEST( testPrepareAccountManager2 );
    CPPUNIT_TEST( testStartBuddySession1 );
    CPPUNIT_TEST( testStartBuddySession2 );
    CPPUNIT_TEST( testSendPacket );
    CPPUNIT_TEST( testReceivePacket );
    CPPUNIT_TEST( testFlushLoops );
    CPPUNIT_TEST( testDestroyManager1 );
    CPPUNIT_TEST( testDestroyManager2 );
    CPPUNIT_TEST( testDestroyAccepterContact );
    CPPUNIT_TEST( testFailAlways );     // need failure to display SAL_LOG, comment out for real builds
    CPPUNIT_TEST_SUITE_END();

private:
// XXX The Jabber accounts specified in test-config.ini need to be setup in
// Empathy, enabled, connected, and on each other's rosters.
    rtl::OUString             maTestConfigIniURL;
    rtl::Bootstrap            maTestConfig;

    rtl::OString              maOffererIdentifier;
    rtl::OString              maAccepterIdentifier;
};

// static, not members, so they actually survive cppunit test iteration
static TeleManager* mpManager1 = NULL;
static TeleManager* mpManager2 = NULL;

static TpContact*   mpAccepterContact = NULL;

static sal_uInt32 nSentPackets = 0;

static gboolean
timed_out (void *user_data)
{
    CPPUNIT_ASSERT_MESSAGE( "Test took longer than ten seconds!", false);

    GMainLoop *loop = reinterpret_cast<GMainLoop *>(user_data);

    g_main_loop_quit (loop);
    return FALSE;
}

TestTeleTubes::TestTeleTubes()
    : maTestConfigIniURL(getURLFromSrc("/tubes/qa/test-config.ini")),
      maTestConfig(maTestConfigIniURL)
{
    TeleManager::addSuffixToNames( "TeleTest");

    rtl::OUString aOffererIdentifier;
    CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini",
        maTestConfig.getFrom("offerer", aOffererIdentifier));
    maOffererIdentifier = OUStringToOString( aOffererIdentifier, RTL_TEXTENCODING_UTF8);

    rtl::OUString aAccepterIdentifier;
    CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini",
        maTestConfig.getFrom("accepter", aAccepterIdentifier));
    maAccepterIdentifier = OUStringToOString( aAccepterIdentifier, RTL_TEXTENCODING_UTF8);

    mpMainLoop = g_main_loop_new (NULL, FALSE);
    g_timeout_add_seconds (10, timed_out, mpMainLoop);
}

TestTeleTubes::~TestTeleTubes()
{
    g_main_loop_unref( mpMainLoop);
    mpMainLoop = NULL;
}

static void TeleTestTubes_ContactListPrepared( GError *errorOr0, void *user_data )
{
    TestTeleTubes *self = reinterpret_cast<TestTeleTubes *>(user_data);

    CPPUNIT_ASSERT( errorOr0 == 0 );

    g_main_loop_quit (self->mpMainLoop);
}

void TestTeleTubes::spinMainLoop()
{
    g_main_loop_run( mpMainLoop);
}

void TestTeleTubes::testContactList()
{
    ContactList cl;
    cl.prepare( TeleTestTubes_ContactListPrepared, this );
    spinMainLoop();

    /* Okay, now everything's prepared, we can get contacts synchronously. */
    AccountContactPairV pairs;

    pairs = cl.getContacts();
    guint i;

    /* FIXME: this is racy, because we can't be 100% sure that MC has finished
     * discovering what we support and passing that on to the connection
     * manager...
     */

    /* Both our accounts are meant to be signed in, and they both should be
     * capable of LibreOffice tubes because this test runs after we register
     * our handler. */
    CPPUNIT_ASSERT_MESSAGE(
        "Make sure both your test accounts are signed in "
        "and are on each other's contact lists",
        pairs.size() > 0 );
    CPPUNIT_ASSERT(!mpAccepterContact);

    for (i = 0; i < pairs.size(); i++)
    {
        AccountContactPair pair = pairs[i];

        /* FIXME: verify that pair.first is the offerer account */
        if (tp_contact_get_identifier(pair.second) == maAccepterIdentifier) {
            mpAccepterContact = pair.second;
            g_object_ref(mpAccepterContact);
        }
        g_object_unref (pair.first);
        g_object_unref (pair.second);
    }

    CPPUNIT_ASSERT_MESSAGE(
        "Couldn't find accepter contact. "
        "Make sure both your test accounts are signed in "
        "and are on each other's contact lists",
        mpAccepterContact);
}

void TestTeleTubes::testSetupManager1()
{
    mpManager1 = new TeleManager( true);
}

void TestTeleTubes::testSetupManager2()
{
    mpManager2 = new TeleManager;
}

void TestTeleTubes::testPrepareAccountManager1()
{
    mpManager1->prepareAccountManager();
    TeleManager::AccountManagerStatus eStatus = mpManager1->getAccountManagerStatus();
    CPPUNIT_ASSERT( eStatus == TeleManager::AMS_PREPARED);
}

void TestTeleTubes::testPrepareAccountManager2()
{
    mpManager2->prepareAccountManager();
    TeleManager::AccountManagerStatus eStatus = mpManager2->getAccountManagerStatus();
    CPPUNIT_ASSERT( eStatus == TeleManager::AMS_PREPARED);
}

void TestTeleTubes::testStartBuddySession1()
{
    TpAccount *pAcc1 = mpManager1->getAccount(maOffererIdentifier);
    CPPUNIT_ASSERT( pAcc1 != 0);
    /* This has to run after testContactList has run successfully. */
    CPPUNIT_ASSERT( mpAccepterContact != 0);
    bool bStarted = mpManager1->startBuddySession( pAcc1, mpAccepterContact);
    CPPUNIT_ASSERT( bStarted == true);
}

void TestTeleTubes::testStartBuddySession2()
{
    //bool bStarted = mpManager2->startBuddySession( sAcc2, sAcc1);
    //CPPUNIT_ASSERT( bStarted == true);
}

void TestTeleTubes::testConnect1()
{
    bool bConnected = mpManager1->connect();
    CPPUNIT_ASSERT( bConnected == true);
}

void TestTeleTubes::testConnect2()
{
    bool bConnected = mpManager2->connect();
    CPPUNIT_ASSERT( bConnected == true);
}

void TestTeleTubes::testSendPacket()
{
    TelePacket aPacket( "", RTL_CONSTASCII_STRINGPARAM( "from 1 to 2"));
    nSentPackets = mpManager1->sendPacket( aPacket);
    CPPUNIT_ASSERT( nSentPackets == 2); // expect out+in conference, as own instance accepted self
}

void TestTeleTubes::testReceivePacket()
{
    TelePacket aPacket( "", RTL_CONSTASCII_STRINGPARAM( "from 1 to 2"));
    TelePacket aReceived;
    sal_uInt32 nReceivedPackets = 0;
    bool bOk;
    do
    {
        do
        {
            bOk = mpManager1->popPacket( aReceived);
            if (bOk)
            {
                ++nReceivedPackets;
                CPPUNIT_ASSERT( aPacket == aReceived);
            }
        } while (bOk);
        if (nReceivedPackets < nSentPackets)
            mpManager1->iterateLoop();
    } while (nReceivedPackets < nSentPackets);
    CPPUNIT_ASSERT( nReceivedPackets == nSentPackets);
}

void TestTeleTubes::testFlushLoops()
{
    mpManager1->flushLoop();
    mpManager2->flushLoop();
}

void TestTeleTubes::testDestroyManager1()
{
    delete mpManager1;
    mpManager1 = NULL;
}

void TestTeleTubes::testDestroyManager2()
{
    delete mpManager2;
    mpManager2 = NULL;
}

void TestTeleTubes::testDestroyAccepterContact()
{
    if (mpAccepterContact) {
        g_object_unref(mpAccepterContact);
        mpAccepterContact = NULL;
    }
}

void TestTeleTubes::testFailAlways()
{
    CPPUNIT_ASSERT( false);
}

CPPUNIT_TEST_SUITE_REGISTRATION( TestTeleTubes);

}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#ifndef CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_
#define CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_

#include "errors.hpp"
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <boost/uuid/uuid.hpp>

#include "containers/archive/archive.hpp"

inline
write_message_t &operator<<(UNUSED write_message_t &msg, UNUSED boost::detail::variant::void_ &v) {
    unreachable("You cannot do operator<<(write_message_t &, boost::detail::variant::void_ &).");
}

inline
int deserialize(UNUSED read_stream_t *s, UNUSED boost::detail::variant::void_ *v) {
    unreachable("You cannot do deserialize(read_stream_t *, boost::detail::variant::void_ *).");
}

#define ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(i)     \
    void operator()(const T##i &x) {                    \
        uint8_t n = i;                                  \
        *(this->msg) << n;                              \
        *(this->msg) << x;                              \
    }

#define ARCHIVE_VARIANT_SERIALIZE_USING_DECL(i) \
    using v_##i##_t<ARCHIVE_TL##i>::operator()

namespace archive_nonsense {

template <class T20> struct v_20_t : public boost::static_visitor<void> {
    v_20_t() : msg(NULL) { }
    write_message_t *msg;

    ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(20);
private:
    DISABLE_COPYING(v_20_t);
};

#define ARCHIVE_CLASS_DECL(i, j) template <ARCHIVE_CL##i> struct v_##i##_t : public v_##j##_t<ARCHIVE_TL##j> { ARCHIVE_VARIANT_SERIALIZE_USING_DECL(j); ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(i); }

#define ARCHIVE_CL19 class T19, class T20
#define ARCHIVE_TL20 T20
ARCHIVE_CLASS_DECL(19, 20);
#define ARCHIVE_CL18 class T18, ARCHIVE_CL19
#define ARCHIVE_TL19 T19, ARCHIVE_TL20
ARCHIVE_CLASS_DECL(18, 19);
#define ARCHIVE_CL17 class T17, ARCHIVE_CL18
#define ARCHIVE_TL18 T18, ARCHIVE_TL19
ARCHIVE_CLASS_DECL(17, 18);
#define ARCHIVE_CL16 class T16, ARCHIVE_CL17
#define ARCHIVE_TL17 T17, ARCHIVE_TL18
ARCHIVE_CLASS_DECL(16, 17);
#define ARCHIVE_CL15 class T15, ARCHIVE_CL16
#define ARCHIVE_TL16 T16, ARCHIVE_TL17
ARCHIVE_CLASS_DECL(15, 16);
#define ARCHIVE_CL14 class T14, ARCHIVE_CL15
#define ARCHIVE_TL15 T15, ARCHIVE_TL16
ARCHIVE_CLASS_DECL(14, 15);
#define ARCHIVE_CL13 class T13, ARCHIVE_CL14
#define ARCHIVE_TL14 T14, ARCHIVE_TL15
ARCHIVE_CLASS_DECL(13, 14);
#define ARCHIVE_CL12 class T12, ARCHIVE_CL13
#define ARCHIVE_TL13 T13, ARCHIVE_TL14
ARCHIVE_CLASS_DECL(12, 13);
#define ARCHIVE_CL11 class T11, ARCHIVE_CL12
#define ARCHIVE_TL12 T12, ARCHIVE_TL13
ARCHIVE_CLASS_DECL(11, 12);
#define ARCHIVE_CL10 class T10, ARCHIVE_CL11
#define ARCHIVE_TL11 T11, ARCHIVE_TL12
ARCHIVE_CLASS_DECL(10, 11);
#define ARCHIVE_CL9 class T9, ARCHIVE_CL10
#define ARCHIVE_TL10 T10, ARCHIVE_TL11
ARCHIVE_CLASS_DECL(9, 10);
#define ARCHIVE_CL8 class T8, ARCHIVE_CL9
#define ARCHIVE_TL9 T9, ARCHIVE_TL10
ARCHIVE_CLASS_DECL(8, 9);
#define ARCHIVE_CL7 class T7, ARCHIVE_CL8
#define ARCHIVE_TL8 T8, ARCHIVE_TL9
ARCHIVE_CLASS_DECL(7, 8);
#define ARCHIVE_CL6 class T6, ARCHIVE_CL7
#define ARCHIVE_TL7 T7, ARCHIVE_TL8
ARCHIVE_CLASS_DECL(6, 7);
#define ARCHIVE_CL5 class T5, ARCHIVE_CL6
#define ARCHIVE_TL6 T6, ARCHIVE_TL7
ARCHIVE_CLASS_DECL(5, 6);
#define ARCHIVE_CL4 class T4, ARCHIVE_CL5
#define ARCHIVE_TL5 T5, ARCHIVE_TL6
ARCHIVE_CLASS_DECL(4, 5);
#define ARCHIVE_CL3 class T3, ARCHIVE_CL4
#define ARCHIVE_TL4 T4, ARCHIVE_TL5
ARCHIVE_CLASS_DECL(3, 4);
#define ARCHIVE_CL2 class T2, ARCHIVE_CL3
#define ARCHIVE_TL3 T3, ARCHIVE_TL4
ARCHIVE_CLASS_DECL(2, 3);
#define ARCHIVE_CL1 class T1, ARCHIVE_CL2
#define ARCHIVE_TL2 T2, ARCHIVE_TL3
ARCHIVE_CLASS_DECL(1, 2);

}  // namespace archive_nonsense

template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
write_message_t &operator<<(write_message_t &msg, const boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> &x) {
    archive_nonsense::v_1_t<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> visitor;
    rassert(sizeof(visitor) == sizeof(write_message_t *));

    visitor.msg = &msg;

    boost::apply_visitor(visitor, x);

    return msg;
}

template <class T> struct archive_variant_deserialize_standin_t {
    template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
    int do_the_deserialization(read_stream_t *s, boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
        T v;
        int res = deserialize(s, &v);
        if (res) { return res; }
        *x = v;
    }
 };

template <> struct archive_variant_deserialize_standin_t<boost::detail::variant::void_> {
    template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
    int do_the_deserialization(UNUSED read_stream_t *s, UNUSED boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
        return -3;
    }
};

template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
int deserialize(read_stream_t *s, boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
    uint8_t n;
    int res = deserialize(s, &n);
    if (res) { return res; }
    if (!(1 <= n && n <= 20)) {
        return -3;
    }

#define ARCHIVE_DESERIALIZE_CASE(i) case i: { archive_variant_deserialize_standin_t<T##i> st; return st.do_the_deserialization(s, x); }

    switch (n) {
    case 1: { archive_variant_deserialize_standin_t<T1> st; return st.do_the_deserialization(s, x); }
    case 2: { archive_variant_deserialize_standin_t<T2> st; return st.do_the_deserialization(s, x); }
    case 3: { archive_variant_deserialize_standin_t<T3> st; return st.do_the_deserialization(s, x); }
    case 4: { archive_variant_deserialize_standin_t<T4> st; return st.do_the_deserialization(s, x); }
    case 5: { archive_variant_deserialize_standin_t<T5> st; return st.do_the_deserialization(s, x); }
    case 6: { archive_variant_deserialize_standin_t<T6> st; return st.do_the_deserialization(s, x); }
    case 7: { archive_variant_deserialize_standin_t<T7> st; return st.do_the_deserialization(s, x); }
    case 8: { archive_variant_deserialize_standin_t<T8> st; return st.do_the_deserialization(s, x); }
    case 9: { archive_variant_deserialize_standin_t<T9> st; return st.do_the_deserialization(s, x); }
    case 10: { archive_variant_deserialize_standin_t<T10> st; return st.do_the_deserialization(s, x); }
    case 11: { archive_variant_deserialize_standin_t<T11> st; return st.do_the_deserialization(s, x); }
    case 12: { archive_variant_deserialize_standin_t<T12> st; return st.do_the_deserialization(s, x); }
    case 13: { archive_variant_deserialize_standin_t<T13> st; return st.do_the_deserialization(s, x); }
    case 14: { archive_variant_deserialize_standin_t<T14> st; return st.do_the_deserialization(s, x); }
    case 15: { archive_variant_deserialize_standin_t<T15> st; return st.do_the_deserialization(s, x); }
    case 16: { archive_variant_deserialize_standin_t<T16> st; return st.do_the_deserialization(s, x); }
    case 17: { archive_variant_deserialize_standin_t<T17> st; return st.do_the_deserialization(s, x); }
    case 18: { archive_variant_deserialize_standin_t<T18> st; return st.do_the_deserialization(s, x); }
    case 19: { archive_variant_deserialize_standin_t<T19> st; return st.do_the_deserialization(s, x); }
    case 20: { archive_variant_deserialize_standin_t<T20> st; return st.do_the_deserialization(s, x); }

    default:
        unreachable("impossible to reach, we already returned -3");
    }

    unreachable("impossible to reach, we return from every case of the switch statement");
}

inline write_message_t &operator<<(write_message_t &msg, const boost::uuids::uuid &uuid) {
    msg.append(uuid.data, boost::uuids::uuid::static_size());
    return msg;
}

inline int deserialize(read_stream_t *s, boost::uuids::uuid *uuid) {
    int64_t sz = boost::uuids::uuid::static_size();
    int64_t res = force_read(s, uuid->data, sz);

    if (res == -1) { return -1; }
    if (res < sz) { return -2; }
    rassert(res == sz);
    return 0;
}

template <class T>
write_message_t &operator<<(write_message_t &msg, const boost::optional<T> &x) {
    const T *ptr = x.get_ptr();
    bool exists = ptr;
    msg << exists;
    if (exists) {
        msg << *ptr;
    }
    return msg;
}

template <class T>
int deserialize(read_stream_t *s, boost::optional<T> *x) {
    bool exists;
    rassert(!x->get_ptr());

    int res = deserialize(s, &exists);
    if (res) { return res; }
    if (exists) {
        x->reset(T());
        res = deserialize(s, x->get_ptr());
        return res;
    } else {
        x->reset();
        return 0;
    }
}

#endif  // CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_
<commit_msg>Removed an unused macro in boost_types.hpp.<commit_after>#ifndef CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_
#define CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_

#include "errors.hpp"
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <boost/uuid/uuid.hpp>

#include "containers/archive/archive.hpp"

inline
write_message_t &operator<<(UNUSED write_message_t &msg, UNUSED boost::detail::variant::void_ &v) {
    unreachable("You cannot do operator<<(write_message_t &, boost::detail::variant::void_ &).");
}

inline
int deserialize(UNUSED read_stream_t *s, UNUSED boost::detail::variant::void_ *v) {
    unreachable("You cannot do deserialize(read_stream_t *, boost::detail::variant::void_ *).");
}

#define ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(i)     \
    void operator()(const T##i &x) {                    \
        uint8_t n = i;                                  \
        *(this->msg) << n;                              \
        *(this->msg) << x;                              \
    }

#define ARCHIVE_VARIANT_SERIALIZE_USING_DECL(i) \
    using v_##i##_t<ARCHIVE_TL##i>::operator()

namespace archive_nonsense {

template <class T20> struct v_20_t : public boost::static_visitor<void> {
    v_20_t() : msg(NULL) { }
    write_message_t *msg;

    ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(20);
private:
    DISABLE_COPYING(v_20_t);
};

#define ARCHIVE_CLASS_DECL(i, j) template <ARCHIVE_CL##i> struct v_##i##_t : public v_##j##_t<ARCHIVE_TL##j> { ARCHIVE_VARIANT_SERIALIZE_USING_DECL(j); ARCHIVE_VARIANT_SERIALIZE_VISITOR_METHOD(i); }

#define ARCHIVE_CL19 class T19, class T20
#define ARCHIVE_TL20 T20
ARCHIVE_CLASS_DECL(19, 20);
#define ARCHIVE_CL18 class T18, ARCHIVE_CL19
#define ARCHIVE_TL19 T19, ARCHIVE_TL20
ARCHIVE_CLASS_DECL(18, 19);
#define ARCHIVE_CL17 class T17, ARCHIVE_CL18
#define ARCHIVE_TL18 T18, ARCHIVE_TL19
ARCHIVE_CLASS_DECL(17, 18);
#define ARCHIVE_CL16 class T16, ARCHIVE_CL17
#define ARCHIVE_TL17 T17, ARCHIVE_TL18
ARCHIVE_CLASS_DECL(16, 17);
#define ARCHIVE_CL15 class T15, ARCHIVE_CL16
#define ARCHIVE_TL16 T16, ARCHIVE_TL17
ARCHIVE_CLASS_DECL(15, 16);
#define ARCHIVE_CL14 class T14, ARCHIVE_CL15
#define ARCHIVE_TL15 T15, ARCHIVE_TL16
ARCHIVE_CLASS_DECL(14, 15);
#define ARCHIVE_CL13 class T13, ARCHIVE_CL14
#define ARCHIVE_TL14 T14, ARCHIVE_TL15
ARCHIVE_CLASS_DECL(13, 14);
#define ARCHIVE_CL12 class T12, ARCHIVE_CL13
#define ARCHIVE_TL13 T13, ARCHIVE_TL14
ARCHIVE_CLASS_DECL(12, 13);
#define ARCHIVE_CL11 class T11, ARCHIVE_CL12
#define ARCHIVE_TL12 T12, ARCHIVE_TL13
ARCHIVE_CLASS_DECL(11, 12);
#define ARCHIVE_CL10 class T10, ARCHIVE_CL11
#define ARCHIVE_TL11 T11, ARCHIVE_TL12
ARCHIVE_CLASS_DECL(10, 11);
#define ARCHIVE_CL9 class T9, ARCHIVE_CL10
#define ARCHIVE_TL10 T10, ARCHIVE_TL11
ARCHIVE_CLASS_DECL(9, 10);
#define ARCHIVE_CL8 class T8, ARCHIVE_CL9
#define ARCHIVE_TL9 T9, ARCHIVE_TL10
ARCHIVE_CLASS_DECL(8, 9);
#define ARCHIVE_CL7 class T7, ARCHIVE_CL8
#define ARCHIVE_TL8 T8, ARCHIVE_TL9
ARCHIVE_CLASS_DECL(7, 8);
#define ARCHIVE_CL6 class T6, ARCHIVE_CL7
#define ARCHIVE_TL7 T7, ARCHIVE_TL8
ARCHIVE_CLASS_DECL(6, 7);
#define ARCHIVE_CL5 class T5, ARCHIVE_CL6
#define ARCHIVE_TL6 T6, ARCHIVE_TL7
ARCHIVE_CLASS_DECL(5, 6);
#define ARCHIVE_CL4 class T4, ARCHIVE_CL5
#define ARCHIVE_TL5 T5, ARCHIVE_TL6
ARCHIVE_CLASS_DECL(4, 5);
#define ARCHIVE_CL3 class T3, ARCHIVE_CL4
#define ARCHIVE_TL4 T4, ARCHIVE_TL5
ARCHIVE_CLASS_DECL(3, 4);
#define ARCHIVE_CL2 class T2, ARCHIVE_CL3
#define ARCHIVE_TL3 T3, ARCHIVE_TL4
ARCHIVE_CLASS_DECL(2, 3);
#define ARCHIVE_CL1 class T1, ARCHIVE_CL2
#define ARCHIVE_TL2 T2, ARCHIVE_TL3
ARCHIVE_CLASS_DECL(1, 2);

}  // namespace archive_nonsense

template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
write_message_t &operator<<(write_message_t &msg, const boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> &x) {
    archive_nonsense::v_1_t<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> visitor;
    rassert(sizeof(visitor) == sizeof(write_message_t *));

    visitor.msg = &msg;

    boost::apply_visitor(visitor, x);

    return msg;
}

template <class T> struct archive_variant_deserialize_standin_t {
    template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
    int do_the_deserialization(read_stream_t *s, boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
        T v;
        int res = deserialize(s, &v);
        if (res) { return res; }
        *x = v;
    }
 };

template <> struct archive_variant_deserialize_standin_t<boost::detail::variant::void_> {
    template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
    int do_the_deserialization(UNUSED read_stream_t *s, UNUSED boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
        return -3;
    }
};

template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19, class T20>
int deserialize(read_stream_t *s, boost::variant<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> *x) {
    uint8_t n;
    int res = deserialize(s, &n);
    if (res) { return res; }
    if (!(1 <= n && n <= 20)) {
        return -3;
    }

    switch (n) {
    case 1: { archive_variant_deserialize_standin_t<T1> st; return st.do_the_deserialization(s, x); }
    case 2: { archive_variant_deserialize_standin_t<T2> st; return st.do_the_deserialization(s, x); }
    case 3: { archive_variant_deserialize_standin_t<T3> st; return st.do_the_deserialization(s, x); }
    case 4: { archive_variant_deserialize_standin_t<T4> st; return st.do_the_deserialization(s, x); }
    case 5: { archive_variant_deserialize_standin_t<T5> st; return st.do_the_deserialization(s, x); }
    case 6: { archive_variant_deserialize_standin_t<T6> st; return st.do_the_deserialization(s, x); }
    case 7: { archive_variant_deserialize_standin_t<T7> st; return st.do_the_deserialization(s, x); }
    case 8: { archive_variant_deserialize_standin_t<T8> st; return st.do_the_deserialization(s, x); }
    case 9: { archive_variant_deserialize_standin_t<T9> st; return st.do_the_deserialization(s, x); }
    case 10: { archive_variant_deserialize_standin_t<T10> st; return st.do_the_deserialization(s, x); }
    case 11: { archive_variant_deserialize_standin_t<T11> st; return st.do_the_deserialization(s, x); }
    case 12: { archive_variant_deserialize_standin_t<T12> st; return st.do_the_deserialization(s, x); }
    case 13: { archive_variant_deserialize_standin_t<T13> st; return st.do_the_deserialization(s, x); }
    case 14: { archive_variant_deserialize_standin_t<T14> st; return st.do_the_deserialization(s, x); }
    case 15: { archive_variant_deserialize_standin_t<T15> st; return st.do_the_deserialization(s, x); }
    case 16: { archive_variant_deserialize_standin_t<T16> st; return st.do_the_deserialization(s, x); }
    case 17: { archive_variant_deserialize_standin_t<T17> st; return st.do_the_deserialization(s, x); }
    case 18: { archive_variant_deserialize_standin_t<T18> st; return st.do_the_deserialization(s, x); }
    case 19: { archive_variant_deserialize_standin_t<T19> st; return st.do_the_deserialization(s, x); }
    case 20: { archive_variant_deserialize_standin_t<T20> st; return st.do_the_deserialization(s, x); }

    default:
        unreachable("impossible to reach, we already returned -3");
    }

    unreachable("impossible to reach, we return from every case of the switch statement");
}

inline write_message_t &operator<<(write_message_t &msg, const boost::uuids::uuid &uuid) {
    msg.append(uuid.data, boost::uuids::uuid::static_size());
    return msg;
}

inline int deserialize(read_stream_t *s, boost::uuids::uuid *uuid) {
    int64_t sz = boost::uuids::uuid::static_size();
    int64_t res = force_read(s, uuid->data, sz);

    if (res == -1) { return -1; }
    if (res < sz) { return -2; }
    rassert(res == sz);
    return 0;
}

template <class T>
write_message_t &operator<<(write_message_t &msg, const boost::optional<T> &x) {
    const T *ptr = x.get_ptr();
    bool exists = ptr;
    msg << exists;
    if (exists) {
        msg << *ptr;
    }
    return msg;
}

template <class T>
int deserialize(read_stream_t *s, boost::optional<T> *x) {
    bool exists;
    rassert(!x->get_ptr());

    int res = deserialize(s, &exists);
    if (res) { return res; }
    if (exists) {
        x->reset(T());
        res = deserialize(s, x->get_ptr());
        return res;
    } else {
        x->reset();
        return 0;
    }
}

#endif  // CONTAINERS_ARCHIVE_BOOST_TYPES_HPP_
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     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 <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"

#ifdef GRPC_POSIX_SOCKET_TCP_CLIENT

#include "src/core/lib/iomgr/tcp_client_posix.h"

#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_mutator.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/slice/slice_internal.h"

extern grpc_core::TraceFlag grpc_tcp_trace;

typedef struct {
  gpr_mu mu;
  grpc_fd* fd;
  grpc_timer alarm;
  grpc_closure on_alarm;
  int refs;
  grpc_closure write_closure;
  grpc_pollset_set* interested_parties;
  char* addr_str;
  grpc_endpoint** ep;
  grpc_closure* closure;
  grpc_channel_args* channel_args;
} async_connect;

static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
                                  const grpc_channel_args* channel_args) {
  grpc_error* err = GRPC_ERROR_NONE;

  GPR_ASSERT(fd >= 0);

  err = grpc_set_socket_nonblocking(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  err = grpc_set_socket_cloexec(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  if (!grpc_is_unix_socket(addr)) {
    err = grpc_set_socket_low_latency(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
    err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
                                           true /* is_client */);
    if (err != GRPC_ERROR_NONE) goto error;
  }
  err = grpc_set_socket_no_sigpipe_if_possible(fd);
  if (err != GRPC_ERROR_NONE) goto error;
  if (channel_args) {
    for (size_t i = 0; i < channel_args->num_args; i++) {
      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_SOCKET_MUTATOR)) {
        GPR_ASSERT(channel_args->args[i].type == GRPC_ARG_POINTER);
        grpc_socket_mutator* mutator = static_cast<grpc_socket_mutator*>(
            channel_args->args[i].value.pointer.p);
        err = grpc_set_socket_with_mutator(fd, mutator);
        if (err != GRPC_ERROR_NONE) goto error;
      }
    }
  }
  goto done;

error:
  if (fd >= 0) {
    close(fd);
  }
done:
  return err;
}

static void tc_on_alarm(void* acp, grpc_error* error) {
  int done;
  async_connect* ac = static_cast<async_connect*>(acp);
  if (grpc_tcp_trace.enabled()) {
    const char* str = grpc_error_string(error);
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
            str);
  }
  gpr_mu_lock(&ac->mu);
  if (ac->fd != nullptr) {
    grpc_fd_shutdown(
        ac->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("connect() timed out"));
  }
  done = (--ac->refs == 0);
  gpr_mu_unlock(&ac->mu);
  if (done) {
    gpr_mu_destroy(&ac->mu);
    gpr_free(ac->addr_str);
    grpc_channel_args_destroy(ac->channel_args);
    gpr_free(ac);
  }
}

grpc_endpoint* grpc_tcp_client_create_from_fd(
    grpc_fd* fd, const grpc_channel_args* channel_args, const char* addr_str) {
  return grpc_tcp_create(fd, channel_args, addr_str);
}

static void on_writable(void* acp, grpc_error* error) {
  async_connect* ac = static_cast<async_connect*>(acp);
  int so_error = 0;
  socklen_t so_error_size;
  int err;
  int done;
  grpc_endpoint** ep = ac->ep;
  grpc_closure* closure = ac->closure;
  grpc_fd* fd;

  GRPC_ERROR_REF(error);

  if (grpc_tcp_trace.enabled()) {
    const char* str = grpc_error_string(error);
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_writable: error=%s", ac->addr_str,
            str);
  }

  gpr_mu_lock(&ac->mu);
  GPR_ASSERT(ac->fd);
  fd = ac->fd;
  ac->fd = nullptr;
  gpr_mu_unlock(&ac->mu);

  grpc_timer_cancel(&ac->alarm);

  gpr_mu_lock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    error =
        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
                           grpc_slice_from_static_string("Timeout occurred"));
    goto finish;
  }

  do {
    so_error_size = sizeof(so_error);
    err = getsockopt(grpc_fd_wrapped_fd(fd), SOL_SOCKET, SO_ERROR, &so_error,
                     &so_error_size);
  } while (err < 0 && errno == EINTR);
  if (err < 0) {
    error = GRPC_OS_ERROR(errno, "getsockopt");
    goto finish;
  }

  switch (so_error) {
    case 0:
      grpc_pollset_set_del_fd(ac->interested_parties, fd);
      *ep = grpc_tcp_client_create_from_fd(fd, ac->channel_args, ac->addr_str);
      fd = nullptr;
      break;
    case ENOBUFS:
      /* We will get one of these errors if we have run out of
         memory in the kernel for the data structures allocated
         when you connect a socket.  If this happens it is very
         likely that if we wait a little bit then try again the
         connection will work (since other programs or this
         program will close their network connections and free up
         memory).  This does _not_ indicate that there is anything
         wrong with the server we are connecting to, this is a
         local problem.

         If you are looking at this code, then chances are that
         your program or another program on the same computer
         opened too many network connections.  The "easy" fix:
         don't do that! */
      gpr_log(GPR_ERROR, "kernel out of buffers");
      gpr_mu_unlock(&ac->mu);
      grpc_fd_notify_on_write(fd, &ac->write_closure);
      return;
    case ECONNREFUSED:
      /* This error shouldn't happen for anything other than connect(). */
      error = GRPC_OS_ERROR(so_error, "connect");
      break;
    default:
      /* We don't really know which syscall triggered the problem here,
         so punt by reporting getsockopt(). */
      error = GRPC_OS_ERROR(so_error, "getsockopt(SO_ERROR)");
      break;
  }

finish:
  if (fd != nullptr) {
    grpc_pollset_set_del_fd(ac->interested_parties, fd);
    grpc_fd_orphan(fd, nullptr, nullptr, "tcp_client_orphan");
    fd = nullptr;
  }
  done = (--ac->refs == 0);
  // Create a copy of the data from "ac" to be accessed after the unlock, as
  // "ac" and its contents may be deallocated by the time they are read.
  const grpc_slice addr_str_slice = grpc_slice_from_copied_string(ac->addr_str);
  gpr_mu_unlock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    char* error_descr;
    grpc_slice str;
    bool ret = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &str);
    GPR_ASSERT(ret);
    char* desc = grpc_slice_to_c_string(str);
    gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION,
                               grpc_slice_from_copied_string(error_descr));
    gpr_free(error_descr);
    gpr_free(desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
                               addr_str_slice /* takes ownership */);
  } else {
    grpc_slice_unref_internal(addr_str_slice);
  }
  if (done) {
    // This is safe even outside the lock, because "done", the sentinel, is
    // populated *inside* the lock.
    gpr_mu_destroy(&ac->mu);
    gpr_free(ac->addr_str);
    grpc_channel_args_destroy(ac->channel_args);
    gpr_free(ac);
  }
  GRPC_CLOSURE_SCHED(closure, error);
}

grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
                                       const grpc_resolved_address* addr,
                                       grpc_resolved_address* mapped_addr,
                                       grpc_fd** fdobj) {
  grpc_dualstack_mode dsmode;
  int fd;
  grpc_error* error;
  char* name;
  char* addr_str;
  *fdobj = nullptr;
  /* Use dualstack sockets where available. Set mapped to v6 or v4 mapped to
     v6. */
  if (!grpc_sockaddr_to_v4mapped(addr, mapped_addr)) {
    /* addr is v4 mapped to v6 or v6. */
    memcpy(mapped_addr, addr, sizeof(*mapped_addr));
  }
  error =
      grpc_create_dualstack_socket(mapped_addr, SOCK_STREAM, 0, &dsmode, &fd);
  if (error != GRPC_ERROR_NONE) {
    return error;
  }
  if (dsmode == GRPC_DSMODE_IPV4) {
    /* Original addr is either v4 or v4 mapped to v6. Set mapped_addr to v4. */
    if (!grpc_sockaddr_is_v4mapped(addr, mapped_addr)) {
      memcpy(mapped_addr, addr, sizeof(*mapped_addr));
    }
  }
  if ((error = prepare_socket(mapped_addr, fd, channel_args)) !=
      GRPC_ERROR_NONE) {
    return error;
  }
  addr_str = grpc_sockaddr_to_uri(mapped_addr);
  gpr_asprintf(&name, "tcp-client:%s", addr_str);
  *fdobj = grpc_fd_create(fd, name, true);
  gpr_free(name);
  gpr_free(addr_str);
  return GRPC_ERROR_NONE;
}

void grpc_tcp_client_create_from_prepared_fd(
    grpc_pollset_set* interested_parties, grpc_closure* closure, grpc_fd* fdobj,
    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
    grpc_millis deadline, grpc_endpoint** ep) {
  const int fd = grpc_fd_wrapped_fd(fdobj);
  int err;
  async_connect* ac;
  do {
    err = connect(fd, reinterpret_cast<const grpc_sockaddr*>(addr->addr),
                  addr->len);
  } while (err < 0 && errno == EINTR);
  if (err >= 0) {
    char* addr_str = grpc_sockaddr_to_uri(addr);
    *ep = grpc_tcp_client_create_from_fd(fdobj, channel_args, addr_str);
    gpr_free(addr_str);
    GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
    return;
  }
  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
    grpc_fd_orphan(fdobj, nullptr, nullptr, "tcp_client_connect_error");
    GRPC_CLOSURE_SCHED(closure, GRPC_OS_ERROR(errno, "connect"));
    return;
  }

  grpc_pollset_set_add_fd(interested_parties, fdobj);

  ac = static_cast<async_connect*>(gpr_malloc(sizeof(async_connect)));
  ac->closure = closure;
  ac->ep = ep;
  ac->fd = fdobj;
  ac->interested_parties = interested_parties;
  ac->addr_str = grpc_sockaddr_to_uri(addr);
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  GRPC_CLOSURE_INIT(&ac->write_closure, on_writable, ac,
                    grpc_schedule_on_exec_ctx);
  ac->channel_args = grpc_channel_args_copy(channel_args);

  if (grpc_tcp_trace.enabled()) {
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: asynchronously connecting fd %p",
            ac->addr_str, fdobj);
  }

  gpr_mu_lock(&ac->mu);
  GRPC_CLOSURE_INIT(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
  grpc_timer_init(&ac->alarm, deadline, &ac->on_alarm);
  grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
  gpr_mu_unlock(&ac->mu);
}

static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
                        grpc_pollset_set* interested_parties,
                        const grpc_channel_args* channel_args,
                        const grpc_resolved_address* addr,
                        grpc_millis deadline) {
  grpc_resolved_address mapped_addr;
  grpc_fd* fdobj = nullptr;
  grpc_error* error;
  *ep = nullptr;
  if ((error = grpc_tcp_client_prepare_fd(channel_args, addr, &mapped_addr,
                                          &fdobj)) != GRPC_ERROR_NONE) {
    GRPC_CLOSURE_SCHED(closure, error);
    return;
  }
  grpc_tcp_client_create_from_prepared_fd(interested_parties, closure, fdobj,
                                          channel_args, &mapped_addr, deadline,
                                          ep);
}

grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {tcp_connect};
#endif
<commit_msg>Enable SO_REUSEADDR in client sockets<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     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 <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"

#ifdef GRPC_POSIX_SOCKET_TCP_CLIENT

#include "src/core/lib/iomgr/tcp_client_posix.h"

#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_mutator.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/slice/slice_internal.h"

extern grpc_core::TraceFlag grpc_tcp_trace;

typedef struct {
  gpr_mu mu;
  grpc_fd* fd;
  grpc_timer alarm;
  grpc_closure on_alarm;
  int refs;
  grpc_closure write_closure;
  grpc_pollset_set* interested_parties;
  char* addr_str;
  grpc_endpoint** ep;
  grpc_closure* closure;
  grpc_channel_args* channel_args;
} async_connect;

static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
                                  const grpc_channel_args* channel_args) {
  grpc_error* err = GRPC_ERROR_NONE;

  GPR_ASSERT(fd >= 0);

  err = grpc_set_socket_nonblocking(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  err = grpc_set_socket_cloexec(fd, 1);
  if (err != GRPC_ERROR_NONE) goto error;
  if (!grpc_is_unix_socket(addr)) {
    err = grpc_set_socket_low_latency(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
    err = grpc_set_socket_reuse_addr(fd, 1);
    if (err != GRPC_ERROR_NONE) goto error;
    err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
                                           true /* is_client */);
    if (err != GRPC_ERROR_NONE) goto error;
  }
  err = grpc_set_socket_no_sigpipe_if_possible(fd);
  if (err != GRPC_ERROR_NONE) goto error;
  if (channel_args) {
    for (size_t i = 0; i < channel_args->num_args; i++) {
      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_SOCKET_MUTATOR)) {
        GPR_ASSERT(channel_args->args[i].type == GRPC_ARG_POINTER);
        grpc_socket_mutator* mutator = static_cast<grpc_socket_mutator*>(
            channel_args->args[i].value.pointer.p);
        err = grpc_set_socket_with_mutator(fd, mutator);
        if (err != GRPC_ERROR_NONE) goto error;
      }
    }
  }
  goto done;

error:
  if (fd >= 0) {
    close(fd);
  }
done:
  return err;
}

static void tc_on_alarm(void* acp, grpc_error* error) {
  int done;
  async_connect* ac = static_cast<async_connect*>(acp);
  if (grpc_tcp_trace.enabled()) {
    const char* str = grpc_error_string(error);
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
            str);
  }
  gpr_mu_lock(&ac->mu);
  if (ac->fd != nullptr) {
    grpc_fd_shutdown(
        ac->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("connect() timed out"));
  }
  done = (--ac->refs == 0);
  gpr_mu_unlock(&ac->mu);
  if (done) {
    gpr_mu_destroy(&ac->mu);
    gpr_free(ac->addr_str);
    grpc_channel_args_destroy(ac->channel_args);
    gpr_free(ac);
  }
}

grpc_endpoint* grpc_tcp_client_create_from_fd(
    grpc_fd* fd, const grpc_channel_args* channel_args, const char* addr_str) {
  return grpc_tcp_create(fd, channel_args, addr_str);
}

static void on_writable(void* acp, grpc_error* error) {
  async_connect* ac = static_cast<async_connect*>(acp);
  int so_error = 0;
  socklen_t so_error_size;
  int err;
  int done;
  grpc_endpoint** ep = ac->ep;
  grpc_closure* closure = ac->closure;
  grpc_fd* fd;

  GRPC_ERROR_REF(error);

  if (grpc_tcp_trace.enabled()) {
    const char* str = grpc_error_string(error);
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_writable: error=%s", ac->addr_str,
            str);
  }

  gpr_mu_lock(&ac->mu);
  GPR_ASSERT(ac->fd);
  fd = ac->fd;
  ac->fd = nullptr;
  gpr_mu_unlock(&ac->mu);

  grpc_timer_cancel(&ac->alarm);

  gpr_mu_lock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    error =
        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
                           grpc_slice_from_static_string("Timeout occurred"));
    goto finish;
  }

  do {
    so_error_size = sizeof(so_error);
    err = getsockopt(grpc_fd_wrapped_fd(fd), SOL_SOCKET, SO_ERROR, &so_error,
                     &so_error_size);
  } while (err < 0 && errno == EINTR);
  if (err < 0) {
    error = GRPC_OS_ERROR(errno, "getsockopt");
    goto finish;
  }

  switch (so_error) {
    case 0:
      grpc_pollset_set_del_fd(ac->interested_parties, fd);
      *ep = grpc_tcp_client_create_from_fd(fd, ac->channel_args, ac->addr_str);
      fd = nullptr;
      break;
    case ENOBUFS:
      /* We will get one of these errors if we have run out of
         memory in the kernel for the data structures allocated
         when you connect a socket.  If this happens it is very
         likely that if we wait a little bit then try again the
         connection will work (since other programs or this
         program will close their network connections and free up
         memory).  This does _not_ indicate that there is anything
         wrong with the server we are connecting to, this is a
         local problem.

         If you are looking at this code, then chances are that
         your program or another program on the same computer
         opened too many network connections.  The "easy" fix:
         don't do that! */
      gpr_log(GPR_ERROR, "kernel out of buffers");
      gpr_mu_unlock(&ac->mu);
      grpc_fd_notify_on_write(fd, &ac->write_closure);
      return;
    case ECONNREFUSED:
      /* This error shouldn't happen for anything other than connect(). */
      error = GRPC_OS_ERROR(so_error, "connect");
      break;
    default:
      /* We don't really know which syscall triggered the problem here,
         so punt by reporting getsockopt(). */
      error = GRPC_OS_ERROR(so_error, "getsockopt(SO_ERROR)");
      break;
  }

finish:
  if (fd != nullptr) {
    grpc_pollset_set_del_fd(ac->interested_parties, fd);
    grpc_fd_orphan(fd, nullptr, nullptr, "tcp_client_orphan");
    fd = nullptr;
  }
  done = (--ac->refs == 0);
  // Create a copy of the data from "ac" to be accessed after the unlock, as
  // "ac" and its contents may be deallocated by the time they are read.
  const grpc_slice addr_str_slice = grpc_slice_from_copied_string(ac->addr_str);
  gpr_mu_unlock(&ac->mu);
  if (error != GRPC_ERROR_NONE) {
    char* error_descr;
    grpc_slice str;
    bool ret = grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &str);
    GPR_ASSERT(ret);
    char* desc = grpc_slice_to_c_string(str);
    gpr_asprintf(&error_descr, "Failed to connect to remote host: %s", desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION,
                               grpc_slice_from_copied_string(error_descr));
    gpr_free(error_descr);
    gpr_free(desc);
    error = grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
                               addr_str_slice /* takes ownership */);
  } else {
    grpc_slice_unref_internal(addr_str_slice);
  }
  if (done) {
    // This is safe even outside the lock, because "done", the sentinel, is
    // populated *inside* the lock.
    gpr_mu_destroy(&ac->mu);
    gpr_free(ac->addr_str);
    grpc_channel_args_destroy(ac->channel_args);
    gpr_free(ac);
  }
  GRPC_CLOSURE_SCHED(closure, error);
}

grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
                                       const grpc_resolved_address* addr,
                                       grpc_resolved_address* mapped_addr,
                                       grpc_fd** fdobj) {
  grpc_dualstack_mode dsmode;
  int fd;
  grpc_error* error;
  char* name;
  char* addr_str;
  *fdobj = nullptr;
  /* Use dualstack sockets where available. Set mapped to v6 or v4 mapped to
     v6. */
  if (!grpc_sockaddr_to_v4mapped(addr, mapped_addr)) {
    /* addr is v4 mapped to v6 or v6. */
    memcpy(mapped_addr, addr, sizeof(*mapped_addr));
  }
  error =
      grpc_create_dualstack_socket(mapped_addr, SOCK_STREAM, 0, &dsmode, &fd);
  if (error != GRPC_ERROR_NONE) {
    return error;
  }
  if (dsmode == GRPC_DSMODE_IPV4) {
    /* Original addr is either v4 or v4 mapped to v6. Set mapped_addr to v4. */
    if (!grpc_sockaddr_is_v4mapped(addr, mapped_addr)) {
      memcpy(mapped_addr, addr, sizeof(*mapped_addr));
    }
  }
  if ((error = prepare_socket(mapped_addr, fd, channel_args)) !=
      GRPC_ERROR_NONE) {
    return error;
  }
  addr_str = grpc_sockaddr_to_uri(mapped_addr);
  gpr_asprintf(&name, "tcp-client:%s", addr_str);
  *fdobj = grpc_fd_create(fd, name, true);
  gpr_free(name);
  gpr_free(addr_str);
  return GRPC_ERROR_NONE;
}

void grpc_tcp_client_create_from_prepared_fd(
    grpc_pollset_set* interested_parties, grpc_closure* closure, grpc_fd* fdobj,
    const grpc_channel_args* channel_args, const grpc_resolved_address* addr,
    grpc_millis deadline, grpc_endpoint** ep) {
  const int fd = grpc_fd_wrapped_fd(fdobj);
  int err;
  async_connect* ac;
  do {
    err = connect(fd, reinterpret_cast<const grpc_sockaddr*>(addr->addr),
                  addr->len);
  } while (err < 0 && errno == EINTR);
  if (err >= 0) {
    char* addr_str = grpc_sockaddr_to_uri(addr);
    *ep = grpc_tcp_client_create_from_fd(fdobj, channel_args, addr_str);
    gpr_free(addr_str);
    GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
    return;
  }
  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
    grpc_fd_orphan(fdobj, nullptr, nullptr, "tcp_client_connect_error");
    GRPC_CLOSURE_SCHED(closure, GRPC_OS_ERROR(errno, "connect"));
    return;
  }

  grpc_pollset_set_add_fd(interested_parties, fdobj);

  ac = static_cast<async_connect*>(gpr_malloc(sizeof(async_connect)));
  ac->closure = closure;
  ac->ep = ep;
  ac->fd = fdobj;
  ac->interested_parties = interested_parties;
  ac->addr_str = grpc_sockaddr_to_uri(addr);
  gpr_mu_init(&ac->mu);
  ac->refs = 2;
  GRPC_CLOSURE_INIT(&ac->write_closure, on_writable, ac,
                    grpc_schedule_on_exec_ctx);
  ac->channel_args = grpc_channel_args_copy(channel_args);

  if (grpc_tcp_trace.enabled()) {
    gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: asynchronously connecting fd %p",
            ac->addr_str, fdobj);
  }

  gpr_mu_lock(&ac->mu);
  GRPC_CLOSURE_INIT(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
  grpc_timer_init(&ac->alarm, deadline, &ac->on_alarm);
  grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
  gpr_mu_unlock(&ac->mu);
}

static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
                        grpc_pollset_set* interested_parties,
                        const grpc_channel_args* channel_args,
                        const grpc_resolved_address* addr,
                        grpc_millis deadline) {
  grpc_resolved_address mapped_addr;
  grpc_fd* fdobj = nullptr;
  grpc_error* error;
  *ep = nullptr;
  if ((error = grpc_tcp_client_prepare_fd(channel_args, addr, &mapped_addr,
                                          &fdobj)) != GRPC_ERROR_NONE) {
    GRPC_CLOSURE_SCHED(closure, error);
    return;
  }
  grpc_tcp_client_create_from_prepared_fd(interested_parties, closure, fdobj,
                                          channel_args, &mapped_addr, deadline,
                                          ep);
}

grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {tcp_connect};
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: axismodel.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef OOX_DRAWINGML_CHART_AXISMODEL_HXX
#define OOX_DRAWINGML_CHART_AXISMODEL_HXX

#include "oox/drawingml/shape.hxx"
#include "oox/drawingml/chart/titlemodel.hxx"

namespace oox {
namespace drawingml {
namespace chart {

// ============================================================================

struct AxisDispUnitsModel
{
    typedef ModelRef< Shape >       ShapeRef;
    typedef ModelRef< TextBody >    TextBodyRef;
    typedef ModelRef< LayoutModel > LayoutRef;
    typedef ModelRef< TextModel >   TextRef;

    ShapeRef            mxShapeProp;        /// Label frame formatting.
    TextBodyRef         mxTextProp;         /// Label text formatting.
    LayoutRef           mxLayout;           /// Layout/position of the axis units label.
    TextRef             mxText;             /// Text source of the axis units label.
    double              mfCustomUnit;       /// Custom unit size on value axis.
    sal_Int32           mnBuiltInUnit;      /// Built-in unit on value axis.

    explicit            AxisDispUnitsModel();
                        ~AxisDispUnitsModel();
};

// ============================================================================

struct AxisModel
{
    typedef ModelRef< Shape >               ShapeRef;
    typedef ModelRef< TextBody >            TextBodyRef;
    typedef ModelRef< TitleModel >          TitleRef;
    typedef ModelRef< AxisDispUnitsModel >  AxisDispUnitsRef;

    ShapeRef            mxShapeProp;        /// Axis line formatting.
    TextBodyRef         mxTextProp;         /// Axis label text formatting.
    TitleRef            mxTitle;            /// Axis title.
    AxisDispUnitsRef    mxDispUnits;        /// Axis units label.
    ShapeRef            mxMajorGridLines;   /// Major grid lines formatting.
    ShapeRef            mxMinorGridLines;   /// Minor grid lines formatting.
    ::rtl::OUString     maFormatCode;       /// Number format code for tick mark labels.
    OptDouble           mofCrossesAt;       /// Position on this axis where another axis crosses.
    OptDouble           mofMajorUnit;       /// Unit for major tick marks on date/value axis.
    OptDouble           mofMinorUnit;       /// Unit for minor tick marks on date/value axis.
    OptDouble           mofLogBase;         /// Logarithmic base for logarithmic axes.
    OptDouble           mofMax;             /// Maximum axis value.
    OptDouble           mofMin;             /// Minimum axis value.
    sal_Int32           mnAxisId;           /// Unique axis identifier.
    sal_Int32           mnAxisPos;          /// Position of the axis (top/bottom/left/right).
    sal_Int32           mnBaseTimeUnit;     /// Base time unit shown on a date axis.
    sal_Int32           mnCrossAxisId;      /// Identifier of a crossing axis.
    sal_Int32           mnCrossBetween;     /// This value axis crosses between or inside category.
    sal_Int32           mnCrossMode;        /// Mode this axis crosses another axis (min, max, auto).
    sal_Int32           mnLabelAlign;       /// Tick mark label alignment.
    sal_Int32           mnLabelOffset;      /// Tick mark label distance from axis.
    sal_Int32           mnMajorTickMark;    /// Major tick mark style.
    sal_Int32           mnMajorTimeUnit;    /// Time unit for major tick marks on date axis.
    sal_Int32           mnMinorTickMark;    /// Mainor tick mark style.
    sal_Int32           mnMinorTimeUnit;    /// Time unit for minor tick marks on date axis.
    sal_Int32           mnOrientation;      /// Axis orientation (value order min to max, or max to min).
    sal_Int32           mnTickLabelPos;     /// Position of tick mark labels relative to the axis.
    sal_Int32           mnTickLabelSkip;    /// Number of tick mark labels to skip.
    sal_Int32           mnTickMarkSkip;     /// Number of tick marks to skip.
    sal_Int32           mnTypeId;           /// Type identifier of this axis.
    bool                mbAuto;             /// True = automatic axis settings.
    bool                mbDeleted;          /// True = axis has been deleted manually.
    bool                mbNoMultiLevel;     /// True = no multi-level categories supported.
    bool                mbSourceLinked;     /// True = number format linked to source data.

    explicit            AxisModel( sal_Int32 nTypeId );
                        ~AxisModel();
};

// ============================================================================

} // namespace chart
} // namespace drawingml
} // namespace oox

#endif

<commit_msg>INTEGRATION: CWS xmlfilter05 (1.2.4); FILE MERGED 2008/05/21 10:26:54 dr 1.2.4.4: #i10000# new header 2008/04/16 13:10:07 dr 1.2.4.3: new optional token handling, fix default rotation in 3d charts 2008/04/02 12:41:47 hbrinkm 1.2.4.2: merged changes from xmlfilter04 to xmlfilter05 2008/04/01 15:37:18 hbrinkm 1.2.4.1: 'Merged xmlfilter04'<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: axismodel.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef OOX_DRAWINGML_CHART_AXISMODEL_HXX
#define OOX_DRAWINGML_CHART_AXISMODEL_HXX

#include "oox/drawingml/shape.hxx"
#include "oox/drawingml/chart/titlemodel.hxx"

namespace oox {
namespace drawingml {
namespace chart {

// ============================================================================

struct AxisDispUnitsModel
{
    typedef ModelRef< Shape >       ShapeRef;
    typedef ModelRef< TextBody >    TextBodyRef;
    typedef ModelRef< LayoutModel > LayoutRef;
    typedef ModelRef< TextModel >   TextRef;

    ShapeRef            mxShapeProp;        /// Label frame formatting.
    TextBodyRef         mxTextProp;         /// Label text formatting.
    LayoutRef           mxLayout;           /// Layout/position of the axis units label.
    TextRef             mxText;             /// Text source of the axis units label.
    double              mfCustomUnit;       /// Custom unit size on value axis.
    sal_Int32           mnBuiltInUnit;      /// Built-in unit on value axis.

    explicit            AxisDispUnitsModel();
                        ~AxisDispUnitsModel();
};

// ============================================================================

struct AxisModel
{
    typedef ModelRef< Shape >               ShapeRef;
    typedef ModelRef< TextBody >            TextBodyRef;
    typedef ModelRef< TitleModel >          TitleRef;
    typedef ModelRef< AxisDispUnitsModel >  AxisDispUnitsRef;

    ShapeRef            mxShapeProp;        /// Axis line formatting.
    TextBodyRef         mxTextProp;         /// Axis label text formatting.
    TitleRef            mxTitle;            /// Axis title.
    AxisDispUnitsRef    mxDispUnits;        /// Axis units label.
    ShapeRef            mxMajorGridLines;   /// Major grid lines formatting.
    ShapeRef            mxMinorGridLines;   /// Minor grid lines formatting.
    ::rtl::OUString     maFormatCode;       /// Number format code for tick mark labels.
    OptValue< double >  mofCrossesAt;       /// Position on this axis where another axis crosses.
    OptValue< double >  mofMajorUnit;       /// Unit for major tick marks on date/value axis.
    OptValue< double >  mofMinorUnit;       /// Unit for minor tick marks on date/value axis.
    OptValue< double >  mofLogBase;         /// Logarithmic base for logarithmic axes.
    OptValue< double >  mofMax;             /// Maximum axis value.
    OptValue< double >  mofMin;             /// Minimum axis value.
    sal_Int32           mnAxisId;           /// Unique axis identifier.
    sal_Int32           mnAxisPos;          /// Position of the axis (top/bottom/left/right).
    sal_Int32           mnBaseTimeUnit;     /// Base time unit shown on a date axis.
    sal_Int32           mnCrossAxisId;      /// Identifier of a crossing axis.
    sal_Int32           mnCrossBetween;     /// This value axis crosses between or inside category.
    sal_Int32           mnCrossMode;        /// Mode this axis crosses another axis (min, max, auto).
    sal_Int32           mnLabelAlign;       /// Tick mark label alignment.
    sal_Int32           mnLabelOffset;      /// Tick mark label distance from axis.
    sal_Int32           mnMajorTickMark;    /// Major tick mark style.
    sal_Int32           mnMajorTimeUnit;    /// Time unit for major tick marks on date axis.
    sal_Int32           mnMinorTickMark;    /// Mainor tick mark style.
    sal_Int32           mnMinorTimeUnit;    /// Time unit for minor tick marks on date axis.
    sal_Int32           mnOrientation;      /// Axis orientation (value order min to max, or max to min).
    sal_Int32           mnTickLabelPos;     /// Position of tick mark labels relative to the axis.
    sal_Int32           mnTickLabelSkip;    /// Number of tick mark labels to skip.
    sal_Int32           mnTickMarkSkip;     /// Number of tick marks to skip.
    sal_Int32           mnTypeId;           /// Type identifier of this axis.
    bool                mbAuto;             /// True = automatic axis settings.
    bool                mbDeleted;          /// True = axis has been deleted manually.
    bool                mbNoMultiLevel;     /// True = no multi-level categories supported.
    bool                mbSourceLinked;     /// True = number format linked to source data.

    explicit            AxisModel( sal_Int32 nTypeId );
                        ~AxisModel();
};

// ============================================================================

} // namespace chart
} // namespace drawingml
} // namespace oox

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/env.h"
#include "ui/aura/test/test_focus_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/gl/gl_surface.h"

#if defined(USE_X11)
#include "ui/gfx/x/x11_connection.h"
#endif

namespace {

// Trivial WindowDelegate implementation that draws a colored background.
class DemoWindowDelegate : public aura::WindowDelegate {
 public:
  explicit DemoWindowDelegate(SkColor color) : color_(color) {}

  // Overridden from WindowDelegate:
  virtual gfx::Size GetMinimumSize() const OVERRIDE {
    return gfx::Size();
  }

  virtual gfx::Size GetMaximumSize() const OVERRIDE {
    return gfx::Size();
  }

  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
                               const gfx::Rect& new_bounds) OVERRIDE {}
  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
    return gfx::kNullCursor;
  }
  virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
    return HTCAPTION;
  }
  virtual bool ShouldDescendIntoChildForEventHandling(
      aura::Window* child,
      const gfx::Point& location) OVERRIDE {
    return true;
  }
  virtual bool CanFocus() OVERRIDE { return true; }
  virtual void OnCaptureLost() OVERRIDE {}
  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    canvas->DrawColor(color_, SkXfermode::kSrc_Mode);
  }
  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {}
  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
  virtual bool HasHitTestMask() const OVERRIDE { return false; }
  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}

 private:
  SkColor color_;

  DISALLOW_COPY_AND_ASSIGN(DemoWindowDelegate);
};

class DemoWindowTreeClient : public aura::client::WindowTreeClient {
 public:
  explicit DemoWindowTreeClient(aura::Window* window) : window_(window) {
    aura::client::SetWindowTreeClient(window_, this);
  }

  virtual ~DemoWindowTreeClient() {
    aura::client::SetWindowTreeClient(window_, NULL);
  }

  // Overridden from aura::client::WindowTreeClient:
  virtual aura::Window* GetDefaultParent(aura::Window* context,
                                         aura::Window* window,
                                         const gfx::Rect& bounds) OVERRIDE {
    if (!capture_client_) {
      capture_client_.reset(
          new aura::client::DefaultCaptureClient(window_->GetRootWindow()));
    }
    return window_;
  }

 private:
  aura::Window* window_;

  scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;

  DISALLOW_COPY_AND_ASSIGN(DemoWindowTreeClient);
};

int DemoMain() {
#if defined(USE_X11)
  // This demo uses InProcessContextFactory which uses X on a separate Gpu
  // thread.
  gfx::InitializeThreadedX11();
#endif

  gfx::GLSurface::InitializeOneOff();

  // The ContextFactory must exist before any Compositors are created.
  scoped_ptr<ui::InProcessContextFactory> context_factory(
      new ui::InProcessContextFactory());
  ui::ContextFactory::SetInstance(context_factory.get());

  // Create the message-loop here before creating the root window.
  base::MessageLoopForUI message_loop;

  aura::Env::CreateInstance();
  scoped_ptr<aura::TestScreen> test_screen(aura::TestScreen::Create());
  gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
  scoped_ptr<aura::WindowTreeHost> host(
      test_screen->CreateHostForPrimaryDisplay());
  scoped_ptr<DemoWindowTreeClient> window_tree_client(
      new DemoWindowTreeClient(host->window()));
  aura::test::TestFocusClient focus_client;
  aura::client::SetFocusClient(host->window(), &focus_client);

  // Create a hierarchy of test windows.
  DemoWindowDelegate window_delegate1(SK_ColorBLUE);
  aura::Window window1(&window_delegate1);
  window1.set_id(1);
  window1.Init(aura::WINDOW_LAYER_TEXTURED);
  window1.SetBounds(gfx::Rect(100, 100, 400, 400));
  window1.Show();
  aura::client::ParentWindowWithContext(&window1, host->window(), gfx::Rect());

  DemoWindowDelegate window_delegate2(SK_ColorRED);
  aura::Window window2(&window_delegate2);
  window2.set_id(2);
  window2.Init(aura::WINDOW_LAYER_TEXTURED);
  window2.SetBounds(gfx::Rect(200, 200, 350, 350));
  window2.Show();
  aura::client::ParentWindowWithContext(&window2, host->window(), gfx::Rect());

  DemoWindowDelegate window_delegate3(SK_ColorGREEN);
  aura::Window window3(&window_delegate3);
  window3.set_id(3);
  window3.Init(aura::WINDOW_LAYER_TEXTURED);
  window3.SetBounds(gfx::Rect(10, 10, 50, 50));
  window3.Show();
  window2.AddChild(&window3);

  host->Show();
  base::MessageLoopForUI::current()->Run();

  return 0;
}

}  // namespace

int main(int argc, char** argv) {
  CommandLine::Init(argc, argv);

  // The exit manager is in charge of calling the dtors of singleton objects.
  base::AtExitManager exit_manager;

  base::i18n::InitializeICU();

  return DemoMain();
}
<commit_msg>Aura demo: Initialize device scale factor<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/env.h"
#include "ui/aura/test/test_focus_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/gl/gl_surface.h"

#if defined(USE_X11)
#include "ui/gfx/x/x11_connection.h"
#endif

#if defined(OS_WIN)
#include "ui/gfx/win/dpi.h"
#endif

namespace {

// Trivial WindowDelegate implementation that draws a colored background.
class DemoWindowDelegate : public aura::WindowDelegate {
 public:
  explicit DemoWindowDelegate(SkColor color) : color_(color) {}

  // Overridden from WindowDelegate:
  virtual gfx::Size GetMinimumSize() const OVERRIDE {
    return gfx::Size();
  }

  virtual gfx::Size GetMaximumSize() const OVERRIDE {
    return gfx::Size();
  }

  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
                               const gfx::Rect& new_bounds) OVERRIDE {}
  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
    return gfx::kNullCursor;
  }
  virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
    return HTCAPTION;
  }
  virtual bool ShouldDescendIntoChildForEventHandling(
      aura::Window* child,
      const gfx::Point& location) OVERRIDE {
    return true;
  }
  virtual bool CanFocus() OVERRIDE { return true; }
  virtual void OnCaptureLost() OVERRIDE {}
  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    canvas->DrawColor(color_, SkXfermode::kSrc_Mode);
  }
  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {}
  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
  virtual bool HasHitTestMask() const OVERRIDE { return false; }
  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}

 private:
  SkColor color_;

  DISALLOW_COPY_AND_ASSIGN(DemoWindowDelegate);
};

class DemoWindowTreeClient : public aura::client::WindowTreeClient {
 public:
  explicit DemoWindowTreeClient(aura::Window* window) : window_(window) {
    aura::client::SetWindowTreeClient(window_, this);
  }

  virtual ~DemoWindowTreeClient() {
    aura::client::SetWindowTreeClient(window_, NULL);
  }

  // Overridden from aura::client::WindowTreeClient:
  virtual aura::Window* GetDefaultParent(aura::Window* context,
                                         aura::Window* window,
                                         const gfx::Rect& bounds) OVERRIDE {
    if (!capture_client_) {
      capture_client_.reset(
          new aura::client::DefaultCaptureClient(window_->GetRootWindow()));
    }
    return window_;
  }

 private:
  aura::Window* window_;

  scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;

  DISALLOW_COPY_AND_ASSIGN(DemoWindowTreeClient);
};

int DemoMain() {
#if defined(USE_X11)
  // This demo uses InProcessContextFactory which uses X on a separate Gpu
  // thread.
  gfx::InitializeThreadedX11();
#endif

  gfx::GLSurface::InitializeOneOff();

#if defined(OS_WIN)
  gfx::InitDeviceScaleFactor(1.0f);
#endif

  // The ContextFactory must exist before any Compositors are created.
  scoped_ptr<ui::InProcessContextFactory> context_factory(
      new ui::InProcessContextFactory());
  ui::ContextFactory::SetInstance(context_factory.get());

  // Create the message-loop here before creating the root window.
  base::MessageLoopForUI message_loop;

  aura::Env::CreateInstance();
  scoped_ptr<aura::TestScreen> test_screen(aura::TestScreen::Create());
  gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
  scoped_ptr<aura::WindowTreeHost> host(
      test_screen->CreateHostForPrimaryDisplay());
  scoped_ptr<DemoWindowTreeClient> window_tree_client(
      new DemoWindowTreeClient(host->window()));
  aura::test::TestFocusClient focus_client;
  aura::client::SetFocusClient(host->window(), &focus_client);

  // Create a hierarchy of test windows.
  DemoWindowDelegate window_delegate1(SK_ColorBLUE);
  aura::Window window1(&window_delegate1);
  window1.set_id(1);
  window1.Init(aura::WINDOW_LAYER_TEXTURED);
  window1.SetBounds(gfx::Rect(100, 100, 400, 400));
  window1.Show();
  aura::client::ParentWindowWithContext(&window1, host->window(), gfx::Rect());

  DemoWindowDelegate window_delegate2(SK_ColorRED);
  aura::Window window2(&window_delegate2);
  window2.set_id(2);
  window2.Init(aura::WINDOW_LAYER_TEXTURED);
  window2.SetBounds(gfx::Rect(200, 200, 350, 350));
  window2.Show();
  aura::client::ParentWindowWithContext(&window2, host->window(), gfx::Rect());

  DemoWindowDelegate window_delegate3(SK_ColorGREEN);
  aura::Window window3(&window_delegate3);
  window3.set_id(3);
  window3.Init(aura::WINDOW_LAYER_TEXTURED);
  window3.SetBounds(gfx::Rect(10, 10, 50, 50));
  window3.Show();
  window2.AddChild(&window3);

  host->Show();
  base::MessageLoopForUI::current()->Run();

  return 0;
}

}  // namespace

int main(int argc, char** argv) {
  CommandLine::Init(argc, argv);

  // The exit manager is in charge of calling the dtors of singleton objects.
  base::AtExitManager exit_manager;

  base::i18n::InitializeICU();

  return DemoMain();
}
<|endoftext|>