<commit_before>#ifndef CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_
#define CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_

#include <map>

#include "buffer_cache/mirrored/mirrored.hpp"
#include "buffer_cache/semantic_checking.hpp"
#include "clustering/immediate_consistency/branch/history.hpp"
#include "clustering/immediate_consistency/branch/metadata.hpp"
#include "clustering/immediate_consistency/branch/multistore.hpp"
#include "clustering/registrant.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/promise.hpp"
#include "concurrency/queue/disk_backed_queue_wrapper.hpp"
#include "serializer/types.hpp"
#include "timestamps.hpp"
#include "utils.hpp"

template <class T> class replier_t;
template <class T> class intro_receiver_t;
template <class T> class registrant_t;
template <class T> class semilattice_read_view_t;
template <class T> class semilattice_readwrite_view_t;
template <class T> class broadcaster_t;

/* `listener_t` keeps a store-view in sync with a branch. Its constructor
backfills from an existing mirror on a branch into the store, and as long as it
exists the store will receive real-time updates.

There are four ways a `listener_t` can go wrong:
 *  You can interrupt the constructor. It will throw `interrupted_exc_t`. The
    store may be left in a half-backfilled state; you can determine this through
    the store's metadata.
 *  It can fail to contact the backfiller. In that case,
    the constructor will throw `backfiller_lost_exc_t`.
 *  It can fail to contact the broadcaster. In this case it will throw `broadcaster_lost_exc_t`.
 *  It can successfully join the branch, but then lose contact with the
    broadcaster later. In that case, `get_broadcaster_lost_signal()` will be
    pulsed when it loses touch.
*/

template<class protocol_t>
class listener_t {
public:
    class backfiller_lost_exc_t : public std::exception {
    public:
        const char *what() const throw () {
            return "Lost contact with backfiller";
        }
    };

    class broadcaster_lost_exc_t : public std::exception {
    public:
        const char *what() const throw () {
            return "Lost contact with broadcaster";
        }
    };

    listener_t(
            mailbox_manager_t *mm,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster_metadata,
            branch_history_manager_t<protocol_t> *branch_history_manager,
            multistore_ptr_t<protocol_t> *svs,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<replier_business_card_t<protocol_t> > > > > replier,
            backfill_session_id_t backfill_session_id,
            perfmon_collection_t *backfill_stats_parent,
            signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, backfiller_lost_exc_t, broadcaster_lost_exc_t);

    /* This version of the `listener_t` constructor is called when we are
    becoming the first mirror of a new branch. It should only be called once for
    each `broadcaster_t`. */
    listener_t(
            mailbox_manager_t *mm,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster_metadata,
            branch_history_manager_t<protocol_t> *branch_history_manager,
            broadcaster_t<protocol_t> *broadcaster,
            perfmon_collection_t *backfill_stats_parent,
            signal_t *interruptor) THROWS_ONLY(interrupted_exc_t);

    /* Returns a signal that is pulsed if the mirror is not in contact with the
    master. */
    signal_t *get_broadcaster_lost_signal();

private:
    friend class replier_t<protocol_t>;
    friend class intro_receiver_t<protocol_t>;

    /* `intro_t` represents the introduction we expect to get from the
    broadcaster if all goes well. */
    class intro_t {
    public:
        typename listener_business_card_t<protocol_t>::upgrade_mailbox_t::address_t upgrade_mailbox;
        typename listener_business_card_t<protocol_t>::downgrade_mailbox_t::address_t downgrade_mailbox;
        state_timestamp_t broadcaster_begin_timestamp;
    };

    class write_queue_entry_t {
    public:
        write_queue_entry_t() { }
        write_queue_entry_t(const typename protocol_t::write_t &w, transition_timestamp_t tt, order_token_t _order_token, fifo_enforcer_write_token_t ft) :
            write(w), transition_timestamp(tt), order_token(_order_token), fifo_token(ft) { }
        typename protocol_t::write_t write;
        transition_timestamp_t transition_timestamp;
        order_token_t order_token;
        fifo_enforcer_write_token_t fifo_token;

        // TODO: Why does this need to be serializable?
        RDB_MAKE_ME_SERIALIZABLE_4(write, order_token, transition_timestamp, fifo_token);
    };

    // TODO: This boost optional boost optional crap is ... crap.  This isn't Haskell, this is *real* programming, people.
    static boost::optional<boost::optional<backfiller_business_card_t<protocol_t> > > get_backfiller_from_replier_bcard(const boost::optional<boost::optional<replier_business_card_t<protocol_t> > > &replier_bcard);

    // TODO: Boost boost optional optional business card business card protocol_tee tee tee tee piii kaaa chuuuuu!
    static boost::optional<boost::optional<registrar_business_card_t<listener_business_card_t<protocol_t> > > > get_registrar_from_broadcaster_bcard(const boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > &broadcaster_bcard);

    /* `try_start_receiving_writes()` is called from within the constructors. It
    tries to register with the master. It throws `interrupted_exc_t` if
    `interruptor` is pulsed. Otherwise, it fills `registration_result_cond` with
    a value indicating if the registration succeeded or not, and with the intro
    we got from the broadcaster if it succeeded. */
    void try_start_receiving_writes(
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster,
            signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t, broadcaster_lost_exc_t);

    void on_write(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void()> ack_addr)
        THROWS_NOTHING;

    void enqueue_write(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void()> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void perform_enqueued_write(const write_queue_entry_t &serialized_write, state_timestamp_t backfill_end_timestamp, signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t);

    /* See the note at the place where `writeread_mailbox` is declared for an
    explanation of why `on_writeread()` and `on_read()` are here. */

    void on_writeread(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::write_response_t)> ack_addr)
        THROWS_NOTHING;

    void perform_writeread(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::write_response_t)> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void on_read(typename protocol_t::read_t read,
            state_timestamp_t expected_timestamp,
            order_token_t order_token,
            fifo_enforcer_read_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::read_response_t)> ack_addr)
        THROWS_NOTHING;

    void perform_read(typename protocol_t::read_t read,
            DEBUG_ONLY_VAR state_timestamp_t expected_timestamp,
            order_token_t order_token,
            fifo_enforcer_read_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::read_response_t)> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void wait_for_version(state_timestamp_t timestamp, signal_t *interruptor);

    void advance_current_timestamp_and_pulse_waiters(transition_timestamp_t timestamp);

    mailbox_manager_t *mailbox_manager;

    branch_history_manager_t<protocol_t> *branch_history_manager;

    multistore_ptr_t<protocol_t> *svs;

    branch_id_t branch_id;

    /* `upgrade_mailbox` and `broadcaster_begin_timestamp` are valid only if we
    successfully registered with the broadcaster at some point. As a sanity
    check, we put them in a `promise_t`, `registration_done_cond`, that only
    gets pulsed when we successfully register. */
    promise_t<intro_t> registration_done_cond;

    uuid_t uuid;
    perfmon_collection_t perfmon_collection;
    fifo_enforcer_sink_t write_queue_entrance_sink;
    disk_backed_queue_wrapper_t<write_queue_entry_t> write_queue;
    boost::scoped_ptr<typename coro_pool_t<write_queue_entry_t>::boost_function_callback_t> write_queue_coro_pool_callback;
    boost::scoped_ptr<coro_pool_t<write_queue_entry_t> > write_queue_coro_pool;
    adjustable_semaphore_t write_queue_semaphore;
    cond_t write_queue_has_drained;

    state_timestamp_t current_timestamp;

    fifo_enforcer_sink_t store_entrance_sink;

    auto_drainer_t drainer;

    typename listener_business_card_t<protocol_t>::write_mailbox_t write_mailbox;

    /* `writeread_mailbox` and `read_mailbox` live on the `listener_t` even
    though they don't get used until the `replier_t` is constructed. The reason
    `writeread_mailbox` has to live here is so we don't drop writes if the
    `replier_t` is destroyed without doing a warm shutdown but the `listener_t`
    stays alive. The reason `read_mailbox` is here is for consistency, and to
    have all the query-handling code in one place. */
    typename listener_business_card_t<protocol_t>::writeread_mailbox_t writeread_mailbox;
    typename listener_business_card_t<protocol_t>::read_mailbox_t read_mailbox;

    boost::scoped_ptr<registrant_t<listener_business_card_t<protocol_t> > > registrant;

    /* Avaste this be used to keep track of people who are waitin' for a us to
     * be up to date (past the given state_timestamp_t). The only use case for
     * this right now is the replier_t who needs to be able to tell backfillees
     * how up to date s/he is. */
    std::multimap<state_timestamp_t, cond_t *> synchronize_waiters;

    DISABLE_COPYING(listener_t);
};

#endif /* CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_ */
<commit_msg>Explained why write_queue_entry_t is serializable.<commit_after>#ifndef CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_
#define CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_

#include <map>

