<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: dp_gui_extensioncmdqueue.hxx,v $
 *
 * $Revision: 1.2 $
 *
 * 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 INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX
#define INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include "com/sun/star/uno/Reference.hxx"
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include "com/sun/star/uno/Sequence.hxx"
#endif
#ifndef _RTL_REF_HXX_
#include "rtl/ref.hxx"
#endif

/// @HTML

namespace com { namespace sun { namespace star {
    namespace deployment { class XPackageManager; }
    namespace uno { class XComponentContext; }
} } }

namespace dp_gui {

class ExtMgrDialog;
class TheExtensionManager;

/**
   Manages installing of extensions in the GUI mode. Requests for installing
   Extensions can be asynchronous. For example, the Extension Manager is running
   in an office process and someone uses the system integration to install an Extension.
   That is, the user double clicks an extension symbol in a file browser, which then
   causes an invocation of "unopkg gui ext". When at that time the Extension Manager
   already performs a task, triggered by the user (for example, add, update, disable,
   enable) then adding of the extension will be postponed until the user has finished
   the task.

   This class also ensures that the extensions are not installed in the main thread.
   Doing so would cause a deadlock because of the progress bar which needs to be constantly
   updated.
*/
class ExtensionCmdQueue {

public:
    /**
       Create an instance.
    */
    ExtensionCmdQueue( ExtMgrDialog * pDialog,
                       TheExtensionManager *pManager,
                       const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & rContext);

    ~ExtensionCmdQueue();

    /**
    */
    void addExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                       const ::rtl::OUString &rExtensionURL,
                       const bool bWarnUser );
    void removeExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage );
    void enableExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage,
                          const bool bEnable );
    void checkForUpdates( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > > &rPackageManagers );
    void checkForUpdate( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                         const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage );
    /**
       This call does not block. It signals the internal thread
       that it should install the remaining extensions and then terminate.
    */
    void stop();

    /** Determines if thread of this class has terminated.
    */
    bool hasTerminated();

    /** Blocks until the thread has terminated. All URLs in the queue will be processed.
    */
    void stopAndWait();

private:
    ExtensionCmdQueue(ExtensionCmdQueue &); // not defined
    void operator =(ExtensionCmdQueue &); // not defined

    class Thread;

    rtl::Reference< Thread > m_thread;
};

}

#endif
<commit_msg>INTEGRATION: CWS extmgrui05 (1.2.52); FILE MERGED 2008/07/01 10:14:09 dv 1.2.52.1: #i91241# Don't allow termination, when ExtMgr is working<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: dp_gui_extensioncmdqueue.hxx,v $
 *
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX
#define INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX

#ifndef _SAL_CONFIG_H_
#include "sal/config.h"
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include "com/sun/star/uno/Reference.hxx"
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include "com/sun/star/uno/Sequence.hxx"
#endif
#ifndef _RTL_REF_HXX_
#include "rtl/ref.hxx"
#endif

/// @HTML

namespace com { namespace sun { namespace star {
    namespace deployment { class XPackageManager; }
    namespace uno { class XComponentContext; }
} } }

namespace dp_gui {

class ExtMgrDialog;
class TheExtensionManager;

/**
   Manages installing of extensions in the GUI mode. Requests for installing
   Extensions can be asynchronous. For example, the Extension Manager is running
   in an office process and someone uses the system integration to install an Extension.
   That is, the user double clicks an extension symbol in a file browser, which then
   causes an invocation of "unopkg gui ext". When at that time the Extension Manager
   already performs a task, triggered by the user (for example, add, update, disable,
   enable) then adding of the extension will be postponed until the user has finished
   the task.

   This class also ensures that the extensions are not installed in the main thread.
   Doing so would cause a deadlock because of the progress bar which needs to be constantly
   updated.
*/
class ExtensionCmdQueue {

public:
    /**
       Create an instance.
    */
    ExtensionCmdQueue( ExtMgrDialog * pDialog,
                       TheExtensionManager *pManager,
                       const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & rContext);

    ~ExtensionCmdQueue();

    /**
    */
    void addExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                       const ::rtl::OUString &rExtensionURL,
                       const bool bWarnUser );
    void removeExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                          const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage );
    void enableExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage,
                          const bool bEnable );
    void checkForUpdates( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > > &rPackageManagers );
    void checkForUpdate( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackageManager > &rPackageManager,
                         const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage );
    /**
       This call does not block. It signals the internal thread
       that it should install the remaining extensions and then terminate.
    */
    void stop();

    /** Determines if thread of this class has terminated.
    */
    bool hasTerminated();

    /** Blocks until the thread has terminated. All URLs in the queue will be processed.
    */
    void stopAndWait();

    bool isBusy();
private:
    ExtensionCmdQueue(ExtensionCmdQueue &); // not defined
    void operator =(ExtensionCmdQueue &); // not defined

    class Thread;

    rtl::Reference< Thread > m_thread;
};

}

#endif
<|endoftext|>


<commit_before>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#include <algorithm>
#ifndef WIN32
    #include <netdb.h>
    #include <sys/socket.h>
#endif
#include "ip.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
#include "rawpdu.h"
#include "utils.h"
#include "constants.h"

using namespace std;

const uint8_t Tins::IP::DEFAULT_TTL = 128;

Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(Constants::IP::PROTO_IP, child) {
    init_ip_fields();
    if(ip_dst.size())
        this->dst_addr(ip_dst);
    if(ip_src.size())
        this->src_addr(ip_src);

}

Tins::IP::IP(const IP &other) : PDU(other) {
    copy_fields(&other);
}

Tins::IP::IP() : PDU(IPPROTO_IP) {
    init_ip_fields();
}

Tins::IP &Tins::IP::operator= (const IP &other) {
    copy_fields(&other);
    copy_inner_pdu(other);
    return *this;
}

Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(Constants::IP::PROTO_IP) {
    static const char *msg("Not enough size for an IP header in the buffer.");
    if(total_sz < sizeof(iphdr))
        throw std::runtime_error(msg);
    std::memcpy(&_ip, buffer, sizeof(iphdr));

    /* Options... */
    /* Establish beginning and ending of the options */
    const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    if(total_sz < head_len() * sizeof(uint32_t))
        throw std::runtime_error(msg);
    buffer += head_len() * sizeof(uint32_t);
    this->_options_size = 0;
    this->_padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr);
    /* While the end of the options is not reached read an option */
    try {
        while (total_sz && ptr_buffer < buffer && (*ptr_buffer != 0)) {
            IPOption opt_to_add;
            opt_to_add.optional_data = 0;
            opt_to_add.optional_data_size = 0;
            memcpy(&opt_to_add.type, ptr_buffer, sizeof(uint8_t));
            ptr_buffer++;
            switch (opt_to_add.type.number) {
                /* Multibyte options with length as second byte */
                case SEC:
                case LSSR:
                case TIMESTAMP:
                case EXTSEC:
                case RR:
                case SID:
                case SSRR:
                case MTUPROBE:
                case MTUREPLY:
                case EIP:
                case TR:
                case ADDEXT:
                case RTRALT:
                case SDB:
                case DPS:
                case UMP:
                case QS:
                    if(!total_sz || *ptr_buffer == 0)
                        throw std::runtime_error(msg);
                    opt_to_add.optional_data_size = *ptr_buffer - 1;
                    if(opt_to_add.optional_data_size > 0) {
                        if(total_sz < opt_to_add.optional_data_size)
                            throw std::runtime_error(msg);
                        opt_to_add.optional_data = new uint8_t[opt_to_add.optional_data_size];
                        memcpy(opt_to_add.optional_data, ptr_buffer, opt_to_add.optional_data_size);
                    }
                    else
                        opt_to_add.optional_data = 0;
                    ptr_buffer += opt_to_add.optional_data_size;
            }
            this->_ip_options.push_back(opt_to_add);
            this->_options_size += 1 + opt_to_add.optional_data_size;
        }
        total_sz -= head_len() * sizeof(uint32_t);
        if (total_sz) {
            switch(_ip.protocol) {
                case IPPROTO_TCP:
                    inner_pdu(new Tins::TCP(buffer, total_sz));
                    break;
                case IPPROTO_UDP:
                    inner_pdu(new Tins::UDP(buffer, total_sz));
                    break;
                case IPPROTO_ICMP:
                    inner_pdu(new Tins::ICMP(buffer, total_sz));
                    break;
                default:
                    inner_pdu(new Tins::RawPDU(buffer, total_sz));
                    break;
            }
        }
    }
    catch(runtime_error &) {
        cleanup();
        throw;
    }
}

Tins::IP::IP(uint32_t ip_dst, uint32_t ip_src, PDU *child) : PDU(Constants::IP::PROTO_IP, child) {
    init_ip_fields();
    this->dst_addr(ip_dst);
    this->src_addr(ip_src);
}