#include "buffer_cache/mirrored/mirrored.hpp"
#include "buffer_cache/semantic_checking.hpp"
#include "clustering/immediate_consistency/branch/history.hpp"
#include "clustering/immediate_consistency/branch/metadata.hpp"
#include "clustering/immediate_consistency/branch/multistore.hpp"
#include "clustering/registrant.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/promise.hpp"
#include "concurrency/queue/disk_backed_queue_wrapper.hpp"
#include "serializer/types.hpp"
#include "timestamps.hpp"
#include "utils.hpp"

template <class T> class replier_t;
template <class T> class intro_receiver_t;
template <class T> class registrant_t;
template <class T> class semilattice_read_view_t;
template <class T> class semilattice_readwrite_view_t;
template <class T> class broadcaster_t;

/* `listener_t` keeps a store-view in sync with a branch. Its constructor
backfills from an existing mirror on a branch into the store, and as long as it
exists the store will receive real-time updates.

There are four ways a `listener_t` can go wrong:
 *  You can interrupt the constructor. It will throw `interrupted_exc_t`. The
    store may be left in a half-backfilled state; you can determine this through
    the store's metadata.
 *  It can fail to contact the backfiller. In that case,
    the constructor will throw `backfiller_lost_exc_t`.
 *  It can fail to contact the broadcaster. In this case it will throw `broadcaster_lost_exc_t`.
 *  It can successfully join the branch, but then lose contact with the
    broadcaster later. In that case, `get_broadcaster_lost_signal()` will be
    pulsed when it loses touch.
*/

template<class protocol_t>
class listener_t {
public:
    class backfiller_lost_exc_t : public std::exception {
    public:
        const char *what() const throw () {
            return "Lost contact with backfiller";
        }
    };

    class broadcaster_lost_exc_t : public std::exception {
    public:
        const char *what() const throw () {
            return "Lost contact with broadcaster";
        }
    };

    listener_t(
            mailbox_manager_t *mm,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster_metadata,
            branch_history_manager_t<protocol_t> *branch_history_manager,
            multistore_ptr_t<protocol_t> *svs,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<replier_business_card_t<protocol_t> > > > > replier,
            backfill_session_id_t backfill_session_id,
            perfmon_collection_t *backfill_stats_parent,
            signal_t *interruptor) THROWS_ONLY(interrupted_exc_t, backfiller_lost_exc_t, broadcaster_lost_exc_t);

    /* This version of the `listener_t` constructor is called when we are
    becoming the first mirror of a new branch. It should only be called once for
    each `broadcaster_t`. */
    listener_t(
            mailbox_manager_t *mm,
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster_metadata,
            branch_history_manager_t<protocol_t> *branch_history_manager,
            broadcaster_t<protocol_t> *broadcaster,
            perfmon_collection_t *backfill_stats_parent,
            signal_t *interruptor) THROWS_ONLY(interrupted_exc_t);

    /* Returns a signal that is pulsed if the mirror is not in contact with the
    master. */
    signal_t *get_broadcaster_lost_signal();

private:
    friend class replier_t<protocol_t>;
    friend class intro_receiver_t<protocol_t>;

    /* `intro_t` represents the introduction we expect to get from the
    broadcaster if all goes well. */
    class intro_t {
    public:
        typename listener_business_card_t<protocol_t>::upgrade_mailbox_t::address_t upgrade_mailbox;
        typename listener_business_card_t<protocol_t>::downgrade_mailbox_t::address_t downgrade_mailbox;
        state_timestamp_t broadcaster_begin_timestamp;
    };

    class write_queue_entry_t {
    public:
        write_queue_entry_t() { }
        write_queue_entry_t(const typename protocol_t::write_t &w, transition_timestamp_t tt, order_token_t _order_token, fifo_enforcer_write_token_t ft) :
            write(w), transition_timestamp(tt), order_token(_order_token), fifo_token(ft) { }
        typename protocol_t::write_t write;
        transition_timestamp_t transition_timestamp;
        order_token_t order_token;
        fifo_enforcer_write_token_t fifo_token;

        // This is serializable because this gets written to a disk backed queue.
        RDB_MAKE_ME_SERIALIZABLE_4(write, order_token, transition_timestamp, fifo_token);
    };

    // TODO: This boost optional boost optional crap is ... crap.  This isn't Haskell, this is *real* programming, people.
    static boost::optional<boost::optional<backfiller_business_card_t<protocol_t> > > get_backfiller_from_replier_bcard(const boost::optional<boost::optional<replier_business_card_t<protocol_t> > > &replier_bcard);

    // TODO: Boost boost optional optional business card business card protocol_tee tee tee tee piii kaaa chuuuuu!
    static boost::optional<boost::optional<registrar_business_card_t<listener_business_card_t<protocol_t> > > > get_registrar_from_broadcaster_bcard(const boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > &broadcaster_bcard);

    /* `try_start_receiving_writes()` is called from within the constructors. It
    tries to register with the master. It throws `interrupted_exc_t` if
    `interruptor` is pulsed. Otherwise, it fills `registration_result_cond` with
    a value indicating if the registration succeeded or not, and with the intro
    we got from the broadcaster if it succeeded. */
    void try_start_receiving_writes(
            clone_ptr_t<watchable_t<boost::optional<boost::optional<broadcaster_business_card_t<protocol_t> > > > > broadcaster,
            signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t, broadcaster_lost_exc_t);

    void on_write(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void()> ack_addr)
        THROWS_NOTHING;

    void enqueue_write(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void()> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void perform_enqueued_write(const write_queue_entry_t &serialized_write, state_timestamp_t backfill_end_timestamp, signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t);

    /* See the note at the place where `writeread_mailbox` is declared for an
    explanation of why `on_writeread()` and `on_read()` are here. */

    void on_writeread(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::write_response_t)> ack_addr)
        THROWS_NOTHING;

    void perform_writeread(typename protocol_t::write_t write,
            transition_timestamp_t transition_timestamp,
            order_token_t order_token,
            fifo_enforcer_write_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::write_response_t)> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void on_read(typename protocol_t::read_t read,
            state_timestamp_t expected_timestamp,
            order_token_t order_token,
            fifo_enforcer_read_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::read_response_t)> ack_addr)
        THROWS_NOTHING;

    void perform_read(typename protocol_t::read_t read,
            DEBUG_ONLY_VAR state_timestamp_t expected_timestamp,
            order_token_t order_token,
            fifo_enforcer_read_token_t fifo_token,
            mailbox_addr_t<void(typename protocol_t::read_response_t)> ack_addr,
            auto_drainer_t::lock_t keepalive)
        THROWS_NOTHING;

    void wait_for_version(state_timestamp_t timestamp, signal_t *interruptor);

    void advance_current_timestamp_and_pulse_waiters(transition_timestamp_t timestamp);

    mailbox_manager_t *mailbox_manager;

    branch_history_manager_t<protocol_t> *branch_history_manager;

    multistore_ptr_t<protocol_t> *svs;

    branch_id_t branch_id;

    /* `upgrade_mailbox` and `broadcaster_begin_timestamp` are valid only if we
    successfully registered with the broadcaster at some point. As a sanity
    check, we put them in a `promise_t`, `registration_done_cond`, that only
    gets pulsed when we successfully register. */
    promise_t<intro_t> registration_done_cond;

    uuid_t uuid;
    perfmon_collection_t perfmon_collection;
    fifo_enforcer_sink_t write_queue_entrance_sink;
    disk_backed_queue_wrapper_t<write_queue_entry_t> write_queue;
    boost::scoped_ptr<typename coro_pool_t<write_queue_entry_t>::boost_function_callback_t> write_queue_coro_pool_callback;
    boost::scoped_ptr<coro_pool_t<write_queue_entry_t> > write_queue_coro_pool;
    adjustable_semaphore_t write_queue_semaphore;
    cond_t write_queue_has_drained;

    state_timestamp_t current_timestamp;

    fifo_enforcer_sink_t store_entrance_sink;

    auto_drainer_t drainer;

    typename listener_business_card_t<protocol_t>::write_mailbox_t write_mailbox;

    /* `writeread_mailbox` and `read_mailbox` live on the `listener_t` even
    though they don't get used until the `replier_t` is constructed. The reason
    `writeread_mailbox` has to live here is so we don't drop writes if the
    `replier_t` is destroyed without doing a warm shutdown but the `listener_t`
    stays alive. The reason `read_mailbox` is here is for consistency, and to
    have all the query-handling code in one place. */
    typename listener_business_card_t<protocol_t>::writeread_mailbox_t writeread_mailbox;
    typename listener_business_card_t<protocol_t>::read_mailbox_t read_mailbox;

    boost::scoped_ptr<registrant_t<listener_business_card_t<protocol_t> > > registrant;

    /* Avaste this be used to keep track of people who are waitin' for a us to
     * be up to date (past the given state_timestamp_t). The only use case for
     * this right now is the replier_t who needs to be able to tell backfillees
     * how up to date s/he is. */
    std::multimap<state_timestamp_t, cond_t *> synchronize_waiters;

    DISABLE_COPYING(listener_t);
};