Tins::IP::~IP() {
    cleanup();
}

void Tins::IP::cleanup() {
    for (list<IPOption>::iterator it = _ip_options.begin(); it != _ip_options.end(); it++) {
        delete[] it->optional_data;
    }
}

void Tins::IP::init_ip_fields() {
    memset(&_ip, 0, sizeof(iphdr));
    this->_ip.version = 4;
    this->ttl(DEFAULT_TTL);
    this->id(1);
    this->_options_size = 0;
    this->_padded_options_size = 0;
}

/* Setters */

void Tins::IP::tos(uint8_t new_tos) {
    _ip.tos = new_tos;
}

void Tins::IP::tot_len(uint16_t new_tot_len) {
    _ip.tot_len = Utils::net_to_host_s(new_tot_len);
}

void Tins::IP::id(uint16_t new_id) {
    _ip.id = Utils::net_to_host_s(new_id);
}

void Tins::IP::frag_off(uint16_t new_frag_off) {
    _ip.frag_off = Utils::net_to_host_s(new_frag_off);
}

void Tins::IP::ttl(uint8_t new_ttl) {
    _ip.ttl = new_ttl;
}

void Tins::IP::protocol(uint8_t new_protocol) {
    _ip.protocol = new_protocol;
}

void Tins::IP::check(uint16_t new_check) {
    _ip.check = Utils::net_to_host_s(new_check);
}

void Tins::IP::src_addr(const string &ip) {
    _ip.saddr = Utils::net_to_host_l(Utils::resolve_ip(ip));
}

void Tins::IP::src_addr(uint32_t ip) {
    _ip.saddr = Utils::net_to_host_l(ip);
}

void Tins::IP::dst_addr(const string &ip) {
    _ip.daddr = Utils::net_to_host_l(Utils::resolve_ip(ip));
}

void Tins::IP::dst_addr(uint32_t ip) {
    _ip.daddr = Utils::net_to_host_l(ip);
}

void Tins::IP::head_len(uint8_t new_head_len) {
    _ip.ihl = new_head_len;
}

void Tins::IP::version(uint8_t ver) {
    _ip.version = ver;
}

void Tins::IP::set_eol_option() {
    this->set_option(0, IP::CONTROL, IP::END);
}

void Tins::IP::set_noop_option() {
    this->set_option(0, IP::CONTROL, IP::NOOP);
}

void Tins::IP::set_sec_option(const uint8_t* data, uint32_t data_len) {
    this->set_option(1, IP::CONTROL, IP::SEC, data, data_len);
}

void Tins::IP::set_option(uint8_t copied,
                OptionClass op_class,
                Option number,
                const uint8_t* data,
                uint32_t data_size) {
    IPOption option;
    option.type.copied = copied;
    option.type.op_class = op_class;
    option.type.number = number;
    uint8_t* buffer(0);
    if (data_size) {
        buffer = new uint8_t[data_size];
        memcpy(buffer, data, data_size);
    }
    option.optional_data = buffer;
    option.optional_data_size = data_size;
    _ip_options.push_back(option);
    _options_size += 1 + ((buffer)? (data_size) : 0);
    uint8_t padding = _options_size & 3;
    _padded_options_size = padding? (_options_size - padding + 4) : _options_size;
}

const Tins::IP::IPOption *Tins::IP::search_option(OptionClass opt_class, Option opt_number) const {
    for(std::list<IPOption>::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
        if(it->type.op_class == opt_class && it->type.number == opt_number)
            return &(*it);
    }
    return 0;
}

uint8_t* Tins::IP::IPOption::write(uint8_t* buffer) {
    memcpy(buffer, &type, 1);
    buffer += 1;
    if (optional_data) {
        memcpy(buffer, optional_data, optional_data_size);
        buffer += optional_data_size;
    }
    return buffer;
}

/* Virtual method overriding. */

uint32_t Tins::IP::header_size() const {
    return sizeof(iphdr) + _padded_options_size;
}

bool Tins::IP::send(PacketSender* sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->send_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

Tins::PDU *Tins::IP::recv_response(PacketSender *sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->recv_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
    uint32_t my_sz = header_size();
    assert(total_sz >= my_sz);
    if(inner_pdu()) {
        uint32_t new_flag;
        new_flag = inner_pdu()->flag();
        if(new_flag == IPPROTO_IP)
            new_flag = IPPROTO_IPIP;

        this->protocol(new_flag);
        this->flag(new_flag);
    }
    this->tot_len(total_sz);
    this->head_len (my_sz / sizeof(uint32_t));

    memcpy(buffer, &_ip, sizeof(_ip));

    uint8_t* ptr_buffer = buffer + sizeof(_ip);
    for(list<IPOption>::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it)
        ptr_buffer = it->write(ptr_buffer);

    memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size);

    if(parent && !_ip.check) {
        uint32_t checksum = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
        while (checksum >> 16)
            checksum = (checksum & 0xffff) + (checksum >> 16);
        ((iphdr*)buffer)->check = Utils::net_to_host_s(~checksum);
        this->check(0);
    }
}

bool Tins::IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return false;
    iphdr *ip_ptr = (iphdr*)ptr;
    if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) {
        uint32_t sz = _ip.ihl * sizeof(uint32_t);
        return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
    }
    return false;
}

Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return 0;
    const iphdr *ip_ptr = (iphdr*)ptr;
    uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
    if(total_sz < sz)
        return 0;
    PDU *child = 0, *cloned;
    if(total_sz > sz) {
        if((child = PDU::clone_inner_pdu(ptr + sizeof(_ip), total_sz - sizeof(_ip))) == 0)
            return 0;
    }
    cloned = new IP(ptr, std::min(total_sz, (uint32_t)(Utils::net_to_host_s(ip_ptr->tot_len) * sizeof(uint32_t))));
    cloned->inner_pdu(child);
    return cloned;
}

void Tins::IP::copy_fields(const IP *other) {
    memcpy(&_ip, &other->_ip, sizeof(_ip));
    for(list<IPOption>::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) {
        IPOption new_opt;
        if(it->optional_data) {
            new_opt.optional_data = new uint8_t[it->optional_data_size];
            memcpy(new_opt.optional_data, it->optional_data, it->optional_data_size);
        }
        else
            new_opt.optional_data = 0;
        new_opt.optional_data_size = it->optional_data_size;
        _ip_options.push_back(new_opt);
    }
    _options_size = other->_options_size;
    _padded_options_size = other->_padded_options_size;
}

Tins::PDU *Tins::IP::clone_pdu() const {
    IP *new_pdu = new IP();
    new_pdu->copy_fields(this);
    return new_pdu;
}
<commit_msg>Fixed warnings in ip.cpp<commit_after>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#include <algorithm>
#ifndef WIN32
    #include <netdb.h>
    #include <sys/socket.h>
#endif
#include "ip.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
#include "rawpdu.h"
#include "utils.h"
#include "constants.h"

using namespace std;

const uint8_t Tins::IP::DEFAULT_TTL = 128;

Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(Constants::IP::PROTO_IP, child) {
    init_ip_fields();
    if(ip_dst.size())
        this->dst_addr(ip_dst);
    if(ip_src.size())
        this->src_addr(ip_src);

}

Tins::IP::IP(const IP &other) : PDU(other) {
    copy_fields(&other);
}

Tins::IP::IP() : PDU(IPPROTO_IP) {
    init_ip_fields();
}