#endif /* CLUSTERING_IMMEDIATE_CONSISTENCY_BRANCH_LISTENER_HPP_ */
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "duplex.hxx"
#include "event/SocketEvent.hxx"
#include "event/DeferEvent.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "net/Buffered.hxx"
#include "io/Buffered.hxx"
#include "io/Logger.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"

#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

class FallbackEvent {
    SocketEvent socket_event;
    DeferEvent defer_event;

    const BoundMethod<void()> callback;

public:
    FallbackEvent(EventLoop &event_loop, int fd, short events,
                  BoundMethod<void()> _callback)
        :socket_event(event_loop, fd, events, BIND_THIS_METHOD(OnSocket)),
         defer_event(event_loop, _callback),
         callback(_callback) {}

    void Add() {
        if (!socket_event.Add())
            /* if "fd" is a regular file, trigger the event repeatedly
               using DeferEvent, because we can't use SocketEvent::READ on
               regular files */
            defer_event.Schedule();
    }

    void Delete() {
        socket_event.Delete();
        defer_event.Cancel();
    }

private:
    void OnSocket(unsigned) {
        callback();
    }
};

class Duplex {
    int read_fd;
    int write_fd;
    int sock_fd;
    bool sock_eof = false;

    SliceFifoBuffer from_read, to_write;

    FallbackEvent read_event, write_event;
    SocketEvent socket_read_event, socket_write_event;

public:
    Duplex(EventLoop &event_loop, int _read_fd, int _write_fd, int _sock_fd)
        :read_fd(_read_fd), write_fd(_write_fd), sock_fd(_sock_fd),
         read_event(event_loop, read_fd, SocketEvent::READ,
                    BIND_THIS_METHOD(ReadEventCallback)),
         write_event(event_loop, write_fd, SocketEvent::WRITE,
                     BIND_THIS_METHOD(WriteEventCallback)),
         socket_read_event(event_loop, sock_fd, SocketEvent::READ,
                           BIND_THIS_METHOD(SocketReadEventCallback)),
         socket_write_event(event_loop, sock_fd, SocketEvent::WRITE,
                           BIND_THIS_METHOD(SocketWriteEventCallback))
    {
        from_read.Allocate(fb_pool_get());
        to_write.Allocate(fb_pool_get());

        read_event.Add();
        socket_read_event.Add();
    }

private:
    void CloseRead() {
        assert(read_fd >= 0);

        read_event.Delete();

        if (read_fd > 2)
            close(read_fd);

        read_fd = -1;
    }

    void CloseWrite() {
        assert(write_fd >= 0);

        write_event.Delete();

        if (write_fd > 2)
            close(write_fd);

        write_fd = -1;
    }

    void CloseSocket() {
        assert(sock_fd >= 0);

        socket_read_event.Delete();
        socket_write_event.Delete();

        close(sock_fd);
        sock_fd = -1;
    }

    void Destroy();
    bool CheckDestroy();

    void ReadEventCallback();
    void WriteEventCallback();
    void SocketReadEventCallback(unsigned);
    void SocketWriteEventCallback(unsigned);
};

void
Duplex::Destroy()
{
    if (read_fd >= 0)
        CloseRead();

    if (write_fd >= 0)
        CloseWrite();

    if (sock_fd >= 0)
        CloseSocket();

    from_read.Free(fb_pool_get());
    to_write.Free(fb_pool_get());
}

bool
Duplex::CheckDestroy()
{
    if (read_fd < 0 && sock_eof && from_read.empty() && to_write.empty()) {
        Destroy();
        return true;
    } else
        return false;
}

inline void
Duplex::ReadEventCallback()
{
    ssize_t nbytes = read_to_buffer(read_fd, from_read, INT_MAX);
    if (nbytes == -1) {
        LogConcat(1, "Duplex", "failed to read: ", strerror(errno));
        Destroy();
        return;
    }

    if (nbytes == 0) {
        CloseRead();
        CheckDestroy();
        return;
    }

    socket_write_event.Add();

    if (!from_read.IsFull())
        read_event.Add();
}

inline void
Duplex::WriteEventCallback()
{
    ssize_t nbytes = write_from_buffer(write_fd, to_write);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && !sock_eof)
        socket_read_event.Add();

    if (!to_write.empty())
        write_event.Add();
    else
        CheckDestroy();
}

inline void
Duplex::SocketReadEventCallback(unsigned)
{
    ssize_t nbytes = ReceiveToBuffer(sock_fd, to_write);
    if (nbytes == -1) {
        LogConcat(1, "Duplex", "failed to read: ", strerror(errno));
        Destroy();
        return;
    }

    if (gcc_likely(nbytes > 0)) {
        write_event.Add();
        if (!to_write.IsFull())
            socket_read_event.Add();
    } else {
        sock_eof = true;
        CheckDestroy();
    }
}

inline void
Duplex::SocketWriteEventCallback(unsigned)
{
    ssize_t nbytes = SendFromBuffer(sock_fd, from_read);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && read_fd >= 0)
        read_event.Add();

    if (!from_read.empty())
        socket_write_event.Add();
}

int
duplex_new(EventLoop &event_loop, struct pool *pool, int read_fd, int write_fd)
{
    assert(pool != nullptr);
    assert(read_fd >= 0);
    assert(write_fd >= 0);

    UniqueSocketDescriptor result_fd, duplex_fd;
    if (!UniqueSocketDescriptor::CreateSocketPairNonBlock(AF_LOCAL, SOCK_STREAM, 0,
                                                          result_fd, duplex_fd))
        return -1;

    NewFromPool<Duplex>(*pool, event_loop, read_fd, write_fd,
                        duplex_fd.Steal());
    return result_fd.Steal();
}
<commit_msg>duplex: call destructor<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "duplex.hxx"
#include "event/SocketEvent.hxx"
#include "event/DeferEvent.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "net/Buffered.hxx"
#include "io/Buffered.hxx"
#include "io/Logger.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"

#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

class FallbackEvent {
    SocketEvent socket_event;
    DeferEvent defer_event;

    const BoundMethod<void()> callback;

public:
    FallbackEvent(EventLoop &event_loop, int fd, short events,
                  BoundMethod<void()> _callback)
        :socket_event(event_loop, fd, events, BIND_THIS_METHOD(OnSocket)),
         defer_event(event_loop, _callback),
         callback(_callback) {}

    void Add() {
        if (!socket_event.Add())
            /* if "fd" is a regular file, trigger the event repeatedly
               using DeferEvent, because we can't use SocketEvent::READ on
               regular files */
            defer_event.Schedule();
    }

    void Delete() {
        socket_event.Delete();
        defer_event.Cancel();
    }

private:
    void OnSocket(unsigned) {
        callback();
    }
};

class Duplex {
    int read_fd;
    int write_fd;
    int sock_fd;
    bool sock_eof = false;

    SliceFifoBuffer from_read, to_write;

    FallbackEvent read_event, write_event;
    SocketEvent socket_read_event, socket_write_event;

public:
    Duplex(EventLoop &event_loop, int _read_fd, int _write_fd, int _sock_fd)
        :read_fd(_read_fd), write_fd(_write_fd), sock_fd(_sock_fd),
         read_event(event_loop, read_fd, SocketEvent::READ,
                    BIND_THIS_METHOD(ReadEventCallback)),
         write_event(event_loop, write_fd, SocketEvent::WRITE,
                     BIND_THIS_METHOD(WriteEventCallback)),
         socket_read_event(event_loop, sock_fd, SocketEvent::READ,
                           BIND_THIS_METHOD(SocketReadEventCallback)),
         socket_write_event(event_loop, sock_fd, SocketEvent::WRITE,
                           BIND_THIS_METHOD(SocketWriteEventCallback))
    {
        from_read.Allocate(fb_pool_get());
        to_write.Allocate(fb_pool_get());

        read_event.Add();
        socket_read_event.Add();
    }

private:
    void CloseRead() {
        assert(read_fd >= 0);

        read_event.Delete();

        if (read_fd > 2)
            close(read_fd);

        read_fd = -1;
    }

    void CloseWrite() {
        assert(write_fd >= 0);

        write_event.Delete();

        if (write_fd > 2)
            close(write_fd);

        write_fd = -1;
    }

    void CloseSocket() {
        assert(sock_fd >= 0);

        socket_read_event.Delete();
        socket_write_event.Delete();

        close(sock_fd);
        sock_fd = -1;
    }

    void Destroy();
    bool CheckDestroy();

    void ReadEventCallback();
    void WriteEventCallback();
    void SocketReadEventCallback(unsigned);
    void SocketWriteEventCallback(unsigned);
};

void
Duplex::Destroy()
{
    if (read_fd >= 0)
        CloseRead();

    if (write_fd >= 0)
        CloseWrite();

    if (sock_fd >= 0)
        CloseSocket();

    from_read.Free(fb_pool_get());
    to_write.Free(fb_pool_get());

    this->~Duplex();
}