Tins::IP &Tins::IP::operator= (const IP &other) {
    copy_fields(&other);
    copy_inner_pdu(other);
    return *this;
}

Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(Constants::IP::PROTO_IP) {
    static const char *msg("Not enough size for an IP header in the buffer.");
    if(total_sz < sizeof(iphdr))
        throw std::runtime_error(msg);
    std::memcpy(&_ip, buffer, sizeof(iphdr));

    /* Options... */
    /* Establish beginning and ending of the options */
    const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    if(total_sz < head_len() * sizeof(uint32_t))
        throw std::runtime_error(msg);
    buffer += head_len() * sizeof(uint32_t);
    this->_options_size = 0;
    this->_padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr);
    /* While the end of the options is not reached read an option */
    try {
        while (total_sz && ptr_buffer < buffer && (*ptr_buffer != 0)) {
            IPOption opt_to_add;
            opt_to_add.optional_data = 0;
            opt_to_add.optional_data_size = 0;
            memcpy(&opt_to_add.type, ptr_buffer, sizeof(uint8_t));
            ptr_buffer++;
            switch (opt_to_add.type.number) {
                /* Multibyte options with length as second byte */
                case SEC:
                case LSSR:
                case TIMESTAMP:
                case EXTSEC:
                case RR:
                case SID:
                case SSRR:
                case MTUPROBE:
                case MTUREPLY:
                case EIP:
                case TR:
                case ADDEXT:
                case RTRALT:
                case SDB:
                case DPS:
                case UMP:
                case QS:
                    if(!total_sz || *ptr_buffer == 0)
                        throw std::runtime_error(msg);
                    opt_to_add.optional_data_size = *ptr_buffer - 1;
                    if(opt_to_add.optional_data_size > 0) {
                        if(total_sz < opt_to_add.optional_data_size)
                            throw std::runtime_error(msg);
                        opt_to_add.optional_data = new uint8_t[opt_to_add.optional_data_size];
                        memcpy(opt_to_add.optional_data, ptr_buffer, opt_to_add.optional_data_size);
                    }
                    else
                        opt_to_add.optional_data = 0;
                    ptr_buffer += opt_to_add.optional_data_size;
            }
            this->_ip_options.push_back(opt_to_add);
            this->_options_size += 1 + opt_to_add.optional_data_size;
        }
        total_sz -= head_len() * sizeof(uint32_t);
        if (total_sz) {
            switch(_ip.protocol) {
                case IPPROTO_TCP:
                    inner_pdu(new Tins::TCP(buffer, total_sz));
                    break;
                case IPPROTO_UDP:
                    inner_pdu(new Tins::UDP(buffer, total_sz));
                    break;
                case IPPROTO_ICMP:
                    inner_pdu(new Tins::ICMP(buffer, total_sz));
                    break;
                default:
                    inner_pdu(new Tins::RawPDU(buffer, total_sz));
                    break;
            }
        }
    }
    catch(runtime_error &) {
        cleanup();
        throw;
    }
}

Tins::IP::IP(uint32_t ip_dst, uint32_t ip_src, PDU *child) : PDU(Constants::IP::PROTO_IP, child) {
    init_ip_fields();
    this->dst_addr(ip_dst);
    this->src_addr(ip_src);
}

Tins::IP::~IP() {
    cleanup();
}

void Tins::IP::cleanup() {
    for (list<IPOption>::iterator it = _ip_options.begin(); it != _ip_options.end(); it++) {
        delete[] it->optional_data;
    }
}

void Tins::IP::init_ip_fields() {
    memset(&_ip, 0, sizeof(iphdr));
    this->_ip.version = 4;
    this->ttl(DEFAULT_TTL);
    this->id(1);
    this->_options_size = 0;
    this->_padded_options_size = 0;
}

/* Setters */

void Tins::IP::tos(uint8_t new_tos) {
    _ip.tos = new_tos;
}

void Tins::IP::tot_len(uint16_t new_tot_len) {
    _ip.tot_len = Utils::net_to_host_s(new_tot_len);
}

void Tins::IP::id(uint16_t new_id) {
    _ip.id = Utils::net_to_host_s(new_id);
}

void Tins::IP::frag_off(uint16_t new_frag_off) {
    _ip.frag_off = Utils::net_to_host_s(new_frag_off);
}

void Tins::IP::ttl(uint8_t new_ttl) {
    _ip.ttl = new_ttl;
}

void Tins::IP::protocol(uint8_t new_protocol) {
    _ip.protocol = new_protocol;
}

void Tins::IP::check(uint16_t new_check) {
    _ip.check = Utils::net_to_host_s(new_check);
}

void Tins::IP::src_addr(const string &ip) {
    _ip.saddr = Utils::net_to_host_l(Utils::resolve_ip(ip));
}

void Tins::IP::src_addr(uint32_t ip) {
    _ip.saddr = Utils::net_to_host_l(ip);
}

void Tins::IP::dst_addr(const string &ip) {
    _ip.daddr = Utils::net_to_host_l(Utils::resolve_ip(ip));
}

void Tins::IP::dst_addr(uint32_t ip) {
    _ip.daddr = Utils::net_to_host_l(ip);
}

void Tins::IP::head_len(uint8_t new_head_len) {
    _ip.ihl = new_head_len;
}

void Tins::IP::version(uint8_t ver) {
    _ip.version = ver;
}

void Tins::IP::set_eol_option() {
    this->set_option(0, IP::CONTROL, IP::END);
}

void Tins::IP::set_noop_option() {
    this->set_option(0, IP::CONTROL, IP::NOOP);
}

void Tins::IP::set_sec_option(const uint8_t* data, uint32_t data_len) {
    this->set_option(1, IP::CONTROL, IP::SEC, data, data_len);
}

void Tins::IP::set_option(uint8_t copied,
                OptionClass op_class,
                Option number,
                const uint8_t* data,
                uint32_t data_size) {
    IPOption option;
    option.type.copied = copied;
    option.type.op_class = op_class;
    option.type.number = number;
    uint8_t* buffer(0);
    if (data_size) {
        buffer = new uint8_t[data_size];
        memcpy(buffer, data, data_size);
    }
    option.optional_data = buffer;
    option.optional_data_size = data_size;
    _ip_options.push_back(option);
    _options_size += 1 + ((buffer)? (data_size) : 0);
    uint8_t padding = _options_size & 3;
    _padded_options_size = padding? (_options_size - padding + 4) : _options_size;
}

const Tins::IP::IPOption *Tins::IP::search_option(OptionClass opt_class, Option opt_number) const {
    for(std::list<IPOption>::const_iterator it = _ip_options.begin(); it != _ip_options.end(); ++it) {
        if(it->type.op_class == (uint8_t)opt_class && it->type.number == (uint8_t)opt_number)
            return &(*it);
    }
    return 0;
}

uint8_t* Tins::IP::IPOption::write(uint8_t* buffer) {
    memcpy(buffer, &type, 1);
    buffer += 1;
    if (optional_data) {
        memcpy(buffer, optional_data, optional_data_size);
        buffer += optional_data_size;
    }
    return buffer;
}

/* Virtual method overriding. */

uint32_t Tins::IP::header_size() const {
    return sizeof(iphdr) + _padded_options_size;
}

bool Tins::IP::send(PacketSender* sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->send_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

Tins::PDU *Tins::IP::recv_response(PacketSender *sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->recv_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
    uint32_t my_sz = header_size();
    assert(total_sz >= my_sz);
    if(inner_pdu()) {
        uint32_t new_flag;
        new_flag = inner_pdu()->flag();
        if(new_flag == IPPROTO_IP)
            new_flag = IPPROTO_IPIP;

        this->protocol(new_flag);
        this->flag(new_flag);
    }
    this->tot_len(total_sz);
    this->head_len (my_sz / sizeof(uint32_t));

    memcpy(buffer, &_ip, sizeof(_ip));

    uint8_t* ptr_buffer = buffer + sizeof(_ip);
    for(list<IPOption>::iterator it = _ip_options.begin(); it != _ip_options.end(); ++it)
        ptr_buffer = it->write(ptr_buffer);

    memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size);

    if(parent && !_ip.check) {
        uint32_t checksum = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size);
        while (checksum >> 16)
            checksum = (checksum & 0xffff) + (checksum >> 16);
        ((iphdr*)buffer)->check = Utils::net_to_host_s(~checksum);
        this->check(0);
    }
}

bool Tins::IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return false;
    iphdr *ip_ptr = (iphdr*)ptr;
    if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) {
        uint32_t sz = _ip.ihl * sizeof(uint32_t);
        return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
    }
    return false;
}

Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return 0;
    const iphdr *ip_ptr = (iphdr*)ptr;
    uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
    if(total_sz < sz)
        return 0;
    PDU *child = 0, *cloned;
    if(total_sz > sz) {
        if((child = PDU::clone_inner_pdu(ptr + sizeof(_ip), total_sz - sizeof(_ip))) == 0)
            return 0;
    }
    cloned = new IP(ptr, std::min(total_sz, (uint32_t)(Utils::net_to_host_s(ip_ptr->tot_len) * sizeof(uint32_t))));
    cloned->inner_pdu(child);
    return cloned;
}

void Tins::IP::copy_fields(const IP *other) {
    memcpy(&_ip, &other->_ip, sizeof(_ip));
    for(list<IPOption>::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) {
        IPOption new_opt;
        if(it->optional_data) {
            new_opt.optional_data = new uint8_t[it->optional_data_size];
            memcpy(new_opt.optional_data, it->optional_data, it->optional_data_size);
        }
        else
            new_opt.optional_data = 0;
        new_opt.optional_data_size = it->optional_data_size;
        _ip_options.push_back(new_opt);
    }
    _options_size = other->_options_size;
    _padded_options_size = other->_padded_options_size;
}

Tins::PDU *Tins::IP::clone_pdu() const {
    IP *new_pdu = new IP();
    new_pdu->copy_fields(this);
    return new_pdu;
}
<|endoftext|>


<commit_before>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#ifndef WIN32
    #include <netinet/in.h>
#endif
#include "ip.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
#include "rawpdu.h"
#include "utils.h"

using namespace std;

const uint8_t Tins::IP::DEFAULT_TTL = 128;

Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(IPPROTO_IP, child) {
    init_ip_fields();
    if(ip_dst.size())
        _ip.daddr = Utils::resolve_ip(ip_dst);
    if(ip_src.size())
        _ip.saddr = Utils::resolve_ip(ip_src);

}

Tins::IP::IP(const IP &other) : PDU(other) {
    copy_fields(&other);
}

Tins::IP::IP() : PDU(IPPROTO_IP) {
    init_ip_fields();
}

Tins::IP &Tins::IP::operator= (const IP &other) {
    copy_fields(&other);
    copy_inner_pdu(other);
    return *this;
}

Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_IP) {
    if(total_sz < sizeof(iphdr))
        throw std::runtime_error("Not enough size for an IP header in the buffer.");
    std::memcpy(&_ip, buffer, sizeof(iphdr));

    /* Options... */
    /* Establish beginning and ending of the options */
    const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    buffer += head_len() * sizeof(uint32_t);
    this->_options_size = 0;
    this->_padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr);
    /* While the end of the options is not reached read an option */
    while (ptr_buffer < buffer && (*ptr_buffer != 0)) {
        IpOption opt_to_add;
        opt_to_add.optional_data = NULL;
        opt_to_add.optional_data_size = 0;
        memcpy(&opt_to_add.type, ptr_buffer, 1);
        ptr_buffer++;
        switch (opt_to_add.type.number) {
            /* Multibyte options with length as second byte */
            case IPOPT_SEC:
            case IPOPT_LSSR:
            case IPOPT_TIMESTAMP:
            case IPOPT_EXTSEC:
            case IPOPT_RR:
            case IPOPT_SID:
            case IPOPT_SSRR:
            case IPOPT_MTUPROBE:
            case IPOPT_MTUREPLY:
            case IPOPT_EIP:
            case IPOPT_TR:
            case IPOPT_ADDEXT:
            case IPOPT_RTRALT:
            case IPOPT_SDB:
            case IPOPT_DPS:
            case IPOPT_UMP:
            case IPOPT_QS:
                opt_to_add.optional_data_size = *ptr_buffer - 1;
                opt_to_add.optional_data = new uint8_t[opt_to_add.optional_data_size];
                memcpy(opt_to_add.optional_data, ptr_buffer, opt_to_add.optional_data_size);
                ptr_buffer += opt_to_add.optional_data_size;
        }
        this->_ip_options.push_back(opt_to_add);
        this->_options_size += 1 + opt_to_add.optional_data_size;
    }

    total_sz -= head_len() * sizeof(uint32_t);
    if (total_sz == 0)
        return;
    switch(_ip.protocol) {
        case IPPROTO_TCP:
            inner_pdu(new Tins::TCP(buffer, total_sz));
            break;
        case IPPROTO_UDP:
            inner_pdu(new Tins::UDP(buffer, total_sz));
            break;
        case IPPROTO_ICMP:
            inner_pdu(new Tins::ICMP(buffer, total_sz));
            break;
        default:
            inner_pdu(new Tins::RawPDU(buffer, total_sz));
            break;
    }
}

Tins::IP::IP(const iphdr *ptr) : PDU(IPPROTO_IP) {
    std::memcpy(&_ip, ptr, sizeof(iphdr));
    /* Options... */
}

Tins::IP::IP(uint32_t ip_dst, uint32_t ip_src, PDU *child) : PDU(IPPROTO_IP, child) {
    init_ip_fields();
    _ip.daddr = ip_dst;
    _ip.saddr = ip_src;
}

Tins::IP::~IP() {
    for (vector<IpOption>::iterator it = this->_ip_options.begin(); it != this->_ip_options.end(); it++) {
        if (it->optional_data)
            delete[] it->optional_data;
    }
}

void Tins::IP::init_ip_fields() {
    memset(&_ip, 0, sizeof(iphdr));
    this->_ip.version = 4;
    this->ttl(DEFAULT_TTL);
    this->id(1);
    this->_options_size = 0;
    this->_padded_options_size = 0;
}

/* Setters */

void Tins::IP::tos(uint8_t new_tos) {
    _ip.tos = new_tos;
}

void Tins::IP::tot_len(uint16_t new_tot_len) {
    _ip.tot_len = Utils::net_to_host_s(new_tot_len);
}

void Tins::IP::id(uint16_t new_id) {
    _ip.id = Utils::net_to_host_s(new_id);
}

void Tins::IP::frag_off(uint16_t new_frag_off) {
    _ip.frag_off = Utils::net_to_host_s(new_frag_off);
}

void Tins::IP::ttl(uint8_t new_ttl) {
    _ip.ttl = new_ttl;
}

void Tins::IP::protocol(uint8_t new_protocol) {
    _ip.protocol = new_protocol;
}

void Tins::IP::check(uint16_t new_check) {
    _ip.check = Utils::net_to_host_s(new_check);
}

void Tins::IP::src_addr(const string &ip) {
    _ip.saddr = Utils::resolve_ip(ip);
}

void Tins::IP::src_addr(uint32_t ip) {
    _ip.saddr = ip;
}

void Tins::IP::dst_addr(const string &ip) {
    _ip.daddr = Utils::resolve_ip(ip);
}

void Tins::IP::dst_addr(uint32_t ip) {
    _ip.daddr = ip;
}

void Tins::IP::head_len(uint8_t new_head_len) {
    this->_ip.ihl = new_head_len;
}

void Tins::IP::set_option_eol() {
    this->set_option(0, IP::CONTROL, IP::IPOPT_END);
}

void Tins::IP::set_option_noop() {
    this->set_option(0, IP::CONTROL, IP::IPOPT_NOOP);
}

void Tins::IP::set_option_sec(uint8_t* data, uint32_t data_len) {
    assert(data_len == 10);
    this->set_option(1, IP::CONTROL, IP::IPOPT_SEC, data, data_len);
}

void Tins::IP::set_option(uint8_t copied,
                OptionClass op_class,
                OptionNumber number,
                uint8_t* data,
                uint32_t data_size) {
    IpOption option;
    option.type.copied = copied;
    option.type.op_class = op_class;
    option.type.number = number;
    uint8_t* buffer(0);
    if (data_size) {
        buffer = new uint8_t[data_size];
        memcpy(buffer, data, data_size);
    }
    option.optional_data = buffer;
    option.optional_data_size = data_size;
    _ip_options.push_back(option);
    _options_size += 1 + ((buffer)? (data_size) : 0);
    uint8_t padding = _options_size & 3;
    _padded_options_size = padding? (_options_size - padding + 4) : _options_size;
}

uint8_t* Tins::IP::IpOption::write(uint8_t* buffer) {

    memcpy(buffer, &type, 1);
    buffer += 1;
    if (optional_data) {
        memcpy(buffer, optional_data, optional_data_size);
        buffer += optional_data_size;
    }
    return buffer;
}

/* Virtual method overriding. */

uint32_t Tins::IP::header_size() const {
    return sizeof(iphdr) + _padded_options_size;
}

bool Tins::IP::send(PacketSender* sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->send_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

Tins::PDU *Tins::IP::recv_response(PacketSender *sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->recv_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
    uint32_t my_sz = header_size();
    assert(total_sz >= my_sz);
    if(inner_pdu()) {
        uint32_t new_flag;
        new_flag = inner_pdu()->flag();
        if(new_flag == IPPROTO_IP)
            new_flag = IPPROTO_IPIP;

        this->protocol(new_flag);
        this->flag(new_flag);
    }
    this->tot_len(total_sz);
    this->head_len (my_sz / sizeof(uint32_t));

    memcpy(buffer, &_ip, sizeof(iphdr));

    uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    for (uint32_t i = 0; i < _ip_options.size(); ++i)
        ptr_buffer = _ip_options[i].write(ptr_buffer);

    memset(buffer + sizeof(iphdr) + this->_options_size, 0, this->_padded_options_size - this->_options_size);

    if (parent && !_ip.check) {
        uint32_t checksum = PDU::do_checksum(buffer, buffer + sizeof(iphdr) + _padded_options_size);
        while (checksum >> 16)
            checksum = (checksum & 0xffff) + (checksum >> 16);
        ((iphdr*)buffer)->check = Utils::net_to_host_s(~checksum);
        this->check(0);
    }

}

bool Tins::IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return false;
    iphdr *ip_ptr = (iphdr*)ptr;
    if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) {
        uint32_t sz = _ip.ihl * sizeof(uint32_t);
        return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
    }
    return false;
}

Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return 0;
    const iphdr *ip_ptr = (iphdr*)ptr;
    uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
    if(total_sz < sz)
        return 0;
    PDU *child = 0, *cloned;
    if(total_sz > sz) {
        if(inner_pdu()) {
            child = inner_pdu()->clone_packet(ptr + sz, total_sz - sz);
            if(!child)
                return 0;
        }
        else
            child = new RawPDU(ptr + sz, total_sz - sz);
    }
    cloned = new IP(ip_ptr);
    cloned->inner_pdu(child);
    return cloned;
}