bool
Duplex::CheckDestroy()
{
    if (read_fd < 0 && sock_eof && from_read.empty() && to_write.empty()) {
        Destroy();
        return true;
    } else
        return false;
}

inline void
Duplex::ReadEventCallback()
{
    ssize_t nbytes = read_to_buffer(read_fd, from_read, INT_MAX);
    if (nbytes == -1) {
        LogConcat(1, "Duplex", "failed to read: ", strerror(errno));
        Destroy();
        return;
    }

    if (nbytes == 0) {
        CloseRead();
        CheckDestroy();
        return;
    }

    socket_write_event.Add();

    if (!from_read.IsFull())
        read_event.Add();
}

inline void
Duplex::WriteEventCallback()
{
    ssize_t nbytes = write_from_buffer(write_fd, to_write);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && !sock_eof)
        socket_read_event.Add();

    if (!to_write.empty())
        write_event.Add();
    else
        CheckDestroy();
}

inline void
Duplex::SocketReadEventCallback(unsigned)
{
    ssize_t nbytes = ReceiveToBuffer(sock_fd, to_write);
    if (nbytes == -1) {
        LogConcat(1, "Duplex", "failed to read: ", strerror(errno));
        Destroy();
        return;
    }

    if (gcc_likely(nbytes > 0)) {
        write_event.Add();
        if (!to_write.IsFull())
            socket_read_event.Add();
    } else {
        sock_eof = true;
        CheckDestroy();
    }
}

inline void
Duplex::SocketWriteEventCallback(unsigned)
{
    ssize_t nbytes = SendFromBuffer(sock_fd, from_read);
    if (nbytes == -1) {
        Destroy();
        return;
    }

    if (nbytes > 0 && read_fd >= 0)
        read_event.Add();

    if (!from_read.empty())
        socket_write_event.Add();
}

int
duplex_new(EventLoop &event_loop, struct pool *pool, int read_fd, int write_fd)
{
    assert(pool != nullptr);
    assert(read_fd >= 0);
    assert(write_fd >= 0);

    UniqueSocketDescriptor result_fd, duplex_fd;
    if (!UniqueSocketDescriptor::CreateSocketPairNonBlock(AF_LOCAL, SOCK_STREAM, 0,
                                                          result_fd, duplex_fd))
        return -1;

    NewFromPool<Duplex>(*pool, event_loop, read_fd, write_fd,
                        duplex_fd.Steal());
    return result_fd.Steal();
}
<|endoftext|>


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

#include "WNFileSystem/inc/WNFactory.h"
#include "WNFileSystem/src/WNMemoryBackedMapping.h"
#include "WNFileSystem/src/WNSystemMapping.h"
#include "WNFileSystem/src/WNSystemPaths.h"
#include "WNFileSystem/src/WNSystemUtilities.h"
#include "WNFileSystem/src/WNUtilities.h"

namespace wn {
namespace file_system {

containers::string factory::get_executable_path() const {
  return internal::get_executable_path(m_allocator, m_system_data);
}

containers::string factory::get_current_working_path() const {
  return internal::get_current_working_path(m_allocator, m_system_data);
}

mapping_ptr factory::make_mapping(
    memory::allocator* _allocator, const mapping_type _mapping_type) const {
  if (!_allocator) {
    return nullptr;
  }

  switch (_mapping_type) {
    case mapping_type::memory_backed:
      return memory::make_unique<memory_backed_mapping>(_allocator, _allocator);
    case mapping_type::scratch_directory: {
      containers::string path(
          internal::get_scratch_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), true);
      }

      break;
    }
    case mapping_type::executable_directory: {
      containers::string path(
          internal::get_executable_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), false);
      }

      break;
    }
    case mapping_type::current_working_directory: {
      containers::string path(
          internal::get_current_working_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), false);
      }
    }
    case mapping_type::development_assets: {
      containers::string path(
          internal::get_dev_assets_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), true);
      }
      break;
    }
    default:
      break;
  }

  return nullptr;
}

mapping_ptr factory::make_mapping(
    memory::allocator* _allocator, containers::string&& _path) const {
  internal::sanitize_path(_path);

  if (!_path.empty() && internal::exists_directory(_path)) {
    return memory::make_unique<internal::system_mapping>(
        _allocator, _allocator, core::move(_path), false);
  }

  return nullptr;
}

}  // namespace file_system
}  // namespace wn
<commit_msg>Fix a bug in file-systems where it was deleting the assets dir.<commit_after>// Copyright (c) 2017, WNProject Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.txt file.

#include "WNFileSystem/inc/WNFactory.h"
#include "WNFileSystem/src/WNMemoryBackedMapping.h"
#include "WNFileSystem/src/WNSystemMapping.h"
#include "WNFileSystem/src/WNSystemPaths.h"
#include "WNFileSystem/src/WNSystemUtilities.h"
#include "WNFileSystem/src/WNUtilities.h"

namespace wn {
namespace file_system {

containers::string factory::get_executable_path() const {
  return internal::get_executable_path(m_allocator, m_system_data);
}

containers::string factory::get_current_working_path() const {
  return internal::get_current_working_path(m_allocator, m_system_data);
}

mapping_ptr factory::make_mapping(
    memory::allocator* _allocator, const mapping_type _mapping_type) const {
  if (!_allocator) {
    return nullptr;
  }

  switch (_mapping_type) {
    case mapping_type::memory_backed:
      return memory::make_unique<memory_backed_mapping>(_allocator, _allocator);
    case mapping_type::scratch_directory: {
      containers::string path(
          internal::get_scratch_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), true);
      }

      break;
    }
    case mapping_type::executable_directory: {
      containers::string path(
          internal::get_executable_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), false);
      }

      break;
    }
    case mapping_type::current_working_directory: {
      containers::string path(
          internal::get_current_working_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), false);
      }
    }
    case mapping_type::development_assets: {
      containers::string path(
          internal::get_dev_assets_path(_allocator, m_system_data));

      if (!path.empty()) {
        return memory::make_unique<internal::system_mapping>(
            _allocator, _allocator, core::move(path), false);
      }
      break;
    }
    default:
      break;
  }

  return nullptr;
}

mapping_ptr factory::make_mapping(
    memory::allocator* _allocator, containers::string&& _path) const {
  internal::sanitize_path(_path);

  if (!_path.empty() && internal::exists_directory(_path)) {
    return memory::make_unique<internal::system_mapping>(
        _allocator, _allocator, core::move(_path), false);
  }

  return nullptr;
}

}  // namespace file_system
}  // namespace wn
<|endoftext|>


<commit_before>/*********************************************************************
 *
 * Copyright 2013 Intel Corporation
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************************/

#define WAFFLE_API_EXPERIMENTAL
#define WAFFLE_API_VERSION 0x0103

#include <string.h>

#include <iostream>

#include "waffle.h"
#include "glws.hpp"

namespace glws {

struct waffle_display *dpy;

class WaffleVisual : public Visual
{
public:
    struct waffle_config *config;

    WaffleVisual(Profile prof, waffle_config *cfg) :
        Visual(prof),
        config (cfg)
    {}

    ~WaffleVisual() {
        if (this->config != NULL) {
            waffle_config_destroy(this->config);
            this->config = NULL;
        }
    }
};

class WaffleDrawable : public Drawable
{
public:
    struct waffle_window *window;

    WaffleDrawable(const Visual *vis, int w, int h, bool pbuffer,
        struct waffle_window *win) :
        Drawable (vis, w, h, pbuffer),
        window (win)
    {}

    void
    resize(int w, int h) {
        if (w == width && h == height) {
            return;
        }
        waffle_window_resize(window, w, h);
        Drawable::resize(w, h);
    }

    void
    show(void) {
        if (visible) {
            return;
        }
        waffle_window_show(window);
        Drawable::show();
    }

    void
    swapBuffers(void) {
        waffle_window_swap_buffers(window);
    }
};

class WaffleContext : public Context
{
public:
    struct waffle_context *context;

    WaffleContext(const Visual *vis, struct waffle_context *ctx) :
        Context(vis),
        context(ctx)
    {}