void Tins::IP::copy_fields(const IP *other) {
    memcpy(&_ip, &other->_ip, sizeof(_ip));
    for(vector<IpOption>::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) {
        IpOption new_opt;
        if(it->optional_data) {
            new_opt.optional_data = new uint8_t[it->optional_data_size];
            memcpy(new_opt.optional_data, it->optional_data, it->optional_data_size);
        }
        else
            new_opt.optional_data = 0;
        new_opt.optional_data_size = it->optional_data_size;
        _ip_options.push_back(new_opt);
    }
    _options_size = other->_options_size;
    _padded_options_size = other->_padded_options_size;
}

Tins::PDU *Tins::IP::clone_pdu() const {
    IP *new_pdu = new IP();
    new_pdu->copy_fields(this);
    return new_pdu;
}
<commit_msg>Done minor modifications on IP.<commit_after>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#ifndef WIN32
    #include <netinet/in.h>
#endif
#include "ip.h"
#include "tcp.h"
#include "udp.h"
#include "icmp.h"
#include "rawpdu.h"
#include "utils.h"

using namespace std;

const uint8_t Tins::IP::DEFAULT_TTL = 128;

Tins::IP::IP(const string &ip_dst, const string &ip_src, PDU *child) : PDU(IPPROTO_IP, child) {
    init_ip_fields();
    if(ip_dst.size())
        _ip.daddr = Utils::resolve_ip(ip_dst);
    if(ip_src.size())
        _ip.saddr = Utils::resolve_ip(ip_src);

}

Tins::IP::IP(const IP &other) : PDU(other) {
    copy_fields(&other);
}

Tins::IP::IP() : PDU(IPPROTO_IP) {
    init_ip_fields();
}

Tins::IP &Tins::IP::operator= (const IP &other) {
    copy_fields(&other);
    copy_inner_pdu(other);
    return *this;
}

Tins::IP::IP(const uint8_t *buffer, uint32_t total_sz) : PDU(IPPROTO_IP) {
    if(total_sz < sizeof(iphdr))
        throw std::runtime_error("Not enough size for an IP header in the buffer.");
    std::memcpy(&_ip, buffer, sizeof(iphdr));

    /* Options... */
    /* Establish beginning and ending of the options */
    const uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    buffer += head_len() * sizeof(uint32_t);
    this->_options_size = 0;
    this->_padded_options_size = head_len() * sizeof(uint32_t) - sizeof(iphdr);
    /* While the end of the options is not reached read an option */
    while (ptr_buffer < buffer && (*ptr_buffer != 0)) {
        IpOption opt_to_add;
        opt_to_add.optional_data = NULL;
        opt_to_add.optional_data_size = 0;
        memcpy(&opt_to_add.type, ptr_buffer, 1);
        ptr_buffer++;
        switch (opt_to_add.type.number) {
            /* Multibyte options with length as second byte */
            case IPOPT_SEC:
            case IPOPT_LSSR:
            case IPOPT_TIMESTAMP:
            case IPOPT_EXTSEC:
            case IPOPT_RR:
            case IPOPT_SID:
            case IPOPT_SSRR:
            case IPOPT_MTUPROBE:
            case IPOPT_MTUREPLY:
            case IPOPT_EIP:
            case IPOPT_TR:
            case IPOPT_ADDEXT:
            case IPOPT_RTRALT:
            case IPOPT_SDB:
            case IPOPT_DPS:
            case IPOPT_UMP:
            case IPOPT_QS:
                opt_to_add.optional_data_size = *ptr_buffer - 1;
                opt_to_add.optional_data = new uint8_t[opt_to_add.optional_data_size];
                memcpy(opt_to_add.optional_data, ptr_buffer, opt_to_add.optional_data_size);
                ptr_buffer += opt_to_add.optional_data_size;
        }
        this->_ip_options.push_back(opt_to_add);
        this->_options_size += 1 + opt_to_add.optional_data_size;
    }
    total_sz -= head_len() * sizeof(uint32_t);
    if (total_sz) {
        switch(_ip.protocol) {
            case IPPROTO_TCP:
                inner_pdu(new Tins::TCP(buffer, total_sz));
                break;
            case IPPROTO_UDP:
                inner_pdu(new Tins::UDP(buffer, total_sz));
                break;
            case IPPROTO_ICMP:
                inner_pdu(new Tins::ICMP(buffer, total_sz));
                break;
            default:
                inner_pdu(new Tins::RawPDU(buffer, total_sz));
                break;
        }
    }
}

Tins::IP::IP(const iphdr *ptr) : PDU(IPPROTO_IP) {
    std::memcpy(&_ip, ptr, sizeof(iphdr));
    /* Options... */
}

Tins::IP::IP(uint32_t ip_dst, uint32_t ip_src, PDU *child) : PDU(IPPROTO_IP, child) {
    init_ip_fields();
    _ip.daddr = ip_dst;
    _ip.saddr = ip_src;
}

Tins::IP::~IP() {
    for (vector<IpOption>::iterator it = this->_ip_options.begin(); it != this->_ip_options.end(); it++) {
        if (it->optional_data)
            delete[] it->optional_data;
    }
}

void Tins::IP::init_ip_fields() {
    memset(&_ip, 0, sizeof(iphdr));
    this->_ip.version = 4;
    this->ttl(DEFAULT_TTL);
    this->id(1);
    this->_options_size = 0;
    this->_padded_options_size = 0;
}

/* Setters */

void Tins::IP::tos(uint8_t new_tos) {
    _ip.tos = new_tos;
}

void Tins::IP::tot_len(uint16_t new_tot_len) {
    _ip.tot_len = Utils::net_to_host_s(new_tot_len);
}

void Tins::IP::id(uint16_t new_id) {
    _ip.id = Utils::net_to_host_s(new_id);
}

void Tins::IP::frag_off(uint16_t new_frag_off) {
    _ip.frag_off = Utils::net_to_host_s(new_frag_off);
}

void Tins::IP::ttl(uint8_t new_ttl) {
    _ip.ttl = new_ttl;
}

void Tins::IP::protocol(uint8_t new_protocol) {
    _ip.protocol = new_protocol;
}

void Tins::IP::check(uint16_t new_check) {
    _ip.check = Utils::net_to_host_s(new_check);
}

void Tins::IP::src_addr(const string &ip) {
    _ip.saddr = Utils::resolve_ip(ip);
}

void Tins::IP::src_addr(uint32_t ip) {
    _ip.saddr = ip;
}

void Tins::IP::dst_addr(const string &ip) {
    _ip.daddr = Utils::resolve_ip(ip);
}

void Tins::IP::dst_addr(uint32_t ip) {
    _ip.daddr = ip;
}

void Tins::IP::head_len(uint8_t new_head_len) {
    this->_ip.ihl = new_head_len;
}

void Tins::IP::set_option_eol() {
    this->set_option(0, IP::CONTROL, IP::IPOPT_END);
}

void Tins::IP::set_option_noop() {
    this->set_option(0, IP::CONTROL, IP::IPOPT_NOOP);
}

void Tins::IP::set_option_sec(uint8_t* data, uint32_t data_len) {
    assert(data_len == 10);
    this->set_option(1, IP::CONTROL, IP::IPOPT_SEC, data, data_len);
}

void Tins::IP::set_option(uint8_t copied,
                OptionClass op_class,
                OptionNumber number,
                uint8_t* data,
                uint32_t data_size) {
    IpOption option;
    option.type.copied = copied;
    option.type.op_class = op_class;
    option.type.number = number;
    uint8_t* buffer(0);
    if (data_size) {
        buffer = new uint8_t[data_size];
        memcpy(buffer, data, data_size);
    }
    option.optional_data = buffer;
    option.optional_data_size = data_size;
    _ip_options.push_back(option);
    _options_size += 1 + ((buffer)? (data_size) : 0);
    uint8_t padding = _options_size & 3;
    _padded_options_size = padding? (_options_size - padding + 4) : _options_size;
}

uint8_t* Tins::IP::IpOption::write(uint8_t* buffer) {

    memcpy(buffer, &type, 1);
    buffer += 1;
    if (optional_data) {
        memcpy(buffer, optional_data, optional_data_size);
        buffer += optional_data_size;
    }
    return buffer;
}

/* Virtual method overriding. */

uint32_t Tins::IP::header_size() const {
    return sizeof(iphdr) + _padded_options_size;
}