    ~WaffleContext() {
        if( context != NULL ) {
            waffle_context_destroy(context);
            context = NULL;
        }
    }
};

/*
 With waffle there is not too many events to look for..
 */
bool
processEvents(void) {
    return true;
}

void
init(void)
{
    int32_t waffle_platform;;

#if defined(__ANDROID__)
    waffle_platform = WAFFLE_PLATFORM_ANDROID;
#elif defined(__APPLE__)
    waffle_platform = WAFFLE_PLATFORM_CGL
#elif defined(_WIN32)
    waffle_platform = WAFFLE_PLATFORM_WGL
#else
    waffle_platform = WAFFLE_PLATFORM_GLX;

    const char *waffle_platform_name = getenv("WAFFLE_PLATFORM");
    if (waffle_platform_name) {
        if (strcmp(waffle_platform_name, "gbm") == 0) {
            waffle_platform = WAFFLE_PLATFORM_GBM;
        } else if (strcmp(waffle_platform_name, "glx") == 0) {
            waffle_platform = WAFFLE_PLATFORM_GLX;
        } else if (strcmp(waffle_platform_name, "wayland") == 0) {
            waffle_platform = WAFFLE_PLATFORM_WAYLAND;
        } else if (strcmp(waffle_platform_name, "x11_egl") == 0) {
            waffle_platform = WAFFLE_PLATFORM_X11_EGL;
        } else {
            std::cerr << "error: unsupported WAFFLE_PLATFORM \"" << waffle_platform_name << "\"\n";
            exit(1);
        }
    }
#endif

    Attributes<int32_t> waffle_init_attrib_list;
    waffle_init_attrib_list.add(WAFFLE_PLATFORM, waffle_platform);
    waffle_init_attrib_list.end(WAFFLE_NONE);

    waffle_init(waffle_init_attrib_list);

    dpy = waffle_display_connect(NULL);
    if (!dpy) {
        std::cerr << "error: waffle_display_connect failed\n";
        exit(1);
    }
}

void
cleanup(void) {
    waffle_display_disconnect(dpy);
}

Visual *
createVisual(bool doubleBuffer, unsigned samples, Profile profile) {
    struct waffle_config *cfg;

    int waffle_api;
    if (profile.api == glprofile::API_GL) {
        waffle_api = WAFFLE_CONTEXT_OPENGL;
    } else if (profile.api == glprofile::API_GLES) {
        switch (profile.major) {
        case 1:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES1;
            break;
        case 2:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES2;
            break;
        case 3:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES3;
            break;
        default:
            std::cerr << "error: unsupported context profile " << profile << "\n";
            exit(1);
            return NULL;
        }
    } else {
        assert(0);
        return NULL;
    }

    if (!waffle_display_supports_context_api(dpy, waffle_api)) {
        std::cerr << "error: waffle_display_supports_context_api failed \n";
        exit(1);
        return NULL;
    }

    Attributes<int32_t> config_attrib_list;
    config_attrib_list.add(WAFFLE_CONTEXT_API, waffle_api);
    if (profile.api == glprofile::API_GL) {
        config_attrib_list.add(WAFFLE_CONTEXT_MAJOR_VERSION, profile.major);
        config_attrib_list.add(WAFFLE_CONTEXT_MINOR_VERSION, profile.minor);
        if (profile.versionGreaterOrEqual(3, 2)) {
            int profileMask = profile.core ? WAFFLE_CONTEXT_CORE_PROFILE : WAFFLE_CONTEXT_COMPATIBILITY_PROFILE;
            config_attrib_list.add(WAFFLE_CONTEXT_PROFILE, profileMask);
        }
        if (profile.forwardCompatible) {
            config_attrib_list.add(WAFFLE_CONTEXT_FORWARD_COMPATIBLE, true);
        }
    }
    config_attrib_list.add(WAFFLE_RED_SIZE, 8);
    config_attrib_list.add(WAFFLE_GREEN_SIZE, 8);
    config_attrib_list.add(WAFFLE_BLUE_SIZE, 8);
    config_attrib_list.add(WAFFLE_DEPTH_SIZE, 8);
    config_attrib_list.add(WAFFLE_ALPHA_SIZE, 8);
    config_attrib_list.add(WAFFLE_STENCIL_SIZE, 8);
    config_attrib_list.add(WAFFLE_DOUBLE_BUFFERED, doubleBuffer);
    if (0) {
        config_attrib_list.add(WAFFLE_CONTEXT_DEBUG, true);
    }
    config_attrib_list.end();

    cfg = waffle_config_choose(dpy, config_attrib_list);
    if (!cfg) {
        std::cerr << "error: waffle_config_choose failed\n";
        exit(1);
        return NULL;
    }
    return new WaffleVisual(profile, cfg);
}

Drawable *
createDrawable(const Visual *visual, int width, int height, bool pbuffer)
{
    struct waffle_window *window;
    const WaffleVisual *waffleVisual =
        static_cast<const WaffleVisual *>(visual);

    window = waffle_window_create(waffleVisual->config, width, height);
    return new WaffleDrawable(visual, width, height, pbuffer, window);
}

Context *
createContext(const Visual *visual, Context *shareContext,
              bool debug)
{
    struct waffle_context *context;
    const WaffleVisual *waffleVisual =
        static_cast<const WaffleVisual *>(visual);

    struct waffle_context * share_context = NULL;
    if (shareContext) {
        share_context = static_cast<WaffleContext*>(shareContext)->context;
    }

    context = waffle_context_create(waffleVisual->config, share_context);
    if (!context) {
        std::cerr << "error: waffle_context_create failed\n";
        exit(1);
        return NULL;
    }
    return new WaffleContext(visual, context);
}

bool
makeCurrentInternal(Drawable *drawable, Context *context)
{
    if (!drawable || !context) {
        return waffle_make_current(dpy, NULL, NULL);
    } else {
        WaffleDrawable *waffleDrawable =
            static_cast<WaffleDrawable *>(drawable);

        WaffleContext *waffleContext =
            static_cast<WaffleContext *>(context);

        return waffle_make_current(dpy, waffleDrawable->window,
                                   waffleContext->context);
    }
}

} /* namespace glws */
<commit_msg>glws: Update Waffle support for interface changes.<commit_after>/*********************************************************************
 *
 * Copyright 2013 Intel Corporation
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************************/

#define WAFFLE_API_EXPERIMENTAL
#define WAFFLE_API_VERSION 0x0103

#include <string.h>

#include <iostream>

#include "waffle.h"
#include "glws.hpp"

namespace glws {

struct waffle_display *dpy;

class WaffleVisual : public Visual
{
public:
    struct waffle_config *config;

    WaffleVisual(Profile prof, waffle_config *cfg) :
        Visual(prof),
        config (cfg)
    {}

    ~WaffleVisual() {
        if (this->config != NULL) {
            waffle_config_destroy(this->config);
            this->config = NULL;
        }
    }
};

class WaffleDrawable : public Drawable
{
public:
    struct waffle_window *window;

    WaffleDrawable(const Visual *vis, int w, int h,
        const pbuffer_info *info,
        struct waffle_window *win) :
        Drawable (vis, w, h, info),
        window (win)
    {}

    void
    resize(int w, int h) {
        if (w == width && h == height) {
            return;
        }
        waffle_window_resize(window, w, h);
        Drawable::resize(w, h);
    }

    void
    show(void) {
        if (visible) {
            return;
        }
        waffle_window_show(window);
        Drawable::show();
    }

    void
    swapBuffers(void) {
        waffle_window_swap_buffers(window);
    }
};

class WaffleContext : public Context
{
public:
    struct waffle_context *context;

    WaffleContext(const Visual *vis, struct waffle_context *ctx) :
        Context(vis),
        context(ctx)
    {}