bool Tins::IP::send(PacketSender* sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->send_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

Tins::PDU *Tins::IP::recv_response(PacketSender *sender) {
    struct sockaddr_in link_addr;
    PacketSender::SocketType type = PacketSender::IP_SOCKET;
    link_addr.sin_family = AF_INET;
    link_addr.sin_port = 0;
    link_addr.sin_addr.s_addr = _ip.daddr;
    if(inner_pdu() && inner_pdu()->flag() == IPPROTO_ICMP)
        type = PacketSender::ICMP_SOCKET;

    return sender->recv_l3(this, (struct sockaddr*)&link_addr, sizeof(link_addr), type);
}

void Tins::IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* parent) {
    uint32_t my_sz = header_size();
    assert(total_sz >= my_sz);
    if(inner_pdu()) {
        uint32_t new_flag;
        new_flag = inner_pdu()->flag();
        if(new_flag == IPPROTO_IP)
            new_flag = IPPROTO_IPIP;

        this->protocol(new_flag);
        this->flag(new_flag);
    }
    this->tot_len(total_sz);
    this->head_len (my_sz / sizeof(uint32_t));

    memcpy(buffer, &_ip, sizeof(iphdr));

    uint8_t* ptr_buffer = buffer + sizeof(iphdr);
    for (uint32_t i = 0; i < _ip_options.size(); ++i)
        ptr_buffer = _ip_options[i].write(ptr_buffer);

    memset(buffer + sizeof(iphdr) + this->_options_size, 0, this->_padded_options_size - this->_options_size);

    if (parent && !_ip.check) {
        uint32_t checksum = PDU::do_checksum(buffer, buffer + sizeof(iphdr) + _padded_options_size);
        while (checksum >> 16)
            checksum = (checksum & 0xffff) + (checksum >> 16);
        ((iphdr*)buffer)->check = Utils::net_to_host_s(~checksum);
        this->check(0);
    }

}

bool Tins::IP::matches_response(uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return false;
    iphdr *ip_ptr = (iphdr*)ptr;
    if(_ip.daddr == ip_ptr->saddr && _ip.saddr == ip_ptr->daddr) {
        uint32_t sz = _ip.ihl * sizeof(uint32_t);
        return inner_pdu() ? inner_pdu()->matches_response(ptr + sz, total_sz - sz) : true;
    }
    return false;
}

Tins::PDU *Tins::IP::clone_packet(const uint8_t *ptr, uint32_t total_sz) {
    if(total_sz < sizeof(iphdr))
        return 0;
    const iphdr *ip_ptr = (iphdr*)ptr;
    uint32_t sz = ip_ptr->ihl * sizeof(uint32_t);
    if(total_sz < sz)
        return 0;
    PDU *child = 0, *cloned;
    if(total_sz > sz) {
        if(inner_pdu()) {
            child = inner_pdu()->clone_packet(ptr + sz, total_sz - sz);
            if(!child)
                return 0;
        }
        else
            child = new RawPDU(ptr + sz, total_sz - sz);
    }
    cloned = new IP(ip_ptr);
    cloned->inner_pdu(child);
    return cloned;
}

void Tins::IP::copy_fields(const IP *other) {
    memcpy(&_ip, &other->_ip, sizeof(_ip));
    for(vector<IpOption>::const_iterator it = other->_ip_options.begin(); it != other->_ip_options.end(); ++it) {
        IpOption new_opt;
        if(it->optional_data) {
            new_opt.optional_data = new uint8_t[it->optional_data_size];
            memcpy(new_opt.optional_data, it->optional_data, it->optional_data_size);
        }
        else
            new_opt.optional_data = 0;
        new_opt.optional_data_size = it->optional_data_size;
        _ip_options.push_back(new_opt);
    }
    _options_size = other->_options_size;
    _padded_options_size = other->_padded_options_size;
}

Tins::PDU *Tins::IP::clone_pdu() const {
    IP *new_pdu = new IP();
    new_pdu->copy_fields(this);
    return new_pdu;
}
<|endoftext|>


<commit_before>#include <reactive/coroutine.hpp>
#include <silicium/http/http.hpp>
#include <silicium/fast_variant.hpp>
#include <reactive/total_consumer.hpp>
#include <reactive/consume.hpp>
#include <boost/asio.hpp>
#include <sys/inotify.h>
#include <dirent.h>

namespace rx
{
	struct file_system_change
	{
		boost::uint32_t mask;
		boost::filesystem::path name;
	};

	struct watch_descriptor
	{
		watch_descriptor() BOOST_NOEXCEPT
		{
		}

		watch_descriptor(int notifier, int watch) BOOST_NOEXCEPT
			: notifier(notifier)
			, watch(watch)
		{
		}

		watch_descriptor(watch_descriptor &&other) BOOST_NOEXCEPT
			: notifier(other.notifier)
			, watch(other.watch)
		{
			other.notifier = -1;
		}

		~watch_descriptor() BOOST_NOEXCEPT
		{
			if (notifier == -1)
			{
				return;
			}
			inotify_rm_watch(notifier, watch);
		}

		watch_descriptor &operator = (watch_descriptor &&other) BOOST_NOEXCEPT
		{
			boost::swap(notifier, other.notifier);
			boost::swap(watch, other.watch);
			return *this;
		}

	private:

		int notifier = -1;
		int watch;
	};

	struct file_system_notifier : observable<std::vector<file_system_change>>
	{
		typedef std::vector<file_system_change> element_type;

		explicit file_system_notifier(boost::asio::io_service &io)
			: notifier(io)
		{
			int fd = inotify_init();
			if (fd < 0)
			{
				throw boost::system::system_error(errno, boost::system::posix_category);
			}
			try
			{
				notifier.assign(fd);
			}
			catch (...)
			{
				close(fd);
				throw;
			}
		}

		~file_system_notifier() BOOST_NOEXCEPT
		{
			close(notifier.native_handle());
		}

		watch_descriptor watch(boost::filesystem::path const &target, boost::uint32_t mask)
		{
			int wd = inotify_add_watch(notifier.native_handle(), target.string().c_str(), mask);
			if (wd < 0)
			{
				throw boost::system::system_error(errno, boost::system::posix_category);
			}
			return watch_descriptor(notifier.native_handle(), wd);
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			std::size_t const min_buffer_size = sizeof(inotify_event) + NAME_MAX + 1;
			std::size_t const additional_buffer = 8192;
			read_buffer.resize(min_buffer_size + additional_buffer);
			notifier.async_read_some(boost::asio::buffer(read_buffer), [this](boost::system::error_code error, std::size_t bytes_read)
			{
				if (error)
				{
					if (error == boost::asio::error::operation_aborted)
					{
						return;
					}
					throw std::logic_error("not implemented");
				}
				else
				{
					std::vector<file_system_change> changes;
					for (std::size_t i = 0; i < bytes_read; )
					{
						inotify_event const &event = *reinterpret_cast<inotify_event const *>(read_buffer.data() + i);
						changes.emplace_back(file_system_change{event.mask, event.name});
						i += sizeof(inotify_event);
						i += event.len;
					}
					exchange(this->receiver_, nullptr)->got_element(std::move(changes));
				}
			});
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			notifier.cancel();
			receiver_ = nullptr;
		}

	private:

		boost::asio::posix::stream_descriptor notifier;
		std::vector<char> read_buffer;
		observer<element_type> *receiver_ = nullptr;
	};
}

namespace
{
}

int main()
{
	boost::asio::io_service io;
	rx::file_system_notifier notifier(io);
	auto w = notifier.watch("/home/virtual/dev", IN_ALL_EVENTS);
	auto printer = rx::transform(rx::ref(notifier), [](rx::file_system_notifier::element_type const &events) -> rx::detail::nothing
	{
		for (auto const &event : events)
		{
			std::cerr << event.mask << " " << event.name << '\n';
		}
		return rx::detail::nothing{};
	});
	auto all = rx::make_total_consumer(printer);
	all.start();
	io.run();
}
<commit_msg>flatten the event vectors using rx::enumerate before handling them<commit_after>#include <reactive/coroutine.hpp>
#include <silicium/http/http.hpp>
#include <silicium/fast_variant.hpp>
#include <reactive/total_consumer.hpp>
#include <reactive/consume.hpp>
#include <reactive/enumerate.hpp>
#include <boost/asio.hpp>
#include <sys/inotify.h>
#include <dirent.h>

namespace rx
{
	struct file_system_change
	{
		boost::uint32_t mask;
		boost::filesystem::path name;
	};

	struct watch_descriptor
	{
		watch_descriptor() BOOST_NOEXCEPT
		{
		}

		watch_descriptor(int notifier, int watch) BOOST_NOEXCEPT
			: notifier(notifier)
			, watch(watch)
		{
		}

		watch_descriptor(watch_descriptor &&other) BOOST_NOEXCEPT
			: notifier(other.notifier)
			, watch(other.watch)
		{
			other.notifier = -1;
		}

		~watch_descriptor() BOOST_NOEXCEPT
		{
			if (notifier == -1)
			{
				return;
			}
			inotify_rm_watch(notifier, watch);
		}