    ~WaffleContext() {
        if( context != NULL ) {
            waffle_context_destroy(context);
            context = NULL;
        }
    }
};

/*
 With waffle there is not too many events to look for..
 */
bool
processEvents(void) {
    return true;
}

void
init(void)
{
    int32_t waffle_platform;;

#if defined(__ANDROID__)
    waffle_platform = WAFFLE_PLATFORM_ANDROID;
#elif defined(__APPLE__)
    waffle_platform = WAFFLE_PLATFORM_CGL
#elif defined(_WIN32)
    waffle_platform = WAFFLE_PLATFORM_WGL
#else
    waffle_platform = WAFFLE_PLATFORM_GLX;

    const char *waffle_platform_name = getenv("WAFFLE_PLATFORM");
    if (waffle_platform_name) {
        if (strcmp(waffle_platform_name, "gbm") == 0) {
            waffle_platform = WAFFLE_PLATFORM_GBM;
        } else if (strcmp(waffle_platform_name, "glx") == 0) {
            waffle_platform = WAFFLE_PLATFORM_GLX;
        } else if (strcmp(waffle_platform_name, "wayland") == 0) {
            waffle_platform = WAFFLE_PLATFORM_WAYLAND;
        } else if (strcmp(waffle_platform_name, "x11_egl") == 0) {
            waffle_platform = WAFFLE_PLATFORM_X11_EGL;
        } else {
            std::cerr << "error: unsupported WAFFLE_PLATFORM \"" << waffle_platform_name << "\"\n";
            exit(1);
        }
    }
#endif

    Attributes<int32_t> waffle_init_attrib_list;
    waffle_init_attrib_list.add(WAFFLE_PLATFORM, waffle_platform);
    waffle_init_attrib_list.end(WAFFLE_NONE);

    waffle_init(waffle_init_attrib_list);

    dpy = waffle_display_connect(NULL);
    if (!dpy) {
        std::cerr << "error: waffle_display_connect failed\n";
        exit(1);
    }
}

void
cleanup(void) {
    waffle_display_disconnect(dpy);
}

Visual *
createVisual(bool doubleBuffer, unsigned samples, Profile profile) {
    struct waffle_config *cfg;

    int waffle_api;
    if (profile.api == glprofile::API_GL) {
        waffle_api = WAFFLE_CONTEXT_OPENGL;
    } else if (profile.api == glprofile::API_GLES) {
        switch (profile.major) {
        case 1:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES1;
            break;
        case 2:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES2;
            break;
        case 3:
            waffle_api = WAFFLE_CONTEXT_OPENGL_ES3;
            break;
        default:
            std::cerr << "error: unsupported context profile " << profile << "\n";
            exit(1);
            return NULL;
        }
    } else {
        assert(0);
        return NULL;
    }

    if (!waffle_display_supports_context_api(dpy, waffle_api)) {
        std::cerr << "error: waffle_display_supports_context_api failed \n";
        exit(1);
        return NULL;
    }

    Attributes<int32_t> config_attrib_list;
    config_attrib_list.add(WAFFLE_CONTEXT_API, waffle_api);
    if (profile.api == glprofile::API_GL) {
        config_attrib_list.add(WAFFLE_CONTEXT_MAJOR_VERSION, profile.major);
        config_attrib_list.add(WAFFLE_CONTEXT_MINOR_VERSION, profile.minor);
        if (profile.versionGreaterOrEqual(3, 2)) {
            int profileMask = profile.core ? WAFFLE_CONTEXT_CORE_PROFILE : WAFFLE_CONTEXT_COMPATIBILITY_PROFILE;
            config_attrib_list.add(WAFFLE_CONTEXT_PROFILE, profileMask);
        }
        if (profile.forwardCompatible) {
            config_attrib_list.add(WAFFLE_CONTEXT_FORWARD_COMPATIBLE, true);
        }
    }
    config_attrib_list.add(WAFFLE_RED_SIZE, 8);
    config_attrib_list.add(WAFFLE_GREEN_SIZE, 8);
    config_attrib_list.add(WAFFLE_BLUE_SIZE, 8);
    config_attrib_list.add(WAFFLE_DEPTH_SIZE, 8);
    config_attrib_list.add(WAFFLE_ALPHA_SIZE, 8);
    config_attrib_list.add(WAFFLE_STENCIL_SIZE, 8);
    config_attrib_list.add(WAFFLE_DOUBLE_BUFFERED, doubleBuffer);
    if (0) {
        config_attrib_list.add(WAFFLE_CONTEXT_DEBUG, true);
    }
    config_attrib_list.end();

    cfg = waffle_config_choose(dpy, config_attrib_list);
    if (!cfg) {
        std::cerr << "error: waffle_config_choose failed\n";
        exit(1);
        return NULL;
    }
    return new WaffleVisual(profile, cfg);
}

Drawable *
createDrawable(const Visual *visual, int width, int height,
               const pbuffer_info *info)
{
    struct waffle_window *window;
    const WaffleVisual *waffleVisual =
        static_cast<const WaffleVisual *>(visual);

    window = waffle_window_create(waffleVisual->config, width, height);
    return new WaffleDrawable(visual, width, height, info, window);
}

Context *
createContext(const Visual *visual, Context *shareContext,
              bool debug)
{
    struct waffle_context *context;
    const WaffleVisual *waffleVisual =
        static_cast<const WaffleVisual *>(visual);

    struct waffle_context * share_context = NULL;
    if (shareContext) {
        share_context = static_cast<WaffleContext*>(shareContext)->context;
    }

    context = waffle_context_create(waffleVisual->config, share_context);
    if (!context) {
        std::cerr << "error: waffle_context_create failed\n";
        exit(1);
        return NULL;
    }
    return new WaffleContext(visual, context);
}

bool
makeCurrentInternal(Drawable *drawable, Context *context)
{
    if (!drawable || !context) {
        return waffle_make_current(dpy, NULL, NULL);
    } else {
        WaffleDrawable *waffleDrawable =
            static_cast<WaffleDrawable *>(drawable);

        WaffleContext *waffleContext =
            static_cast<WaffleContext *>(context);

        return waffle_make_current(dpy, waffleDrawable->window,
                                   waffleContext->context);
    }
}

bool
bindTexImage(Drawable *pBuffer, int iBuffer) {
    std::cerr << "error: Waffle::wglBindTexImageARB not implemented.\n";
    assert(pBuffer->pbuffer);
    return true;
}

bool
releaseTexImage(Drawable *pBuffer, int iBuffer) {
    std::cerr << "error: Waffle::wglReleaseTexImageARB not implemented.\n";
    assert(pBuffer->pbuffer);
    return true;
}

bool
setPbufferAttrib(Drawable *pBuffer, const int *attribList) {
    // nothing to do here.
    assert(pBuffer->pbuffer);
    return true;
}

} /* namespace glws */
<|endoftext|>


<commit_before>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
// Boost
#include <boost/make_shared.hpp>
// StdAir
#include <stdair/basic/BasConst_General.hpp>
#include <stdair/basic/BasConst_Event.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/bom/EventStruct.hpp>

namespace stdair {

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct()
    : _eventType (EventType::BKG_REQ), _eventTimeStamp (0),
      _demandStreamKeyStr(), _specificProgressStatus(),
      _overallProgressStatus() {
    assert (false);
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct (const EventType::EN_EventType& iEventType,
                            const DemandStreamKeyStr_T& iDemandStreamKey,
                            BookingRequestPtr_T ioRequestPtr)
    : _eventType (iEventType), _demandStreamKeyStr (iDemandStreamKey),
      _specificProgressStatus(), _overallProgressStatus() {

    //
    assert (ioRequestPtr != NULL);
    _request = boost::make_shared<BookingRequestStruct> (*ioRequestPtr);
    assert (_request != NULL);

    // Compute and store the number of seconds between iDateTime and
    // DEFAULT_DATETIME.
    const Duration_T lDuration =
      _request->getRequestDateTime() - DEFAULT_DATETIME;
    _eventTimeStamp = lDuration.total_milliseconds();
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct (const EventStruct& iEventStruct)
    : _eventType (iEventStruct._eventType),
      _eventTimeStamp (iEventStruct._eventTimeStamp),
      _demandStreamKeyStr (iEventStruct._demandStreamKeyStr),
      _specificProgressStatus (iEventStruct._specificProgressStatus),
      _overallProgressStatus (iEventStruct._overallProgressStatus) {

    //
    if (iEventStruct._request != NULL) {
      _request =
        boost::make_shared<BookingRequestStruct> (*iEventStruct._request);
    }
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::~EventStruct() {
  }

  // //////////////////////////////////////////////////////////////////////
  void EventStruct::fromStream (std::istream& ioIn) {
  }

  // //////////////////////////////////////////////////////////////////////
  const std::string EventStruct::describe() const {
    std::ostringstream oStr;
    oStr << "[" << EventType (_eventType)
         << "][" << _overallProgressStatus.getCurrentNb()
         << "/{" << _overallProgressStatus.getExpectedNb()
         << "," << _overallProgressStatus.getActualNb()
         << "}][" << _specificProgressStatus.getCurrentNb()
         << "/{" << _specificProgressStatus.getExpectedNb()
         << "," << _specificProgressStatus.getActualNb()
         << "}] " << _eventTimeStamp;

    switch (_eventType) {
    case EventType::BKG_REQ: {
      assert (_request != NULL);
      oStr << ", " << _demandStreamKeyStr << ", " << _request->describe();
    }
    default: {
    }
    }

    return oStr.str();
  }

}
<commit_msg>[StdAir][Dev] Improved the description of the EventStruct key.<commit_after>// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <cassert>
// Boost
#include <boost/make_shared.hpp>
// StdAir
#include <stdair/basic/BasConst_General.hpp>
#include <stdair/basic/BasConst_Event.hpp>
#include <stdair/bom/BookingRequestStruct.hpp>
#include <stdair/bom/EventStruct.hpp>

namespace stdair {

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct()
    : _eventType (EventType::BKG_REQ), _eventTimeStamp (0),
      _demandStreamKeyStr(), _specificProgressStatus(),
      _overallProgressStatus() {
    assert (false);
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct (const EventType::EN_EventType& iEventType,
                            const DemandStreamKeyStr_T& iDemandStreamKey,
                            BookingRequestPtr_T ioRequestPtr)
    : _eventType (iEventType), _demandStreamKeyStr (iDemandStreamKey),
      _specificProgressStatus(), _overallProgressStatus() {

    //
    assert (ioRequestPtr != NULL);
    _request = boost::make_shared<BookingRequestStruct> (*ioRequestPtr);
    assert (_request != NULL);

    // Compute and store the number of milliseconds between the
    // date-time of the booking request and DEFAULT_DATETIME (as of
    // Feb. 2011, that date is set to Jan. 1, 2010).
    const Duration_T lDuration =
      _request->getRequestDateTime() - DEFAULT_DATETIME;
    _eventTimeStamp = lDuration.total_milliseconds();
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::EventStruct (const EventStruct& iEventStruct)
    : _eventType (iEventStruct._eventType),
      _eventTimeStamp (iEventStruct._eventTimeStamp),
      _demandStreamKeyStr (iEventStruct._demandStreamKeyStr),
      _specificProgressStatus (iEventStruct._specificProgressStatus),
      _overallProgressStatus (iEventStruct._overallProgressStatus) {

    //
    if (iEventStruct._request != NULL) {
      _request =
        boost::make_shared<BookingRequestStruct> (*iEventStruct._request);
    }
  }

  // //////////////////////////////////////////////////////////////////////
  EventStruct::~EventStruct() {
  }

  // //////////////////////////////////////////////////////////////////////
  void EventStruct::fromStream (std::istream& ioIn) {
  }

  // //////////////////////////////////////////////////////////////////////
  const std::string EventStruct::describe() const {
    std::ostringstream oStr;
    oStr << "[" << EventType (_eventType)
         << "][" << _overallProgressStatus.getCurrentNb()
         << "/{" << _overallProgressStatus.getExpectedNb()
         << "," << _overallProgressStatus.getActualNb()
         << "}][" << _specificProgressStatus.getCurrentNb()
         << "/{" << _specificProgressStatus.getExpectedNb()
         << "," << _specificProgressStatus.getActualNb()
         << "}] ";

    const Duration_T lRequestDateDelta (0, 0, 0, _eventTimeStamp);
    const DateTime_T lRequestDate (DEFAULT_DATETIME + lRequestDateDelta);
    oStr << lRequestDate;

    switch (_eventType) {
    case EventType::BKG_REQ: {
      assert (_request != NULL);
      oStr << ", " << _demandStreamKeyStr << ", " << _request->describe();
    }
    default: {
    }
    }

    return oStr.str();
  }

}
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>

#include <nan.h>
#include <stdlib.h>

#include "ed25519/ed25519.h"

using namespace v8;
using namespace node;

/**
 * MakeKeypair(Buffer seed)
 * seed: A 32 byte buffer
 * returns: an Object with PublicKey and PrivateKey
 **/
NAN_METHOD(MakeKeypair) {
	NanScope();
	if ((args.Length() < 1) || (!Buffer::HasInstance(args[0])) || (Buffer::Length(args[0]->ToObject()) != 32)) {
		return NanThrowError("MakeKeypair requires a 32 byte buffer");
	}
	const unsigned char* seed = (unsigned char*)Buffer::Data(args[0]->ToObject());

	v8::Local<v8::Object> privateKey = NanNewBufferHandle(64);

	unsigned char* privateKeyData = (unsigned char*)Buffer::Data(privateKey);

	v8::Local<v8::Object> publicKey = NanNewBufferHandle(32);
	unsigned char* publicKeyData = (unsigned char*)Buffer::Data(publicKey);
	for (int i = 0; i < 32; i++)
		privateKeyData[i] = seed[i];
	crypto_sign_keypair(publicKeyData, privateKeyData);

	Local<Object> result = NanNew<Object>();
	result->Set(NanNew("publicKey"), publicKey);
	result->Set(NanNew("privateKey"), privateKey);
	NanReturnValue(result);
}

/**
 * Sign(Buffer message, Buffer seed)
 * Sign(Buffer message, Buffer privateKey)
 * Sign(Buffer message, Object keyPair)
 * message: the message to be signed
 * seed: 32 byte buffer to make a keypair
 * keyPair: the object from the MakeKeypair function
 * returns: the signature as a Buffer
 **/
NAN_METHOD(Sign) {
	NanScope();
	if ((args.Length() < 2) || (!Buffer::HasInstance(args[0]->ToObject()))) {
		return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
	}
	unsigned char* privateKey;
	if ((Buffer::HasInstance(args[1])) && (Buffer::Length(args[1]->ToObject()) == 32)) {
		unsigned char* seed = (unsigned char*)Buffer::Data(args[1]->ToObject());
		unsigned char publicKeyData[32];
		unsigned char privateKeyData[64];
		for (int i = 0; i < 32; i++) {
			privateKeyData[i] = seed[i];
		}
		crypto_sign_keypair(publicKeyData, privateKeyData);
		privateKey = privateKeyData;
	} else if ((Buffer::HasInstance(args[1])) && (Buffer::Length(args[1]->ToObject()) == 64)) {
		privateKey = (unsigned char*)Buffer::Data(args[1]->ToObject());
	} else if ((args[1]->IsObject()) && (!Buffer::HasInstance(args[1]))) {
		Handle<Object> privateKeyBuffer = args[1]->ToObject()->Get(NanNew<String>("privateKey"))->ToObject();
		if (!Buffer::HasInstance(privateKeyBuffer)) {
			return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
		}
		privateKey = (unsigned char*)Buffer::Data(privateKeyBuffer);
	} else {
		return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
	}
	Handle<Object> message = args[0]->ToObject();
	const unsigned char* messageData = (unsigned char*)Buffer::Data(message);
	size_t messageLen = Buffer::Length(message);
	unsigned long long sigLen = 64 + messageLen;
	unsigned char *signatureMessageData = (unsigned char*) malloc(sigLen);
	crypto_sign(signatureMessageData, &sigLen, messageData, messageLen, privateKey);

	v8::Local<v8::Object> signature = NanNewBufferHandle(64);
	unsigned char* signatureData = (unsigned char*)Buffer::Data(signature);
	for (int i = 0; i < 64; i++) {
		signatureData[i] = signatureMessageData[i];
	}
	free(signatureMessageData);
	NanReturnValue(signature);
}

/**
 * Verify(Buffer message, Buffer signature, Buffer publicKey)
 * message: message the signature is for
 * signature: signature to be verified
 * publicKey: publicKey to the private key that created the signature
 * returns: boolean
 **/
NAN_METHOD(Verify) {
	NanScope();
	if ((args.Length() < 3) || (!Buffer::HasInstance(args[0]->ToObject())) ||
		(!Buffer::HasInstance(args[1]->ToObject())) || (!Buffer::HasInstance(args[2]->ToObject()))) {
		return NanThrowError("Verify requires (Buffer, Buffer(64), Buffer(32)");
	}
	Handle<Object> message = args[0]->ToObject();
	Handle<Object> signature = args[1]->ToObject();
	Handle<Object> publicKey = args[2]->ToObject();
	if ((Buffer::Length(signature) != 64) || (Buffer::Length(publicKey) != 32)) {
		return NanThrowError("Verify requires (Buffer, Buffer(64), Buffer(32)");
	}
	unsigned char* messageData = (unsigned char*)Buffer::Data(message);
	size_t messageLen = Buffer::Length(message);
	unsigned char* signatureData = (unsigned char*)Buffer::Data(signature);
	unsigned char* publicKeyData = (unsigned char*)Buffer::Data(publicKey);

	NanReturnValue(NanNew(crypto_sign_verify(signatureData, messageData, messageLen, publicKeyData) == 0));
}

void InitModule(Handle<Object> exports) {
	exports->Set(NanNew("MakeKeypair"), NanNew<FunctionTemplate>(MakeKeypair)->GetFunction());
	exports->Set(NanNew("Sign"), NanNew<FunctionTemplate>(Sign)->GetFunction());
	exports->Set(NanNew("Verify"), NanNew<FunctionTemplate>(Verify)->GetFunction());
}

NODE_MODULE(native, InitModule)

<commit_msg>changed module name to match bindings.gyp<commit_after>#include <node.h>
#include <node_buffer.h>

#include <nan.h>
#include <stdlib.h>

#include "ed25519/ed25519.h"

using namespace v8;
using namespace node;

/**
 * MakeKeypair(Buffer seed)
 * seed: A 32 byte buffer
 * returns: an Object with PublicKey and PrivateKey
 **/
NAN_METHOD(MakeKeypair) {
	NanScope();
	if ((args.Length() < 1) || (!Buffer::HasInstance(args[0])) || (Buffer::Length(args[0]->ToObject()) != 32)) {
		return NanThrowError("MakeKeypair requires a 32 byte buffer");
	}
	const unsigned char* seed = (unsigned char*)Buffer::Data(args[0]->ToObject());

	v8::Local<v8::Object> privateKey = NanNewBufferHandle(64);

	unsigned char* privateKeyData = (unsigned char*)Buffer::Data(privateKey);

	v8::Local<v8::Object> publicKey = NanNewBufferHandle(32);
	unsigned char* publicKeyData = (unsigned char*)Buffer::Data(publicKey);
	for (int i = 0; i < 32; i++)
		privateKeyData[i] = seed[i];
	crypto_sign_keypair(publicKeyData, privateKeyData);

	Local<Object> result = NanNew<Object>();
	result->Set(NanNew("publicKey"), publicKey);
	result->Set(NanNew("privateKey"), privateKey);
	NanReturnValue(result);
}

/**
 * Sign(Buffer message, Buffer seed)
 * Sign(Buffer message, Buffer privateKey)
 * Sign(Buffer message, Object keyPair)
 * message: the message to be signed
 * seed: 32 byte buffer to make a keypair
 * keyPair: the object from the MakeKeypair function
 * returns: the signature as a Buffer
 **/
NAN_METHOD(Sign) {
	NanScope();
	if ((args.Length() < 2) || (!Buffer::HasInstance(args[0]->ToObject()))) {
		return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
	}
	unsigned char* privateKey;
	if ((Buffer::HasInstance(args[1])) && (Buffer::Length(args[1]->ToObject()) == 32)) {
		unsigned char* seed = (unsigned char*)Buffer::Data(args[1]->ToObject());
		unsigned char publicKeyData[32];
		unsigned char privateKeyData[64];
		for (int i = 0; i < 32; i++) {
			privateKeyData[i] = seed[i];
		}
		crypto_sign_keypair(publicKeyData, privateKeyData);
		privateKey = privateKeyData;
	} else if ((Buffer::HasInstance(args[1])) && (Buffer::Length(args[1]->ToObject()) == 64)) {
		privateKey = (unsigned char*)Buffer::Data(args[1]->ToObject());
	} else if ((args[1]->IsObject()) && (!Buffer::HasInstance(args[1]))) {
		Handle<Object> privateKeyBuffer = args[1]->ToObject()->Get(NanNew<String>("privateKey"))->ToObject();
		if (!Buffer::HasInstance(privateKeyBuffer)) {
			return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
		}
		privateKey = (unsigned char*)Buffer::Data(privateKeyBuffer);
	} else {
		return NanThrowError("Sign requires (Buffer, {Buffer(32 or 64) | keyPair object})");
	}
	Handle<Object> message = args[0]->ToObject();
	const unsigned char* messageData = (unsigned char*)Buffer::Data(message);
	size_t messageLen = Buffer::Length(message);
	unsigned long long sigLen = 64 + messageLen;
	unsigned char *signatureMessageData = (unsigned char*) malloc(sigLen);
	crypto_sign(signatureMessageData, &sigLen, messageData, messageLen, privateKey);

	v8::Local<v8::Object> signature = NanNewBufferHandle(64);
	unsigned char* signatureData = (unsigned char*)Buffer::Data(signature);
	for (int i = 0; i < 64; i++) {
		signatureData[i] = signatureMessageData[i];
	}
	free(signatureMessageData);
	NanReturnValue(signature);
}

/**
 * Verify(Buffer message, Buffer signature, Buffer publicKey)
 * message: message the signature is for
 * signature: signature to be verified
 * publicKey: publicKey to the private key that created the signature
 * returns: boolean
 **/
NAN_METHOD(Verify) {
	NanScope();
	if ((args.Length() < 3) || (!Buffer::HasInstance(args[0]->ToObject())) ||
		(!Buffer::HasInstance(args[1]->ToObject())) || (!Buffer::HasInstance(args[2]->ToObject()))) {
		return NanThrowError("Verify requires (Buffer, Buffer(64), Buffer(32)");
	}
	Handle<Object> message = args[0]->ToObject();
	Handle<Object> signature = args[1]->ToObject();
	Handle<Object> publicKey = args[2]->ToObject();
	if ((Buffer::Length(signature) != 64) || (Buffer::Length(publicKey) != 32)) {
		return NanThrowError("Verify requires (Buffer, Buffer(64), Buffer(32)");
	}
	unsigned char* messageData = (unsigned char*)Buffer::Data(message);
	size_t messageLen = Buffer::Length(message);
	unsigned char* signatureData = (unsigned char*)Buffer::Data(signature);
	unsigned char* publicKeyData = (unsigned char*)Buffer::Data(publicKey);

	NanReturnValue(NanNew(crypto_sign_verify(signatureData, messageData, messageLen, publicKeyData) == 0));
}

void InitModule(Handle<Object> exports) {
	exports->Set(NanNew("MakeKeypair"), NanNew<FunctionTemplate>(MakeKeypair)->GetFunction());
	exports->Set(NanNew("Sign"), NanNew<FunctionTemplate>(Sign)->GetFunction());
	exports->Set(NanNew("Verify"), NanNew<FunctionTemplate>(Verify)->GetFunction());
}

NODE_MODULE(ed25519, InitModule)
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLFBOMultiRenderTarget.h"
#include "OgreGLPixelFormat.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreRoot.h"
#include "OgreGLHardwarePixelBuffer.h"

namespace Ogre {

	GLFBOMultiRenderTarget::GLFBOMultiRenderTarget(GLFBOManager *manager, const String &name):
		MultiRenderTarget(name),
		fbo(manager, 0 /* TODO: multisampling on MRTs? */)
	{
	}
	GLFBOMultiRenderTarget::~GLFBOMultiRenderTarget()
	{
	}

	void GLFBOMultiRenderTarget::bindSurfaceImpl(size_t attachment, RenderTexture *target)

	{

		/// Check if the render target is in the rendertarget->FBO map
        GLFrameBufferObject *fbobj = 0;
        target->getCustomAttribute(GLRenderTexture::CustomAttributeString_FBO, &fbobj);
		assert(fbobj);
		fbo.bindSurface(attachment, fbobj->getSurface(0));

		// Initialise?

		// Set width and height

		mWidth = fbo.getWidth();

		mHeight = fbo.getHeight();

	}

	void GLFBOMultiRenderTarget::unbindSurfaceImpl(size_t attachment)
	{
		fbo.unbindSurface(attachment);

		// Set width and height

		mWidth = fbo.getWidth();

		mHeight = fbo.getHeight();
	}

	void GLFBOMultiRenderTarget::getCustomAttribute( const String& name, void *pData )
	{
		if( name == GLRenderTexture::CustomAttributeString_FBO )
        {
            *static_cast<GLFrameBufferObject **>(pData) = &fbo;
        }
	}
	//-----------------------------------------------------------------------------
	bool GLFBOMultiRenderTarget::attachDepthBuffer( DepthBuffer *depthBuffer )
	{
		bool result;
		if( (result = MultiRenderTarget::attachDepthBuffer( depthBuffer )) )
			fbo.attachDepthBuffer( depthBuffer );

		return result;
	}
	//-----------------------------------------------------------------------------
	void GLFBOMultiRenderTarget::detachDepthBuffer()
	{
		fbo.detachDepthBuffer();
		MultiRenderTarget::detachDepthBuffer();
	}
	//-----------------------------------------------------------------------------
	void GLFBOMultiRenderTarget::_detachDepthBuffer()
	{
		fbo.detachDepthBuffer();
		MultiRenderTarget::_detachDepthBuffer();
	}
}
<commit_msg>Clean a little bit of whitespace.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLFBOMultiRenderTarget.h"
#include "OgreGLPixelFormat.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreRoot.h"
#include "OgreGLHardwarePixelBuffer.h"

namespace Ogre {

	GLFBOMultiRenderTarget::GLFBOMultiRenderTarget(GLFBOManager *manager, const String &name):
		MultiRenderTarget(name),
		fbo(manager, 0 /* TODO: multisampling on MRTs? */)
	{
	}

	GLFBOMultiRenderTarget::~GLFBOMultiRenderTarget()
	{
	}

	void GLFBOMultiRenderTarget::bindSurfaceImpl(size_t attachment, RenderTexture *target)
	{
		/// Check if the render target is in the rendertarget->FBO map
        GLFrameBufferObject *fbobj = 0;
        target->getCustomAttribute(GLRenderTexture::CustomAttributeString_FBO, &fbobj);
		assert(fbobj);
		fbo.bindSurface(attachment, fbobj->getSurface(0));

		// Set width and height
		mWidth = fbo.getWidth();
		mHeight = fbo.getHeight();
	}

	void GLFBOMultiRenderTarget::unbindSurfaceImpl(size_t attachment)
	{
		fbo.unbindSurface(attachment);

		// Set width and height
		mWidth = fbo.getWidth();
		mHeight = fbo.getHeight();
	}

	void GLFBOMultiRenderTarget::getCustomAttribute( const String& name, void *pData )
	{
		if( name == GLRenderTexture::CustomAttributeString_FBO )
        {
            *static_cast<GLFrameBufferObject **>(pData) = &fbo;
        }
	}
	//-----------------------------------------------------------------------------
	bool GLFBOMultiRenderTarget::attachDepthBuffer( DepthBuffer *depthBuffer )
	{
		bool result;
		if( (result = MultiRenderTarget::attachDepthBuffer( depthBuffer )) )
			fbo.attachDepthBuffer( depthBuffer );

		return result;
	}
	//-----------------------------------------------------------------------------
	void GLFBOMultiRenderTarget::detachDepthBuffer()
	{
		fbo.detachDepthBuffer();
		MultiRenderTarget::detachDepthBuffer();
	}
	//-----------------------------------------------------------------------------
	void GLFBOMultiRenderTarget::_detachDepthBuffer()
	{
		fbo.detachDepthBuffer();
		MultiRenderTarget::_detachDepthBuffer();
	}
}
<|endoftext|>