		watch_descriptor &operator = (watch_descriptor &&other) BOOST_NOEXCEPT
		{
			boost::swap(notifier, other.notifier);
			boost::swap(watch, other.watch);
			return *this;
		}

	private:

		int notifier = -1;
		int watch;
	};

	struct file_system_notifier : observable<std::vector<file_system_change>>
	{
		typedef std::vector<file_system_change> element_type;

		explicit file_system_notifier(boost::asio::io_service &io)
			: notifier(io)
		{
			int fd = inotify_init();
			if (fd < 0)
			{
				throw boost::system::system_error(errno, boost::system::posix_category);
			}
			try
			{
				notifier.assign(fd);
			}
			catch (...)
			{
				close(fd);
				throw;
			}
		}

		~file_system_notifier() BOOST_NOEXCEPT
		{
			close(notifier.native_handle());
		}

		watch_descriptor watch(boost::filesystem::path const &target, boost::uint32_t mask)
		{
			int wd = inotify_add_watch(notifier.native_handle(), target.string().c_str(), mask);
			if (wd < 0)
			{
				throw boost::system::system_error(errno, boost::system::posix_category);
			}
			return watch_descriptor(notifier.native_handle(), wd);
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			std::size_t const min_buffer_size = sizeof(inotify_event) + NAME_MAX + 1;
			std::size_t const additional_buffer = 8192;
			read_buffer.resize(min_buffer_size + additional_buffer);
			notifier.async_read_some(boost::asio::buffer(read_buffer), [this](boost::system::error_code error, std::size_t bytes_read)
			{
				if (error)
				{
					if (error == boost::asio::error::operation_aborted)
					{
						return;
					}
					throw std::logic_error("not implemented");
				}
				else
				{
					std::vector<file_system_change> changes;
					for (std::size_t i = 0; i < bytes_read; )
					{
						inotify_event const &event = *reinterpret_cast<inotify_event const *>(read_buffer.data() + i);
						changes.emplace_back(file_system_change{event.mask, event.name});
						i += sizeof(inotify_event);
						i += event.len;
					}
					exchange(this->receiver_, nullptr)->got_element(std::move(changes));
				}
			});
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			notifier.cancel();
			receiver_ = nullptr;
		}

	private:

		boost::asio::posix::stream_descriptor notifier;
		std::vector<char> read_buffer;
		observer<element_type> *receiver_ = nullptr;
	};
}

namespace
{
}

int main()
{
	boost::asio::io_service io;
	rx::file_system_notifier notifier(io);
	auto w = notifier.watch("/home/virtual/dev", IN_ALL_EVENTS);
	auto printer = rx::transform(rx::enumerate(rx::ref(notifier)), [](rx::file_system_change const &event) -> rx::detail::nothing
	{
		std::cerr << event.mask << " " << event.name << '\n';
		return rx::detail::nothing{};
	});
	auto all = rx::make_total_consumer(printer);
	all.start();
	io.run();
}
<|endoftext|>


<commit_before>#ifndef MESHSPLITIMPL_HPP
#define MESHSPLITIMPL_HPP

#include "TriangleMesh.hpp"
#include "libnest2d/tools/benchmark.h"
#include "Execution/ExecutionTBB.hpp"

namespace Slic3r {

template<class ExPolicy>
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its);

namespace meshsplit_detail {

template<class Its, class Enable = void> struct ItsWithNeighborsIndex_ {
    using Index = typename Its::Index;
    static const indexed_triangle_set &get_its(const Its &m) { return m.get_its();}
    static const Index &get_index(const Its &m) { return m.get_index(); }
};

// Define a default neighbors index for indexed_triangle_set
template<> struct ItsWithNeighborsIndex_<indexed_triangle_set> {
    using Index = std::vector<Vec3i>;
    static const indexed_triangle_set &get_its(const indexed_triangle_set &its) noexcept { return its; }
    static Index get_index(const indexed_triangle_set &its) noexcept
    {
        return create_neighbors_index(ex_tbb, its);
    }
};

// Visit all unvisited neighboring facets that are reachable from the first unvisited facet,
// and return them.
template<class NeighborIndex>
std::vector<size_t> its_find_unvisited_neighbors(
    const indexed_triangle_set &its,
    const NeighborIndex &       neighbor_index,
    std::vector<char> &         visited)
{
    using stack_el = size_t;

    auto facestack = reserve_vector<stack_el>(its.indices.size());
    auto push = [&facestack] (const stack_el &s) { facestack.emplace_back(s); };
    auto pop  = [&facestack] () -> stack_el {
        stack_el ret = facestack.back();
        facestack.pop_back();
        return ret;
    };

    // find the next unvisited facet and push the index
    auto facet = std::find(visited.begin(), visited.end(), false);
    std::vector<size_t> ret;

    if (facet != visited.end()) {
        ret.reserve(its.indices.size());
        auto idx = size_t(facet - visited.begin());
        push(idx);
        ret.emplace_back(idx);
        visited[idx] = true;
    }

    while (!facestack.empty()) {
        size_t facet_idx = pop();
        const auto &neighbors = neighbor_index[facet_idx];
        for (auto neighbor_idx : neighbors) {
            if (size_t(neighbor_idx) < visited.size() && !visited[size_t(neighbor_idx)]) {
                visited[size_t(neighbor_idx)] = true;
                push(stack_el(neighbor_idx));
                ret.emplace_back(size_t(neighbor_idx));
            }
        }
    }

    return ret;
}

} // namespace meshsplit_detail

template<class IndexT> struct ItsNeighborsWrapper
{
    using Index = IndexT;
    const indexed_triangle_set *its;
    IndexT index;

    ItsNeighborsWrapper(const indexed_triangle_set &m, IndexT &&idx)
        : its{&m}, index{std::move(idx)}
    {}

    const auto& get_its() const noexcept { return *its; }
    const auto& get_index() const noexcept { return index; }
};

// Splits a mesh into multiple meshes when possible.
template<class Its, class OutputIt>
void its_split(const Its &m, OutputIt out_it)
{
    using namespace meshsplit_detail;

    const indexed_triangle_set &its = ItsWithNeighborsIndex_<Its>::get_its(m);

    std::vector<char> visited(its.indices.size(), false);

    struct VertexConv {
        size_t part_id      = std::numeric_limits<size_t>::max();
        size_t vertex_image;
    };
    std::vector<VertexConv> vidx_conv(its.vertices.size());

    const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);

    for (size_t part_id = 0;; ++part_id) {
        std::vector<size_t> facets =
            its_find_unvisited_neighbors(its, neighbor_index, visited);

        if (facets.empty())
            break;

        // Create a new mesh for the part that was just split off.
        indexed_triangle_set mesh;
        mesh.indices.reserve(facets.size());
        mesh.vertices.reserve(std::min(facets.size() * 3, its.vertices.size()));

        // Assign the facets to the new mesh.
        for (size_t face_id : facets) {
            const auto &face = its.indices[face_id];
            Vec3i       new_face;
            for (size_t v = 0; v < 3; ++v) {
                auto vi = face(v);

                if (vidx_conv[vi].part_id != part_id) {
                    vidx_conv[vi] = {part_id, mesh.vertices.size()};
                    mesh.vertices.emplace_back(its.vertices[size_t(vi)]);
                }

                new_face(v) = vidx_conv[vi].vertex_image;
            }

            mesh.indices.emplace_back(new_face);
        }

        out_it = std::move(mesh);
    }
}

template<class Its>
std::vector<indexed_triangle_set> its_split(const Its &its)
{
    auto ret = reserve_vector<indexed_triangle_set>(3);
    its_split(its, std::back_inserter(ret));

    return ret;
}

template<class Its> bool its_is_splittable(const Its &m)
{
    using namespace meshsplit_detail;
    const indexed_triangle_set &its = ItsWithNeighborsIndex_<Its>::get_its(m);
    const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);

    std::vector<char> visited(its.indices.size(), false);
    auto faces = its_find_unvisited_neighbors(its, neighbor_index, visited);

    return !faces.empty();
}

inline int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
    if (int(vertex_index) == triangle_indices[0]) return 0;
    if (int(vertex_index) == triangle_indices[1]) return 1;
    if (int(vertex_index) == triangle_indices[2]) return 2;
    return -1;
}

inline Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
{
    int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
    int vi0             = triangle_indices[edge_index];
    int vi1             = triangle_indices[next_edge_index];
    return Vec2crd(vi0, vi1);
}

template<class ExPolicy>
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its)
{
    const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
    size_t vertices_size = its.vertices.size();

    if (indices.empty() || vertices_size == 0) return {};

    auto               vertex_triangles = VertexFaceIndex{its};
    constexpr int      no_value         = -1;
    std::vector<Vec3i> neighbors(indices.size(),
                                 Vec3i(no_value, no_value, no_value));

    //for (const stl_triangle_vertex_indices& triangle_indices : indices) {
    execution::for_each(ex, size_t(0), indices.size(),
        [&neighbors, &indices, &vertex_triangles] (size_t index)
        {
            Vec3i& neighbor = neighbors[index];
            const stl_triangle_vertex_indices & triangle_indices = indices[index];
            for (int edge_index = 0; edge_index < 3; ++edge_index) {
                // check if done
                int& neighbor_edge = neighbor[edge_index];
                if (neighbor_edge != no_value) continue;
                Vec2crd edge_indices = get_edge_indices(edge_index, triangle_indices);
                // IMPROVE: use same vector for 2 sides of triangle
                const auto &faces_range = vertex_triangles[edge_indices[0]];
                for (const size_t &face : faces_range) {
                    if (face <= index) continue;
                    const stl_triangle_vertex_indices &face_indices = indices[face];
                    int vertex_index = get_vertex_index(edge_indices[1], face_indices);
                    // NOT Contain second vertex?
                    if (vertex_index < 0) continue;
                    // Has NOT oposit direction?
                    if (edge_indices[0] != face_indices[(vertex_index + 1) % 3]) continue;
                    neighbor_edge = face;
                    neighbors[face][vertex_index] = index;
                    break;
                }
            }
        }, execution::max_concurrency(ex));

    return neighbors;
}

} // namespace Slic3r

#endif // MESHSPLITIMPL_HPP
<commit_msg>try to fix build on windows<commit_after>#ifndef MESHSPLITIMPL_HPP
#define MESHSPLITIMPL_HPP

#include "TriangleMesh.hpp"
#include "libnest2d/tools/benchmark.h"
#include "Execution/ExecutionTBB.hpp"

namespace Slic3r {

template<class ExPolicy>
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its);

namespace meshsplit_detail {

template<class Its, class Enable = void> struct ItsWithNeighborsIndex_ {
    using Index = typename Its::Index;
    static const indexed_triangle_set &get_its(const Its &m) { return m.get_its();}
    static const Index &get_index(const Its &m) { return m.get_index(); }
};

// Define a default neighbors index for indexed_triangle_set
template<> struct ItsWithNeighborsIndex_<indexed_triangle_set> {
    using Index = std::vector<Vec3i>;
    static const indexed_triangle_set &get_its(const indexed_triangle_set &its) noexcept { return its; }
    static Index get_index(const indexed_triangle_set &its) noexcept
    {
        return create_neighbors_index(ex_tbb, its);
    }
};

// Visit all unvisited neighboring facets that are reachable from the first unvisited facet,
// and return them.
template<class NeighborIndex>
std::vector<size_t> its_find_unvisited_neighbors(
    const indexed_triangle_set &its,
    const NeighborIndex &       neighbor_index,
    std::vector<char> &         visited)
{
    using stack_el = size_t;

    auto facestack = reserve_vector<stack_el>(its.indices.size());
    auto push = [&facestack] (const stack_el &s) { facestack.emplace_back(s); };
    auto pop  = [&facestack] () -> stack_el {
        stack_el ret = facestack.back();
        facestack.pop_back();
        return ret;
    };

    // find the next unvisited facet and push the index
    auto facet = std::find(visited.begin(), visited.end(), false);
    std::vector<size_t> ret;

    if (facet != visited.end()) {
        ret.reserve(its.indices.size());
        auto idx = size_t(facet - visited.begin());
        push(idx);
        ret.emplace_back(idx);
        visited[idx] = true;
    }

    while (!facestack.empty()) {
        size_t facet_idx = pop();
        const auto &neighbors = neighbor_index[facet_idx];
        for (auto neighbor_idx : neighbors) {
            if (size_t(neighbor_idx) < visited.size() && !visited[size_t(neighbor_idx)]) {
                visited[size_t(neighbor_idx)] = true;
                push(stack_el(neighbor_idx));
                ret.emplace_back(size_t(neighbor_idx));
            }
        }
    }

    return ret;
}

} // namespace meshsplit_detail

template<class IndexT> struct ItsNeighborsWrapper
{
    using Index = IndexT;
    const indexed_triangle_set *its;
    IndexT index;

    ItsNeighborsWrapper(const indexed_triangle_set &m, IndexT &&idx)
        : its{&m}, index{std::move(idx)}
    {}

    const auto& get_its() const noexcept { return *its; }
    const auto& get_index() const noexcept { return index; }
};

// Splits a mesh into multiple meshes when possible.
template<class Its, class OutputIt>
void its_split(const Its &m, OutputIt out_it)
{
    using namespace meshsplit_detail;

    const indexed_triangle_set &its = ItsWithNeighborsIndex_<Its>::get_its(m);

    std::vector<char> visited(its.indices.size(), false);

    struct VertexConv {
        size_t part_id      = std::numeric_limits<size_t>::max();
        size_t vertex_image;
    };
    std::vector<VertexConv> vidx_conv(its.vertices.size());

    const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);

    for (size_t part_id = 0;; ++part_id) {
        std::vector<size_t> facets =
            its_find_unvisited_neighbors(its, neighbor_index, visited);

        if (facets.empty())
            break;

        // Create a new mesh for the part that was just split off.
        indexed_triangle_set mesh;
        mesh.indices.reserve(facets.size());
        mesh.vertices.reserve(std::min(facets.size() * 3, its.vertices.size()));

        // Assign the facets to the new mesh.
        for (size_t face_id : facets) {
            const auto &face = its.indices[face_id];
            Vec3i       new_face;
            for (size_t v = 0; v < 3; ++v) {
                auto vi = face(v);

                if (vidx_conv[vi].part_id != part_id) {
                    vidx_conv[vi] = {part_id, mesh.vertices.size()};
                    mesh.vertices.emplace_back(its.vertices[size_t(vi)]);
                }

                new_face(v) = vidx_conv[vi].vertex_image;
            }

            mesh.indices.emplace_back(new_face);
        }

        out_it = std::move(mesh);
    }
}

template<class Its>
std::vector<indexed_triangle_set> its_split(const Its &its)
{
    auto ret = reserve_vector<indexed_triangle_set>(3);
    its_split(its, std::back_inserter(ret));

    return ret;
}

template<class Its> bool its_is_splittable(const Its &m)
{
    using namespace meshsplit_detail;
    const indexed_triangle_set &its = ItsWithNeighborsIndex_<Its>::get_its(m);
    const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);

    std::vector<char> visited(its.indices.size(), false);
    auto faces = its_find_unvisited_neighbors(its, neighbor_index, visited);

    return !faces.empty();
}

inline int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
    if (int(vertex_index) == triangle_indices[0]) return 0;
    if (int(vertex_index) == triangle_indices[1]) return 1;
    if (int(vertex_index) == triangle_indices[2]) return 2;
    return -1;
}

inline Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
{
    int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
    int vi0             = triangle_indices[edge_index];
    int vi1             = triangle_indices[next_edge_index];
    return Vec2crd(vi0, vi1);
}

template<class ExPolicy>
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its)
{
    const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
    size_t vertices_size = its.vertices.size();

    if (indices.empty() || vertices_size == 0) return {};

    auto               vertex_triangles = VertexFaceIndex{its};
    static constexpr int no_value         = -1;
    std::vector<Vec3i> neighbors(indices.size(),
                                 Vec3i(no_value, no_value, no_value));

    //for (const stl_triangle_vertex_indices& triangle_indices : indices) {
    execution::for_each(ex, size_t(0), indices.size(),
        [&neighbors, &indices, &vertex_triangles] (size_t index)
        {
            Vec3i& neighbor = neighbors[index];
            const stl_triangle_vertex_indices & triangle_indices = indices[index];
            for (int edge_index = 0; edge_index < 3; ++edge_index) {
                // check if done
                int& neighbor_edge = neighbor[edge_index];
                if (neighbor_edge != no_value) continue;
                Vec2crd edge_indices = get_edge_indices(edge_index, triangle_indices);
                // IMPROVE: use same vector for 2 sides of triangle
                const auto &faces_range = vertex_triangles[edge_indices[0]];
                for (const size_t &face : faces_range) {
                    if (face <= index) continue;
                    const stl_triangle_vertex_indices &face_indices = indices[face];
                    int vertex_index = get_vertex_index(edge_indices[1], face_indices);
                    // NOT Contain second vertex?
                    if (vertex_index < 0) continue;
                    // Has NOT oposit direction?
                    if (edge_indices[0] != face_indices[(vertex_index + 1) % 3]) continue;
                    neighbor_edge = face;
                    neighbors[face][vertex_index] = index;
                    break;
                }
            }
        }, execution::max_concurrency(ex));

    return neighbors;
}

} // namespace Slic3r

#endif // MESHSPLITIMPL_HPP
<|endoftext|>