<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IP4_PACKET_IP4_HPP
#define IP4_PACKET_IP4_HPP

#include "header.hpp"
#include <cassert>
#include <net/packet.hpp>
#include <net/inet_common.hpp>

namespace net {

  /** IPv4 packet. */
  class PacketIP4 : public Packet {
  public:
    static constexpr int DEFAULT_TTL = 64;

    using Span = gsl::span<Byte>;
    using Cspan = gsl::span<const Byte>;

    //
    // IP header getters
    //

    /** Get IP protocol version field. Must be 4 (RFC 1122) */
    uint8_t ip_version() const noexcept
    { return (ip_header().version_ihl >> 4) & 0xf; }

    bool is_ipv4() const noexcept
    { return (ip_header().version_ihl & 0xf0) == 0x40; }

    /** Get IP header length field as-is. */
    uint8_t ip_ihl() const noexcept
    { return (ip_header().version_ihl & 0xf); }

    /** Get IP header length field in bytes. */
    uint8_t ip_header_length() const noexcept
    { return (ip_header().version_ihl & 0xf) * 4; }

    /** Get Differentiated Services Code Point (DSCP)*/
    DSCP ip_dscp() const noexcept
    { return static_cast<DSCP>(ip_header().ds_ecn >> 2); }

    /** Get Explicit Congestion Notification (ECN) bits */
    ECN ip_ecn() const noexcept
    { return ECN(ip_header().ds_ecn & 0x3); }

    /** Get total length header field */
    uint16_t ip_total_length() const noexcept
    { return ntohs(ip_header().tot_len); }

    /** Get ID header field */
    uint16_t ip_id() const noexcept
    { return ntohs(ip_header().id); }

    /** Get IP header flags */
    ip4::Flags ip_flags() const noexcept
    { return static_cast<ip4::Flags>(ntohs(ip_header().frag_off_flags) >> 13); }

    /** Get Fragment offset field */
    uint16_t ip_frag_offs() const noexcept
    { return ntohs(ip_header().frag_off_flags) & 0x1fff; }

    /** Get Time-To-Live field */
    uint8_t ip_ttl() const noexcept
    { return ip_header().ttl; }

    /** Get protocol field value */
    Protocol ip_protocol() const noexcept
    { return static_cast<Protocol>(ip_header().protocol); }

    /** Get the IP header checksum field as-is */
    uint16_t ip_checksum() const noexcept
    { return ip_header().check; }

    /** Get source address */
    const ip4::Addr& ip_src() const noexcept
    { return ip_header().saddr; }

    /** Get destination address */
    const ip4::Addr& ip_dst() const noexcept
    { return ip_header().daddr; }

    /** Get IP data length. */
    uint16_t ip_data_length() const noexcept
    {
      //Expects(size() and static_cast<size_t>(size()) >= sizeof(ip4::Header));
      return size() - ip_header_length();
    }

    /** Adjust packet size to match IP header's tot_len in case of padding */
    void adjust_size_from_header() {
      auto ip_len = ip_total_length();
      if (UNLIKELY(size() > ip_len)) {
        set_data_end(ip_len);
      }
    }

    /** Get total data capacity of IP packet in bytes  */
    uint16_t ip_capacity() const noexcept
    { return capacity() - ip_header_length(); }

    /** Compute IP header checksum on header as-is */
    uint16_t compute_ip_checksum() noexcept
    { return net::checksum(&ip_header(), ip_header_length()); };

    //
    // IP header setters
    //

    /** Set IP version header field */
    void set_ip_version(uint8_t ver) noexcept
    {
      Expects(ver < 0x10);
      ip_header().version_ihl |= ver << 4;
    }

    /** Set IP header length field */
    void set_ihl(uint8_t ihl) noexcept
    {
      Expects(ihl < 0x10);
      ip_header().version_ihl |= ihl;
    }

    /** Set IP header lenght field, in bytes */
    void set_ip_header_length(uint8_t bytes) noexcept
    { set_ihl(bytes / 4); }

    /** Set DSCP header bits */
    void set_ip_dscp(DSCP dscp) noexcept
    { ip_header().ds_ecn |= (static_cast<uint8_t>(dscp) << 2); }

    /** Set ECN header bits */
    void set_ip_ecn(ECN ecn) noexcept
    { ip_header().ds_ecn |= (static_cast<uint8_t>(ecn) & 0x3); }

    /** Set total length header field */
    void set_ip_total_length(uint16_t len) noexcept
    { ip_header().tot_len = htons(len); }

    /** Set ID header field */
    void set_ip_id(uint16_t i) noexcept
    { ip_header().id = htons(i); }

    /** Set flags field */
    void set_ip_flags(ip4::Flags f)
    {
      ip_header().frag_off_flags |= static_cast<uint16_t>(f) << 13;
      ip_header().frag_off_flags = htons(ip_header().frag_off_flags);
    }

    /** Set fragment offset header field */
    void set_ip_frag_offs(uint16_t offs)
    {
      Expects(offs < 0x2000);
      ip_header().frag_off_flags |= htons(offs) >> 3;
    }

    /** Set total length header field */
    void set_ip_ttl(uint8_t ttl) noexcept
    { ip_header().ttl = ttl; }

    /**
     * @brief      Decrement Time-To-Live by 1 and adjust the checksum.
     */
    void decrement_ttl()
    {
      Expects(ip_ttl() != 0);
      ip_header().ttl--;
      // RFC 1141 p. 1
      uint16_t sum = ntohs(ip_header().check + htons(0x100)); // increment checksum high byte
      ip_header().check = htons(sum + (sum>>16)); // add carry
    }

    /** Set protocol header field */
    void set_protocol(Protocol p) noexcept
    { ip_header().protocol = static_cast<uint8_t>(p); }

    /** Set IP header checksum field directly */
    void set_ip_checksum(uint16_t sum) noexcept
    { ip_header().check = sum; }

    /** Calculate and set IP header checksum field */
    void set_ip_checksum() noexcept {
      auto& hdr = ip_header();
      hdr.check = 0;
      hdr.check = net::checksum(&hdr, ip_header_length());
    }

    /** Set source address header field */
    void set_ip_src(const ip4::Addr& addr) noexcept
    { ip_header().saddr = addr; }

    /** Set destination address header field */
    void set_ip_dst(const ip4::Addr& addr) noexcept
    { ip_header().daddr = addr; }

    /**
     * Set size of data contained in IP datagram.
     * @note : does not modify IP header
     **/
    void set_ip_data_length(uint16_t length) noexcept
    {
      Expects(sizeof(ip4::Header) + length <= (size_t) capacity());
      set_data_end(sizeof(ip4::Header) + length);
    }

    /** Last modifications before transmission */
    void make_flight_ready() noexcept {
      assert( ip_header().protocol );
      set_segment_length();
      set_ip_checksum();
    }

    void init(Protocol proto = Protocol::HOPOPT) noexcept {
      Expects(size() == 0);
      auto& hdr = ip_header();
      hdr = {};
      hdr.tot_len        = 0x1400; // Big-endian 20
      hdr.ttl            = DEFAULT_TTL;
      hdr.protocol       = static_cast<uint8_t>(proto);
      increment_data_end(sizeof(ip4::Header));
    }

    Span ip_data() {
      return {ip_data_ptr(), ip_data_length()};
    }

    Cspan ip_data() const {
      return {ip_data_ptr(), ip_data_length()};
    }

    bool validate_length() const noexcept {
      return this->size() == ip_header_length() + ip_data_length();
    }

  protected:

    /** Get pointer to IP data */
    Byte* ip_data_ptr() noexcept __attribute__((assume_aligned(4)))
    {
      return layer_begin() + ip_header_length();
    }

    const Byte* ip_data_ptr() const noexcept __attribute__((assume_aligned(4)))
    {
      return layer_begin() + ip_header_length();
    }

  private:

    /**
     *  Set IP4 header length
     *  Inferred from packet size
     */
    void set_segment_length() noexcept
    { ip_header().tot_len = htons(size()); }

    const ip4::Header& ip_header() const noexcept
    { return *reinterpret_cast<const ip4::Header*>(layer_begin()); }

    ip4::Header& ip_header() noexcept
    { return *reinterpret_cast<ip4::Header*>(layer_begin()); }

  }; //< class PacketIP4
} //< namespace net

#endif //< IP4_PACKET_IP4_HPP
<commit_msg>ip4: Set version and IHL properly in IP4 packet<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IP4_PACKET_IP4_HPP
#define IP4_PACKET_IP4_HPP

#include "header.hpp"
#include <cassert>
#include <net/packet.hpp>
#include <net/inet_common.hpp>

namespace net {

  /** IPv4 packet. */
  class PacketIP4 : public Packet {
  public:
    static constexpr int DEFAULT_TTL = 64;

    using Span = gsl::span<Byte>;
    using Cspan = gsl::span<const Byte>;

    //
    // IP header getters
    //

    /** Get IP protocol version field. Must be 4 (RFC 1122) */
    uint8_t ip_version() const noexcept
    { return (ip_header().version_ihl >> 4) & 0xf; }

    bool is_ipv4() const noexcept
    { return (ip_header().version_ihl & 0xf0) == 0x40; }

    /** Get IP header length field as-is. */
    uint8_t ip_ihl() const noexcept
    { return (ip_header().version_ihl & 0xf); }

    /** Get IP header length field in bytes. */
    uint8_t ip_header_length() const noexcept
    { return (ip_header().version_ihl & 0xf) * 4; }

    /** Get Differentiated Services Code Point (DSCP)*/
    DSCP ip_dscp() const noexcept
    { return static_cast<DSCP>(ip_header().ds_ecn >> 2); }

    /** Get Explicit Congestion Notification (ECN) bits */
    ECN ip_ecn() const noexcept
    { return ECN(ip_header().ds_ecn & 0x3); }

    /** Get total length header field */
    uint16_t ip_total_length() const noexcept
    { return ntohs(ip_header().tot_len); }

    /** Get ID header field */
    uint16_t ip_id() const noexcept
    { return ntohs(ip_header().id); }

    /** Get IP header flags */
    ip4::Flags ip_flags() const noexcept
    { return static_cast<ip4::Flags>(ntohs(ip_header().frag_off_flags) >> 13); }

    /** Get Fragment offset field */
    uint16_t ip_frag_offs() const noexcept
    { return ntohs(ip_header().frag_off_flags) & 0x1fff; }

    /** Get Time-To-Live field */
    uint8_t ip_ttl() const noexcept
    { return ip_header().ttl; }

    /** Get protocol field value */
    Protocol ip_protocol() const noexcept
    { return static_cast<Protocol>(ip_header().protocol); }

    /** Get the IP header checksum field as-is */
    uint16_t ip_checksum() const noexcept
    { return ip_header().check; }

    /** Get source address */
    const ip4::Addr& ip_src() const noexcept
    { return ip_header().saddr; }

    /** Get destination address */
    const ip4::Addr& ip_dst() const noexcept
    { return ip_header().daddr; }

    /** Get IP data length. */
    uint16_t ip_data_length() const noexcept
    {
      //Expects(size() and static_cast<size_t>(size()) >= sizeof(ip4::Header));
      return size() - ip_header_length();
    }

    /** Adjust packet size to match IP header's tot_len in case of padding */
    void adjust_size_from_header() {
      auto ip_len = ip_total_length();
      if (UNLIKELY(size() > ip_len)) {
        set_data_end(ip_len);
      }
    }

    /** Get total data capacity of IP packet in bytes  */
    uint16_t ip_capacity() const noexcept
    { return capacity() - ip_header_length(); }

    /** Compute IP header checksum on header as-is */
    uint16_t compute_ip_checksum() noexcept
    { return net::checksum(&ip_header(), ip_header_length()); };

    //
    // IP header setters
    //

    /** Set IP version header field */
    void set_ip_version(uint8_t ver) noexcept
    {
      Expects(ver < 0x10);
      ip_header().version_ihl &= 0x0F;
      ip_header().version_ihl |= ver << 4;
    }

    /** Set IP header length field */
    void set_ihl(uint8_t ihl) noexcept
    {
      Expects(ihl < 0x10);
      ip_header().version_ihl &= 0xF0;
      ip_header().version_ihl |= ihl;
    }

    /** Set IP header lenght field, in bytes */
    void set_ip_header_length(uint8_t bytes) noexcept
    { set_ihl(bytes / 4); }

    /** Set DSCP header bits */
    void set_ip_dscp(DSCP dscp) noexcept
    { ip_header().ds_ecn |= (static_cast<uint8_t>(dscp) << 2); }

    /** Set ECN header bits */
    void set_ip_ecn(ECN ecn) noexcept
    { ip_header().ds_ecn |= (static_cast<uint8_t>(ecn) & 0x3); }

    /** Set total length header field */
    void set_ip_total_length(uint16_t len) noexcept
    { ip_header().tot_len = htons(len); }

    /** Set ID header field */
    void set_ip_id(uint16_t i) noexcept
    { ip_header().id = htons(i); }

    /** Set flags field */
    void set_ip_flags(ip4::Flags f)
    {
      ip_header().frag_off_flags |= static_cast<uint16_t>(f) << 13;
      ip_header().frag_off_flags = htons(ip_header().frag_off_flags);
    }

    /** Set fragment offset header field */
    void set_ip_frag_offs(uint16_t offs)
    {
      Expects(offs < 0x2000);
      ip_header().frag_off_flags |= htons(offs) >> 3;
    }

    /** Set total length header field */
    void set_ip_ttl(uint8_t ttl) noexcept
    { ip_header().ttl = ttl; }

    /**
     * @brief      Decrement Time-To-Live by 1 and adjust the checksum.
     */
    void decrement_ttl()
    {
      Expects(ip_ttl() != 0);
      ip_header().ttl--;
      // RFC 1141 p. 1
      uint16_t sum = ntohs(ip_header().check + htons(0x100)); // increment checksum high byte
      ip_header().check = htons(sum + (sum>>16)); // add carry
    }

    /** Set protocol header field */
    void set_protocol(Protocol p) noexcept
    { ip_header().protocol = static_cast<uint8_t>(p); }

    /** Set IP header checksum field directly */
    void set_ip_checksum(uint16_t sum) noexcept
    { ip_header().check = sum; }

    /** Calculate and set IP header checksum field */
    void set_ip_checksum() noexcept {
      auto& hdr = ip_header();
      hdr.check = 0;
      hdr.check = net::checksum(&hdr, ip_header_length());
    }

    /** Set source address header field */
    void set_ip_src(const ip4::Addr& addr) noexcept
    { ip_header().saddr = addr; }

    /** Set destination address header field */
    void set_ip_dst(const ip4::Addr& addr) noexcept
    { ip_header().daddr = addr; }

    /**
     * Set size of data contained in IP datagram.
     * @note : does not modify IP header
     **/
    void set_ip_data_length(uint16_t length) noexcept
    {
      Expects(sizeof(ip4::Header) + length <= (size_t) capacity());
      set_data_end(sizeof(ip4::Header) + length);
    }

    /** Last modifications before transmission */
    void make_flight_ready() noexcept {
      assert( ip_header().protocol );
      set_segment_length();
      set_ip_checksum();
    }

    void init(Protocol proto = Protocol::HOPOPT) noexcept {
      Expects(size() == 0);
      auto& hdr = ip_header();
      hdr = {};
      hdr.tot_len        = 0x1400; // Big-endian 20
      hdr.ttl            = DEFAULT_TTL;
      hdr.protocol       = static_cast<uint8_t>(proto);
      increment_data_end(sizeof(ip4::Header));
    }

    Span ip_data() {
      return {ip_data_ptr(), ip_data_length()};
    }

    Cspan ip_data() const {
      return {ip_data_ptr(), ip_data_length()};
    }

    bool validate_length() const noexcept {
      return this->size() == ip_header_length() + ip_data_length();
    }

  protected:

    /** Get pointer to IP data */
    Byte* ip_data_ptr() noexcept __attribute__((assume_aligned(4)))
    {
      return layer_begin() + ip_header_length();
    }

    const Byte* ip_data_ptr() const noexcept __attribute__((assume_aligned(4)))
    {
      return layer_begin() + ip_header_length();
    }

  private:

    /**
     *  Set IP4 header length
     *  Inferred from packet size
     */
    void set_segment_length() noexcept
    { ip_header().tot_len = htons(size()); }

    const ip4::Header& ip_header() const noexcept
    { return *reinterpret_cast<const ip4::Header*>(layer_begin()); }

    ip4::Header& ip_header() noexcept
    { return *reinterpret_cast<ip4::Header*>(layer_begin()); }

  }; //< class PacketIP4
} //< namespace net

#endif //< IP4_PACKET_IP4_HPP
<|endoftext|>


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

#ifndef ADC_CX_DSAPI_HXX
#define ADC_CX_DSAPI_HXX

// USED SERVICES
    // BASE CLASSES
#include <tokens/tkpcont2.hxx>
    // COMPONENTS
#include <cosv/template/dyn.hxx>
#include <tokens/tkpstam2.hxx>
    // PARAMETERS

namespace csi
{
namespace dsapi
{

class Token_Receiver;
class Token;

class Cx_EoHtml;
class Cx_EoXmlConst;
class Cx_EoXmlLink_BeginTag;
class Cx_EoXmlLink_EndTag;
class Cx_EoXmlFormat_BeginTag;
class Cx_EoXmlFormat_EndTag;
class Cx_CheckStar;

/**
@descr
*/
class Context_Docu : public TkpDocuContext,
                     private StateMachineContext
{
  public:
    //  LIFECYCLE
                        Context_Docu(
                            Token_Receiver &    o_rReceiver );
    virtual void        SetParentContext(
                            TkpContext &        io_rParentContext,
                            const char *        i_sMultiLineEndToken );

                        ~Context_Docu();
    //  OPERATIONS
    virtual void        ReadCharChain(
                            CharacterSource &   io_rText );

    virtual bool        PassNewToken();
    virtual void        SetMode_IsMultiLine(
                            bool                i_bTrue );

    //  INQUIRY
    virtual TkpContext &
                        FollowUpContext();
  private:
    //  SERVICE FUNCTIONS
    virtual void        PerformStatusFunction(
                            uintt               i_nStatusSignal,
                            UINT16              i_nTokenId,
                            CharacterSource &   io_rText );

    void                SetupStateMachine();

    //  DATA
    StateMachin2        aStateMachine;
    Token_Receiver *    pReceiver;

        // Contexts
    TkpContext *        pParentContext;
    udmstri             sMultiLineEndToken;

    Dyn<Cx_EoHtml>      pCx_EoHtml;
    Dyn<Cx_EoXmlConst>  pCx_EoXmlConst;
    Dyn<Cx_EoXmlLink_BeginTag>
                        pCx_EoXmlLink_BeginTag;
    Dyn<Cx_EoXmlLink_EndTag>
                        pCx_EoXmlLink_EndTag;
    Dyn<Cx_EoXmlFormat_BeginTag>
                        pCx_EoXmlFormat_BeginTag;
    Dyn<Cx_EoXmlFormat_EndTag>
                        pCx_EoXmlFormat_EndTag;
    Dyn<Cx_CheckStar>   pCx_CheckStar;

        // Temporary data, used during ReadCharChain()
    Dyn<Token>          pNewToken;
    ::TkpContext *      pFollowUpContext;
    bool                bIsMultiline;
};

}   // namespace dsapi
}   // namespace csi

#endif

<commit_msg>INTEGRATION: CWS adc18 (1.2.56); FILE MERGED 2007/10/19 10:37:32 np 1.2.56.2: #i81775# 2007/10/18 15:23:21 np 1.2.56.1: #i81775#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cx_dsapi.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 17:12:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ADC_CX_DSAPI_HXX
#define ADC_CX_DSAPI_HXX

// USED SERVICES
    // BASE CLASSES
#include <tokens/tkpcont2.hxx>
    // COMPONENTS
#include <cosv/tpl/dyn.hxx>
#include <tokens/tkpstam2.hxx>
    // PARAMETERS

namespace csi
{
namespace dsapi
{

class Token_Receiver;
class Token;

class Cx_EoHtml;
class Cx_EoXmlConst;
class Cx_EoXmlLink_BeginTag;
class Cx_EoXmlLink_EndTag;
class Cx_EoXmlFormat_BeginTag;
class Cx_EoXmlFormat_EndTag;
class Cx_CheckStar;

/**
@descr
*/
class Context_Docu : public TkpDocuContext,
                     private StateMachineContext
{
  public:
    //  LIFECYCLE
                        Context_Docu(
                            Token_Receiver &    o_rReceiver );
    virtual void        SetParentContext(
                            TkpContext &        io_rParentContext,
                            const char *        i_sMultiLineEndToken );

                        ~Context_Docu();
    //  OPERATIONS
    virtual void        ReadCharChain(
                            CharacterSource &   io_rText );

    virtual bool        PassNewToken();
    virtual void        SetMode_IsMultiLine(
                            bool                i_bTrue );

    //  INQUIRY
    virtual TkpContext &
                        FollowUpContext();
  private:
    //  SERVICE FUNCTIONS
    virtual void        PerformStatusFunction(
                            uintt               i_nStatusSignal,
                            UINT16              i_nTokenId,
                            CharacterSource &   io_rText );

    void                SetupStateMachine();

    //  DATA
    StateMachin2        aStateMachine;
    Token_Receiver *    pReceiver;

        // Contexts
    TkpContext *        pParentContext;
    String              sMultiLineEndToken;

    Dyn<Cx_EoHtml>      pCx_EoHtml;
    Dyn<Cx_EoXmlConst>  pCx_EoXmlConst;
    Dyn<Cx_EoXmlLink_BeginTag>
                        pCx_EoXmlLink_BeginTag;
    Dyn<Cx_EoXmlLink_EndTag>
                        pCx_EoXmlLink_EndTag;
    Dyn<Cx_EoXmlFormat_BeginTag>
                        pCx_EoXmlFormat_BeginTag;
    Dyn<Cx_EoXmlFormat_EndTag>
                        pCx_EoXmlFormat_EndTag;
    Dyn<Cx_CheckStar>   pCx_CheckStar;

        // Temporary data, used during ReadCharChain()
    Dyn<Token>          pNewToken;
    ::TkpContext *      pFollowUpContext;
    bool                bIsMultiline;
};

}   // namespace dsapi
}   // namespace csi

#endif

<|endoftext|>


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

#ifndef ADC_DSAPI_DOCU_PE2_HXX
#define ADC_DSAPI_DOCU_PE2_HXX

// USED SERVICES
    // BASE CLASSES
#include <s2_dsapi/tokintpr.hxx>
    // COMPONENTS
    // PARAMETERS

class ParserInfo;

namespace ary
{
namespace info
{
class CodeInformation;
class DocuToken;
}   // namespace info
}   // namespace ary

namespace csi
{
namespace dsapi
{

class Token;
class DT_AtTag;

class SapiDocu_PE : public TokenInterpreter
{
  public:
                        SapiDocu_PE(
                            ParserInfo &        io_rPositionInfo );
                        ~SapiDocu_PE();

    void                ProcessToken(
                            DYN csi::dsapi::Token &
                                                let_drToken );

    virtual void        Process_AtTag(
                            const Tok_AtTag &   i_rToken );
    virtual void        Process_HtmlTag(
                            const Tok_HtmlTag & i_rToken );
    virtual void        Process_XmlConst(
                            const Tok_XmlConst &
                                                i_rToken );
    virtual void        Process_XmlLink_BeginTag(
                            const Tok_XmlLink_BeginTag &
                                                i_rToken );
    virtual void        Process_XmlLink_EndTag(
                            const Tok_XmlLink_EndTag &
                                                i_rToken );
    virtual void        Process_XmlFormat_BeginTag(
                            const Tok_XmlFormat_BeginTag &
                                                i_rToken );
    virtual void        Process_XmlFormat_EndTag(
                            const Tok_XmlFormat_EndTag &
                                                i_rToken );
    virtual void        Process_Word(
                            const Tok_Word &    i_rToken );
    virtual void        Process_Comma();
    virtual void        Process_DocuEnd();
    virtual void        Process_EOL();

    DYN ary::info::CodeInformation *
                            ReleaseJustParsedDocu();

    bool                IsComplete() const;

  private:
    enum E_State
    {
        e_none = 0,
        st_short,
        st_description,
        st_attags,
        st_complete
    };

    typedef void ( SapiDocu_PE::*F_TokenAdder )( DYN ary::info::DocuToken & let_drNewToken );

    void                AddDocuToken2Void(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Short(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Description(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Deprecated(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2CurAtTag(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurParameterAtTagName(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText_2(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText_3(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSinceAtTagVersion(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2SinceAtTag(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );

    // DATA
    Dyn<ary::info::CodeInformation>
                        pDocu;
    E_State             eState;
    ParserInfo *        pPositionInfo;
    F_TokenAdder        fCurTokenAddFunction;

    Dyn<DT_AtTag>       pCurAtTag;
    String              sCurDimAttribute;
    StreamStr           sCurAtSeeType_byXML;
};

}   // namespace dsapi
}   // namespace csi

// IMPLEMENTATION

#endif

<commit_msg>INTEGRATION: CWS adc17 (1.6.2); FILE MERGED 2007/08/10 10:37:10 np 1.6.2.1: #i23626 correct spacing in autodoc output#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: docu_pe2.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: vg $ $Date: 2007-09-18 14:26:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ADC_DSAPI_DOCU_PE2_HXX
#define ADC_DSAPI_DOCU_PE2_HXX

// USED SERVICES
    // BASE CLASSES
#include <s2_dsapi/tokintpr.hxx>
    // COMPONENTS
    // PARAMETERS

class ParserInfo;

namespace ary
{
namespace info
{
class CodeInformation;
class DocuToken;
}   // namespace info
}   // namespace ary

namespace csi
{
namespace dsapi
{

class Token;
class DT_AtTag;

class SapiDocu_PE : public TokenInterpreter
{
  public:
                        SapiDocu_PE(
                            ParserInfo &        io_rPositionInfo );
                        ~SapiDocu_PE();

    void                ProcessToken(
                            DYN csi::dsapi::Token &
                                                let_drToken );

    virtual void        Process_AtTag(
                            const Tok_AtTag &   i_rToken );
    virtual void        Process_HtmlTag(
                            const Tok_HtmlTag & i_rToken );
    virtual void        Process_XmlConst(
                            const Tok_XmlConst &
                                                i_rToken );
    virtual void        Process_XmlLink_BeginTag(
                            const Tok_XmlLink_BeginTag &
                                                i_rToken );
    virtual void        Process_XmlLink_EndTag(
                            const Tok_XmlLink_EndTag &
                                                i_rToken );
    virtual void        Process_XmlFormat_BeginTag(
                            const Tok_XmlFormat_BeginTag &
                                                i_rToken );
    virtual void        Process_XmlFormat_EndTag(
                            const Tok_XmlFormat_EndTag &
                                                i_rToken );
    virtual void        Process_Word(
                            const Tok_Word &    i_rToken );
    virtual void        Process_Comma();
    virtual void        Process_DocuEnd();
    virtual void        Process_EOL();
    virtual void        Process_White();

    DYN ary::info::CodeInformation *
                            ReleaseJustParsedDocu();

    bool                IsComplete() const;

  private:
    enum E_State
    {
        e_none = 0,
        st_short,
        st_description,
        st_attags,
        st_complete
    };

    typedef void ( SapiDocu_PE::*F_TokenAdder )( DYN ary::info::DocuToken & let_drNewToken );

    void                AddDocuToken2Void(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Short(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Description(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2Deprecated(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2CurAtTag(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurParameterAtTagName(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText_2(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSeeAlsoAtTagLinkText_3(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                SetCurSinceAtTagVersion(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );
    void                AddDocuToken2SinceAtTag(
                            DYN ary::info::DocuToken &
                                                let_drNewToken );

    // DATA
    Dyn<ary::info::CodeInformation>
                        pDocu;
    E_State             eState;
    ParserInfo *        pPositionInfo;
    F_TokenAdder        fCurTokenAddFunction;

    Dyn<DT_AtTag>       pCurAtTag;
    String              sCurDimAttribute;
    StreamStr           sCurAtSeeType_byXML;
};

}   // namespace dsapi
}   // namespace csi

// IMPLEMENTATION

#endif

<|endoftext|>


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

#include "chrome/browser/crash_handler_host_linux.h"

#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/format_macros.h"
#include "base/linux_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
#include "chrome/app/breakpad_linux.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"

using google_breakpad::ExceptionHandler;

// Since classes derived from CrashHandlerHostLinux are singletons, it's only
// destroyed at the end of the processes lifetime, which is greater in span than
// the lifetime of the IO message loop.
DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux);

CrashHandlerHostLinux::CrashHandlerHostLinux()
    : process_socket_(-1),
      browser_socket_(-1) {
  int fds[2];
  // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
  // sending datagrams to other sockets on the system. The sandbox may prevent
  // the process from calling socket() to create new sockets, but it'll still
  // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
  // a datagram to any (abstract) socket on the same system. With
  // SOCK_SEQPACKET, this is prevented.
  CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0);
  static const int on = 1;

  // Enable passcred on the server end of the socket
  CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0);

  process_socket_ = fds[0];
  browser_socket_ = fds[1];

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &CrashHandlerHostLinux::Init));
}

CrashHandlerHostLinux::~CrashHandlerHostLinux() {
  HANDLE_EINTR(close(process_socket_));
  HANDLE_EINTR(close(browser_socket_));
}

void CrashHandlerHostLinux::Init() {
  MessageLoopForIO* ml = MessageLoopForIO::current();
  CHECK(ml->WatchFileDescriptor(
      browser_socket_, true /* persistent */,
      MessageLoopForIO::WATCH_READ,
      &file_descriptor_watcher_, this));
  ml->AddDestructionObserver(this);
}

void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
  DCHECK(false);
}

void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
  DCHECK_EQ(fd, browser_socket_);

  // A process has crashed and has signaled us by writing a datagram
  // to the death signal socket. The datagram contains the crash context needed
  // for writing the minidump as well as a file descriptor and a credentials
  // block so that they can't lie about their pid.

  // The length of the control message:
  static const unsigned kControlMsgSize =
      CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
  // The length of the regular payload:
  static const unsigned kCrashContextSize =
      sizeof(ExceptionHandler::CrashContext);

  struct msghdr msg = {0};
  struct iovec iov[6];
  char crash_context[kCrashContextSize];
  char guid[kGuidSize + 1];
  char crash_url[kMaxActiveURLSize + 1];
  char distro[kDistroSize + 1];
  char* tid_buf_addr = NULL;
  int tid_fd = -1;
  char control[kControlMsgSize];
  const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) +
      sizeof(crash_url) + sizeof(distro) +
      sizeof(tid_buf_addr) + sizeof(tid_fd);

  iov[0].iov_base = crash_context;
  iov[0].iov_len = sizeof(crash_context);
  iov[1].iov_base = guid;
  iov[1].iov_len = sizeof(guid);
  iov[2].iov_base = crash_url;
  iov[2].iov_len = sizeof(crash_url);
  iov[3].iov_base = distro;
  iov[3].iov_len = sizeof(distro);
  iov[4].iov_base = &tid_buf_addr;
  iov[4].iov_len = sizeof(tid_buf_addr);
  iov[5].iov_base = &tid_fd;
  iov[5].iov_len = sizeof(tid_fd);
  msg.msg_iov = iov;
  msg.msg_iovlen = 6;
  msg.msg_control = control;
  msg.msg_controllen = kControlMsgSize;

  const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0));
  if (msg_size != expected_msg_size) {
    LOG(ERROR) << "Error reading from death signal socket. Crash dumping"
               << " is disabled."
               << " msg_size:" << msg_size
               << " errno:" << errno;
    file_descriptor_watcher_.StopWatchingFileDescriptor();
    return;
  }

  if (msg.msg_controllen != kControlMsgSize ||
      msg.msg_flags & ~MSG_TRUNC) {
    LOG(ERROR) << "Received death signal message with the wrong size;"
               << " msg.msg_controllen:" << msg.msg_controllen
               << " msg.msg_flags:" << msg.msg_flags
               << " kCrashContextSize:" << kCrashContextSize
               << " kControlMsgSize:" << kControlMsgSize;
    return;
  }

  // Walk the control payload an extract the file descriptor and validated pid.
  pid_t crashing_pid = -1;
  int partner_fd = -1;
  int signal_fd = -1;
  for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
       hdr = CMSG_NXTHDR(&msg, hdr)) {
    if (hdr->cmsg_level != SOL_SOCKET)
      continue;
    if (hdr->cmsg_type == SCM_RIGHTS) {
      const unsigned len = hdr->cmsg_len -
          (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
      DCHECK_EQ(len % sizeof(int), 0u);
      const unsigned num_fds = len / sizeof(int);
      if (num_fds != 2) {
        // A nasty process could try and send us too many descriptors and
        // force a leak.
        LOG(ERROR) << "Death signal contained wrong number of descriptors;"
                   << " num_fds:" << num_fds;
        for (unsigned i = 0; i < num_fds; ++i)
          HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
        return;
      } else {
        partner_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
        signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[1];
      }
    } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
      const struct ucred *cred =
          reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
      crashing_pid = cred->pid;
    }
  }

  if (crashing_pid == -1 || partner_fd == -1 || signal_fd == -1) {
    LOG(ERROR) << "Death signal message didn't contain all expected control"
               << " messages";
    if (partner_fd >= 0)
      HANDLE_EINTR(close(partner_fd));
    if (signal_fd >= 0)
      HANDLE_EINTR(close(signal_fd));
    return;
  }

  // Kernel bug workaround (broken in 2.6.30 at least):
  // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
  // namespaces. Thus |crashing_pid| might be garbage from our point of view.
  // In the future we can remove this workaround, but we have to wait a couple
  // of years to be sure that it's worked its way out into the world.

  // The crashing process closes its copy of the signal_fd immediately after
  // calling sendmsg(). We can thus not reliably look for with with
  // FindProcessHoldingSocket(). But by necessity, it has to keep the
  // partner_fd open until the crashdump is complete.
  uint64_t inode_number;
  if (!base::FileDescriptorGetInode(&inode_number, partner_fd)) {
    LOG(WARNING) << "Failed to get inode number for passed socket";
    HANDLE_EINTR(close(partner_fd));
    HANDLE_EINTR(close(signal_fd));
    return;
  }
  HANDLE_EINTR(close(partner_fd));

  pid_t actual_crashing_pid = -1;
  if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number)) {
    LOG(WARNING) << "Failed to find process holding other end of crash reply "
                    "socket";
    HANDLE_EINTR(close(signal_fd));
    return;
  }

  if (actual_crashing_pid != crashing_pid) {
    crashing_pid = actual_crashing_pid;

    // The crashing TID set inside the compromised context via sys_gettid()
    // in ExceptionHandler::HandleSignal is also wrong and needs to be
    // translated.
    //
    // We expect the crashing thread to be in sys_read(), waiting for use to
    // write to |signal_fd|. Most newer kernels where we have the different pid
    // namespaces also have /proc/[pid]/syscall, so we can look through
    // |actual_crashing_pid|'s thread group and find the thread that's in the
    // read syscall with the right arguments.

    std::string expected_syscall_data;
    // /proc/[pid]/syscall is formatted as follows:
    // syscall_number arg1 ... arg6 sp pc
    // but we just check syscall_number through arg3.
    StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
                  SYS_read, tid_fd, tid_buf_addr);
    pid_t crashing_tid =
        base::FindThreadIDWithSyscall(crashing_pid, expected_syscall_data);
    if (crashing_tid == -1) {
      // We didn't find the thread we want. Maybe it didn't reach sys_read()
      // yet, or the kernel doesn't support /proc/[pid]/syscall or the thread
      // went away.  We'll just take a guess here and assume the crashing
      // thread is the thread group leader.
      crashing_tid = crashing_pid;
    }

    ExceptionHandler::CrashContext* bad_context =
        reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
    bad_context->tid = crashing_tid;
  }

  bool upload = true;
  FilePath dumps_path("/tmp");
  if (getenv(env_vars::kHeadless)) {
    upload = false;
    PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
  }
  const uint64 rand = base::RandUint64();
  const std::string minidump_filename =
      StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
                   dumps_path.value().c_str(), process_type_.c_str(), rand);
  if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
                                      crashing_pid, crash_context,
                                      kCrashContextSize)) {
    LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
    HANDLE_EINTR(close(signal_fd));
  }

  // Send the done signal to the process: it can exit now.
  memset(&msg, 0, sizeof(msg));
  struct iovec done_iov;
  done_iov.iov_base = const_cast<char*>("\x42");
  done_iov.iov_len = 1;
  msg.msg_iov = &done_iov;
  msg.msg_iovlen = 1;

  HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
  HANDLE_EINTR(close(signal_fd));

  // Sanitize the string data a bit more
  guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0;

  BreakpadInfo info;
  info.filename = minidump_filename.c_str();
  info.process_type = process_type_.c_str();
  info.process_type_length = process_type_.length();
  info.crash_url = crash_url;
  info.crash_url_length = strlen(crash_url);
  info.guid = guid;
  info.guid_length = strlen(guid);
  info.distro = distro;
  info.distro_length = strlen(distro);
  info.upload = upload;
  HandleCrashDump(info);
}

void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
  file_descriptor_watcher_.StopWatchingFileDescriptor();
}
<commit_msg>Change the message size for breakpad notifications. Due to alignment issues, this does not seem to a problem on x86-64, but on x86-32 we would encounter assertion failures.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/crash_handler_host_linux.h"

#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/format_macros.h"
#include "base/linux_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "breakpad/src/client/linux/handler/exception_handler.h"
#include "breakpad/src/client/linux/minidump_writer/linux_dumper.h"
#include "breakpad/src/client/linux/minidump_writer/minidump_writer.h"
#include "chrome/app/breakpad_linux.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"

using google_breakpad::ExceptionHandler;

// Since classes derived from CrashHandlerHostLinux are singletons, it's only
// destroyed at the end of the processes lifetime, which is greater in span than
// the lifetime of the IO message loop.
DISABLE_RUNNABLE_METHOD_REFCOUNT(CrashHandlerHostLinux);

CrashHandlerHostLinux::CrashHandlerHostLinux()
    : process_socket_(-1),
      browser_socket_(-1) {
  int fds[2];
  // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
  // sending datagrams to other sockets on the system. The sandbox may prevent
  // the process from calling socket() to create new sockets, but it'll still
  // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
  // a datagram to any (abstract) socket on the same system. With
  // SOCK_SEQPACKET, this is prevented.
  CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0);
  static const int on = 1;

  // Enable passcred on the server end of the socket
  CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0);

  process_socket_ = fds[0];
  browser_socket_ = fds[1];

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &CrashHandlerHostLinux::Init));
}

CrashHandlerHostLinux::~CrashHandlerHostLinux() {
  HANDLE_EINTR(close(process_socket_));
  HANDLE_EINTR(close(browser_socket_));
}

void CrashHandlerHostLinux::Init() {
  MessageLoopForIO* ml = MessageLoopForIO::current();
  CHECK(ml->WatchFileDescriptor(
      browser_socket_, true /* persistent */,
      MessageLoopForIO::WATCH_READ,
      &file_descriptor_watcher_, this));
  ml->AddDestructionObserver(this);
}

void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) {
  DCHECK(false);
}

void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
  DCHECK_EQ(fd, browser_socket_);

  // A process has crashed and has signaled us by writing a datagram
  // to the death signal socket. The datagram contains the crash context needed
  // for writing the minidump as well as a file descriptor and a credentials
  // block so that they can't lie about their pid.

  // The length of the control message:
  static const unsigned kControlMsgSize =
      CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
  // The length of the regular payload:
  static const unsigned kCrashContextSize =
      sizeof(ExceptionHandler::CrashContext);

  struct msghdr msg = {0};
  struct iovec iov[6];
  char crash_context[kCrashContextSize];
  char guid[kGuidSize + 1];
  char crash_url[kMaxActiveURLSize + 1];
  char distro[kDistroSize + 1];
  char* tid_buf_addr = NULL;
  int tid_fd = -1;
  char control[kControlMsgSize];
  const ssize_t expected_msg_size = sizeof(crash_context) + sizeof(guid) +
      sizeof(crash_url) + sizeof(distro) +
      sizeof(tid_buf_addr) + sizeof(tid_fd);

  iov[0].iov_base = crash_context;
  iov[0].iov_len = sizeof(crash_context);
  iov[1].iov_base = guid;
  iov[1].iov_len = sizeof(guid);
  iov[2].iov_base = crash_url;
  iov[2].iov_len = sizeof(crash_url);
  iov[3].iov_base = distro;
  iov[3].iov_len = sizeof(distro);
  iov[4].iov_base = &tid_buf_addr;
  iov[4].iov_len = sizeof(tid_buf_addr);
  iov[5].iov_base = &tid_fd;
  iov[5].iov_len = sizeof(tid_fd);
  msg.msg_iov = iov;
  msg.msg_iovlen = 6;
  msg.msg_control = control;
  msg.msg_controllen = kControlMsgSize;

  const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0));
  if (msg_size != expected_msg_size) {
    LOG(ERROR) << "Error reading from death signal socket. Crash dumping"
               << " is disabled."
               << " msg_size:" << msg_size
               << " errno:" << errno;
    file_descriptor_watcher_.StopWatchingFileDescriptor();
    return;
  }

  if (msg.msg_controllen != kControlMsgSize ||
      msg.msg_flags & ~MSG_TRUNC) {
    LOG(ERROR) << "Received death signal message with the wrong size;"
               << " msg.msg_controllen:" << msg.msg_controllen
               << " msg.msg_flags:" << msg.msg_flags
               << " kCrashContextSize:" << kCrashContextSize
               << " kControlMsgSize:" << kControlMsgSize;
    return;
  }

  // Walk the control payload an extract the file descriptor and validated pid.
  pid_t crashing_pid = -1;
  int partner_fd = -1;
  int signal_fd = -1;
  for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
       hdr = CMSG_NXTHDR(&msg, hdr)) {
    if (hdr->cmsg_level != SOL_SOCKET)
      continue;
    if (hdr->cmsg_type == SCM_RIGHTS) {
      const unsigned len = hdr->cmsg_len -
          (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
      DCHECK_EQ(len % sizeof(int), 0u);
      const unsigned num_fds = len / sizeof(int);
      if (num_fds != 2) {
        // A nasty process could try and send us too many descriptors and
        // force a leak.
        LOG(ERROR) << "Death signal contained wrong number of descriptors;"
                   << " num_fds:" << num_fds;
        for (unsigned i = 0; i < num_fds; ++i)
          HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
        return;
      } else {
        partner_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
        signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[1];
      }
    } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
      const struct ucred *cred =
          reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
      crashing_pid = cred->pid;
    }
  }

  if (crashing_pid == -1 || partner_fd == -1 || signal_fd == -1) {
    LOG(ERROR) << "Death signal message didn't contain all expected control"
               << " messages";
    if (partner_fd >= 0)
      HANDLE_EINTR(close(partner_fd));
    if (signal_fd >= 0)
      HANDLE_EINTR(close(signal_fd));
    return;
  }

  // Kernel bug workaround (broken in 2.6.30 at least):
  // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
  // namespaces. Thus |crashing_pid| might be garbage from our point of view.
  // In the future we can remove this workaround, but we have to wait a couple
  // of years to be sure that it's worked its way out into the world.

  // The crashing process closes its copy of the signal_fd immediately after
  // calling sendmsg(). We can thus not reliably look for with with
  // FindProcessHoldingSocket(). But by necessity, it has to keep the
  // partner_fd open until the crashdump is complete.
  uint64_t inode_number;
  if (!base::FileDescriptorGetInode(&inode_number, partner_fd)) {
    LOG(WARNING) << "Failed to get inode number for passed socket";
    HANDLE_EINTR(close(partner_fd));
    HANDLE_EINTR(close(signal_fd));
    return;
  }
  HANDLE_EINTR(close(partner_fd));

  pid_t actual_crashing_pid = -1;
  if (!base::FindProcessHoldingSocket(&actual_crashing_pid, inode_number)) {
    LOG(WARNING) << "Failed to find process holding other end of crash reply "
                    "socket";
    HANDLE_EINTR(close(signal_fd));
    return;
  }

  if (actual_crashing_pid != crashing_pid) {
    crashing_pid = actual_crashing_pid;

    // The crashing TID set inside the compromised context via sys_gettid()
    // in ExceptionHandler::HandleSignal is also wrong and needs to be
    // translated.
    //
    // We expect the crashing thread to be in sys_read(), waiting for use to
    // write to |signal_fd|. Most newer kernels where we have the different pid
    // namespaces also have /proc/[pid]/syscall, so we can look through
    // |actual_crashing_pid|'s thread group and find the thread that's in the
    // read syscall with the right arguments.

    std::string expected_syscall_data;
    // /proc/[pid]/syscall is formatted as follows:
    // syscall_number arg1 ... arg6 sp pc
    // but we just check syscall_number through arg3.
    StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
                  SYS_read, tid_fd, tid_buf_addr);
    pid_t crashing_tid =
        base::FindThreadIDWithSyscall(crashing_pid, expected_syscall_data);
    if (crashing_tid == -1) {
      // We didn't find the thread we want. Maybe it didn't reach sys_read()
      // yet, or the kernel doesn't support /proc/[pid]/syscall or the thread
      // went away.  We'll just take a guess here and assume the crashing
      // thread is the thread group leader.
      crashing_tid = crashing_pid;
    }

    ExceptionHandler::CrashContext* bad_context =
        reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
    bad_context->tid = crashing_tid;
  }

  bool upload = true;
  FilePath dumps_path("/tmp");
  if (getenv(env_vars::kHeadless)) {
    upload = false;
    PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
  }
  const uint64 rand = base::RandUint64();
  const std::string minidump_filename =
      StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
                   dumps_path.value().c_str(), process_type_.c_str(), rand);
  if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
                                      crashing_pid, crash_context,
                                      kCrashContextSize)) {
    LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
    HANDLE_EINTR(close(signal_fd));
  }

  // Send the done signal to the process: it can exit now.
  memset(&msg, 0, sizeof(msg));
  struct iovec done_iov;
  done_iov.iov_base = const_cast<char*>("\x42");
  done_iov.iov_len = 1;
  msg.msg_iov = &done_iov;
  msg.msg_iovlen = 1;

  HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
  HANDLE_EINTR(close(signal_fd));

  // Sanitize the string data a bit more
  guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0;

  BreakpadInfo info;
  info.filename = minidump_filename.c_str();
  info.process_type = process_type_.c_str();
  info.process_type_length = process_type_.length();
  info.crash_url = crash_url;
  info.crash_url_length = strlen(crash_url);
  info.guid = guid;
  info.guid_length = strlen(guid);
  info.distro = distro;
  info.distro_length = strlen(distro);
  info.upload = upload;
  HandleCrashDump(info);
}

void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
  file_descriptor_watcher_.StopWatchingFileDescriptor();
}
<|endoftext|>


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

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

DevToolsWindow::DevToolsWindow(Profile* profile)
    : TabStripModelObserver(),
      inspected_tab_closing_(false) {
  static std::wstring g_wp_key = L"";
  if (g_wp_key.empty()) {
    // TODO(pfeldman): Make browser's getter for this key static.
    g_wp_key.append(prefs::kBrowserWindowPlacement);
    g_wp_key.append(L"_");
    g_wp_key.append(L"DevToolsApp");

    PrefService* prefs = g_browser_process->local_state();
    prefs->RegisterDictionaryPref(g_wp_key.c_str());

    const DictionaryValue* wp_pref = prefs->GetDictionary(g_wp_key.c_str());
    if (!wp_pref) {
      DictionaryValue* defaults = prefs->GetMutableDictionary(
          g_wp_key.c_str());
      defaults->SetInteger(L"left", 100);
      defaults->SetInteger(L"top", 100);
      defaults->SetInteger(L"right", 740);
      defaults->SetInteger(L"bottom", 740);
      defaults->SetBoolean(L"maximized", false);
      defaults->SetBoolean(L"always_on_top", false);
    }
  }

  browser_.reset(Browser::CreateForApp(L"DevToolsApp", profile, false));
  GURL contents(std::string(chrome::kChromeUIDevToolsURL) + "devtools.html");
  browser_->AddTabWithURL(contents, GURL(), PageTransition::START_PAGE, true,
                          -1, false, NULL);
  tab_contents_ = browser_->GetSelectedTabContents();
  browser_->tabstrip_model()->AddObserver(this);
}

DevToolsWindow::~DevToolsWindow() {
}

void DevToolsWindow::Show() {
  browser_->window()->Show();
  tab_contents_->view()->SetInitialFocus();
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() const {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::InspectedTabClosing() {
  inspected_tab_closing_ = true;
  browser_->CloseAllTabs();
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::TabClosingAt(TabContents* contents, int index) {
  if (!inspected_tab_closing_ && contents == tab_contents_) {
    // Notify manager that this DevToolsClientHost no longer exists.
    NotifyCloseListener();
  }
  if (browser_->tabstrip_model()->empty()) {
    // We are removing the last tab. Delete browser along with the
    // tabstrip_model and its listeners.
    delete this;
  }
}
<commit_msg>DevTools: Set Chrome icon to Dev Tools window. BUG=12687<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

DevToolsWindow::DevToolsWindow(Profile* profile)
    : TabStripModelObserver(),
      inspected_tab_closing_(false) {
  static std::wstring g_wp_key = L"";
  if (g_wp_key.empty()) {
    // TODO(pfeldman): Make browser's getter for this key static.
    g_wp_key.append(prefs::kBrowserWindowPlacement);
    g_wp_key.append(L"_");
    g_wp_key.append(L"DevToolsApp");

    PrefService* prefs = g_browser_process->local_state();
    prefs->RegisterDictionaryPref(g_wp_key.c_str());

    const DictionaryValue* wp_pref = prefs->GetDictionary(g_wp_key.c_str());
    if (!wp_pref) {
      DictionaryValue* defaults = prefs->GetMutableDictionary(
          g_wp_key.c_str());
      defaults->SetInteger(L"left", 100);
      defaults->SetInteger(L"top", 100);
      defaults->SetInteger(L"right", 740);
      defaults->SetInteger(L"bottom", 740);
      defaults->SetBoolean(L"maximized", false);
      defaults->SetBoolean(L"always_on_top", false);
    }
  }

  browser_.reset(Browser::CreateForApp(L"DevToolsApp", profile, false));
  GURL contents(std::string(chrome::kChromeUIDevToolsURL) + "devtools.html");
  browser_->AddTabWithURL(contents, GURL(), PageTransition::START_PAGE, true,
                          -1, false, NULL);
  tab_contents_ = browser_->GetSelectedTabContents();
  browser_->tabstrip_model()->AddObserver(this);

  // Wipe out page icon so that the default application icon is used.
  NavigationEntry* entry = tab_contents_->controller().GetActiveEntry();
  entry->favicon().set_bitmap(SkBitmap());
  entry->favicon().set_is_valid(true);
}

DevToolsWindow::~DevToolsWindow() {
}

void DevToolsWindow::Show() {
  browser_->window()->Show();
  tab_contents_->view()->SetInitialFocus();
}

DevToolsWindow* DevToolsWindow::AsDevToolsWindow() {
  return this;
}

RenderViewHost* DevToolsWindow::GetRenderViewHost() const {
  return tab_contents_->render_view_host();
}

void DevToolsWindow::InspectedTabClosing() {
  inspected_tab_closing_ = true;
  browser_->CloseAllTabs();
}

void DevToolsWindow::SendMessageToClient(const IPC::Message& message) {
  RenderViewHost* target_host = tab_contents_->render_view_host();
  IPC::Message* m =  new IPC::Message(message);
  m->set_routing_id(target_host->routing_id());
  target_host->Send(m);
}

void DevToolsWindow::TabClosingAt(TabContents* contents, int index) {
  if (!inspected_tab_closing_ && contents == tab_contents_) {
    // Notify manager that this DevToolsClientHost no longer exists.
    NotifyCloseListener();
  }
  if (browser_->tabstrip_model()->empty()) {
    // We are removing the last tab. Delete browser along with the
    // tabstrip_model and its listeners.
    delete this;
  }
}
<|endoftext|>


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

#include "chrome/browser/extensions/crx_installer.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/convert_user_script.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"

namespace {
  // Helper function to delete files. This is used to avoid ugly casts which
  // would be necessary with PostMessage since file_util::Delete is overloaded.
  static void DeleteFileHelper(const FilePath& path, bool recursive) {
    file_util::Delete(path, recursive);
  }
}

CrxInstaller::CrxInstaller(const FilePath& install_directory,
                           ExtensionsService* frontend,
                           ExtensionInstallUI* client)
    : install_directory_(install_directory),
      install_source_(Extension::INTERNAL),
      delete_source_(false),
      allow_privilege_increase_(false),
      limit_web_extent_to_download_host_(false),
      create_app_shortcut_(false),
      frontend_(frontend),
      client_(client),
      apps_require_extension_mime_type_(false) {
  extensions_enabled_ = frontend_->extensions_enabled();
}

CrxInstaller::~CrxInstaller() {
  // Delete the temp directory and crx file as necessary. Note that the
  // destructor might be called on any thread, so we post a task to the file
  // thread to make sure the delete happens there.
  if (!temp_dir_.value().empty()) {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableFunction(&DeleteFileHelper, temp_dir_, true));
  }

  if (delete_source_) {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableFunction(&DeleteFileHelper, source_file_, false));
  }

  // Make sure the UI is deleted on the ui thread.
  ChromeThread::DeleteSoon(ChromeThread::UI, FROM_HERE, client_);
  client_ = NULL;
}

void CrxInstaller::InstallCrx(const FilePath& source_file) {
  source_file_ = source_file;

  FilePath user_data_temp_dir;
  CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));

  scoped_refptr<SandboxedExtensionUnpacker> unpacker(
      new SandboxedExtensionUnpacker(
          source_file,
          user_data_temp_dir,
          g_browser_process->resource_dispatcher_host(),
          this));

  ChromeThread::PostTask(
      ChromeThread::FILE, FROM_HERE,
      NewRunnableMethod(
          unpacker.get(), &SandboxedExtensionUnpacker::Start));
}

void CrxInstaller::InstallUserScript(const FilePath& source_file,
                                     const GURL& original_url) {
  DCHECK(!original_url.is_empty());

  source_file_ = source_file;
  original_url_ = original_url;

  ChromeThread::PostTask(
      ChromeThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ConvertUserScriptOnFileThread));
}

void CrxInstaller::ConvertUserScriptOnFileThread() {
  std::string error;
  Extension* extension = ConvertUserScriptToExtension(source_file_,
                                                      original_url_, &error);
  if (!extension) {
    ReportFailureFromFileThread(error);
    return;
  }

  OnUnpackSuccess(extension->path(), extension->path(), extension);
}

void CrxInstaller::OnUnpackFailure(const std::string& error_message) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ReportFailureFromFileThread(error_message);
}

void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
                                   const FilePath& extension_dir,
                                   Extension* extension) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));

  // Note: We take ownership of |extension| and |temp_dir|.
  extension_.reset(extension);
  temp_dir_ = temp_dir;

  // If the extension was downloaded, apps_require_extension_mime_type_
  // will be set.  In this case, check that if the extension is an app,
  // it was served with the right mime type.  Make an exception for file
  // URLs, which come from the users computer and have no headers.
  if (extension->is_app() &&
      !original_url_.SchemeIsFile() &&
      apps_require_extension_mime_type_ &&
      original_mime_type_ != Extension::kMimeType) {
    ReportFailureFromFileThread(StringPrintf(
        "Applications must be served with content type %s.",
        Extension::kMimeType));
    return;
  }

  // The unpack dir we don't have to delete explicity since it is a child of
  // the temp dir.
  unpacked_extension_root_ = extension_dir;

  // Only allow extensions with a gallery update url to be installed after
  // having been directly downloaded from the gallery.
  if (extension->update_url() == GURL(extension_urls::kGalleryUpdateURL) &&
      !ExtensionsService::IsGalleryDownloadURL(original_url_)) {
    ReportFailureFromFileThread(l10n_util::GetStringFUTF8(
        IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS,
        l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
    return;
  }

  // Determine whether to allow installation. We always allow themes and
  // external installs.
  if (!extensions_enabled_ && !extension->is_theme() &&
      !Extension::IsExternalLocation(install_source_)) {
    ReportFailureFromFileThread("Extensions are not enabled.");
    return;
  }

  // Make sure the expected id matches.
  // TODO(aa): Also support expected version?
  if (!expected_id_.empty() && expected_id_ != extension->id()) {
    ReportFailureFromFileThread(StringPrintf(
        "ID in new extension manifest (%s) does not match expected id (%s)",
        extension->id().c_str(),
        expected_id_.c_str()));
    return;
  }

  // Require that apps are served from the domain they claim in their extent,
  // or some ancestor domain.
  if (extension_->is_app() && limit_web_extent_to_download_host_) {
    URLPattern pattern;
    pattern.set_host(original_url_.host());
    pattern.set_match_subdomains(true);

    for (size_t i = 0; i < extension_->web_extent().patterns().size(); ++i) {
      if (!pattern.MatchesHost(extension_->web_extent().patterns()[i].host())) {
        ReportFailureFromFileThread(StringPrintf(
            "Apps must be served from the host that they affect."));
        return;
      }
    }
  }

  if (client_ || extension_->GetFullLaunchURL().is_valid()) {
    Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE,
                          &install_icon_);
  }

  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ConfirmInstall));
}

void CrxInstaller::ConfirmInstall() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) {
    LOG(INFO) << "This extension: " << extension_->id()
      << " is blacklisted. Install failed.";
    ReportFailureFromUIThread("This extension is blacklisted.");
    return;
  }

  GURL overlapping_url;
  Extension* overlapping_extension =
      frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
  if (overlapping_extension) {
    ReportFailureFromUIThread(l10n_util::GetStringFUTF8(
        IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
        UTF8ToUTF16(overlapping_extension->name())));
    return;
  }

  current_version_ =
      frontend_->extension_prefs()->GetVersionString(extension_->id());

  if (client_) {
    AddRef();  // Balanced in Proceed() and Abort().
    client_->ConfirmInstall(this, extension_.get());
  } else {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableMethod(this, &CrxInstaller::CompleteInstall));
  }
  return;
}

void CrxInstaller::InstallUIProceed(bool create_app_shortcut) {
  if (create_app_shortcut) {
    DCHECK(extension_->GetFullLaunchURL().is_valid());
    create_app_shortcut_ = true;
  }

  ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableMethod(this, &CrxInstaller::CompleteInstall));

  Release();  // balanced in ConfirmInstall().
}

void CrxInstaller::InstallUIAbort() {
  // Kill the theme loading bubble.
  NotificationService* service = NotificationService::current();
  service->Notify(NotificationType::NO_THEME_DETECTED,
                  Source<CrxInstaller>(this),
                  NotificationService::NoDetails());
  Release();  // balanced in ConfirmInstall().

  // We're done. Since we don't post any more tasks to ourself, our ref count
  // should go to zero and we die. The destructor will clean up the temp dir.
}

void CrxInstaller::CompleteInstall() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));

  if (!current_version_.empty()) {
    scoped_ptr<Version> current_version(
        Version::GetVersionFromString(current_version_));
    if (current_version->CompareTo(*(extension_->version())) > 0) {
      ReportFailureFromFileThread("Attempted to downgrade extension.");
      return;
    }
  }

  FilePath version_dir = extension_file_util::InstallExtension(
      unpacked_extension_root_,
      extension_->id(),
      extension_->VersionString(),
      install_directory_);
  if (version_dir.empty()) {
    ReportFailureFromFileThread(
        l10n_util::GetStringUTF8(
            IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED));
    return;
  }

  if (create_app_shortcut_) {
    SkBitmap icon = install_icon_.get() ? *install_icon_ :
        *ResourceBundle::GetSharedInstance().GetBitmapNamed(
            IDR_EXTENSION_DEFAULT_ICON);

    ShellIntegration::ShortcutInfo shortcut_info;
    shortcut_info.url = extension_->GetFullLaunchURL();
    shortcut_info.extension_id = UTF8ToUTF16(extension_->id());
    shortcut_info.title = UTF8ToUTF16(extension_->name());
    shortcut_info.description = UTF8ToUTF16(extension_->description());
    shortcut_info.favicon = icon;
    shortcut_info.create_on_desktop = true;

    // TODO(aa): Seems nasty to be reusing the old webapps code this way. What
    // baggage am I inheriting?
    web_app::CreateShortcut(frontend_->profile()->GetPath(), shortcut_info,
                            NULL);
  }

  // This is lame, but we must reload the extension because absolute paths
  // inside the content scripts are established inside InitFromValue() and we
  // just moved the extension.
  // TODO(aa): All paths to resources inside extensions should be created
  // lazily and based on the Extension's root path at that moment.
  std::string error;
  extension_.reset(extension_file_util::LoadExtension(version_dir, true,
                                                      &error));
  DCHECK(error.empty());
  extension_->set_location(install_source_);

  ReportSuccessFromFileThread();
}

void CrxInstaller::ReportFailureFromFileThread(const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ReportFailureFromUIThread, error));
}

void CrxInstaller::ReportFailureFromUIThread(const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  NotificationService* service = NotificationService::current();
  service->Notify(NotificationType::EXTENSION_INSTALL_ERROR,
                  Source<CrxInstaller>(this),
                  Details<const std::string>(&error));

  // This isn't really necessary, it is only used because unit tests expect to
  // see errors get reported via this interface.
  //
  // TODO(aa): Need to go through unit tests and clean them up too, probably get
  // rid of this line.
  ExtensionErrorReporter::GetInstance()->ReportError(error, false);  // quiet

  if (client_)
    client_->OnInstallFailure(error);
}

void CrxInstaller::ReportSuccessFromFileThread() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ReportSuccessFromUIThread));
}

void CrxInstaller::ReportSuccessFromUIThread() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  // If there is a client, tell the client about installation.
  if (client_)
    client_->OnInstallSuccess(extension_.get());

  // Tell the frontend about the installation and hand off ownership of
  // extension_ to it.
  frontend_->OnExtensionInstalled(extension_.release(),
                                  allow_privilege_increase_);

  // We're done. We don't post any more tasks to ourselves so we are deleted
  // soon.
}
<commit_msg>Remove download check for web store apps (temporarily).<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/crx_installer.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/convert_user_script.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"

namespace {
  // Helper function to delete files. This is used to avoid ugly casts which
  // would be necessary with PostMessage since file_util::Delete is overloaded.
  static void DeleteFileHelper(const FilePath& path, bool recursive) {
    file_util::Delete(path, recursive);
  }
}

CrxInstaller::CrxInstaller(const FilePath& install_directory,
                           ExtensionsService* frontend,
                           ExtensionInstallUI* client)
    : install_directory_(install_directory),
      install_source_(Extension::INTERNAL),
      delete_source_(false),
      allow_privilege_increase_(false),
      limit_web_extent_to_download_host_(false),
      create_app_shortcut_(false),
      frontend_(frontend),
      client_(client),
      apps_require_extension_mime_type_(false) {
  extensions_enabled_ = frontend_->extensions_enabled();
}

CrxInstaller::~CrxInstaller() {
  // Delete the temp directory and crx file as necessary. Note that the
  // destructor might be called on any thread, so we post a task to the file
  // thread to make sure the delete happens there.
  if (!temp_dir_.value().empty()) {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableFunction(&DeleteFileHelper, temp_dir_, true));
  }

  if (delete_source_) {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableFunction(&DeleteFileHelper, source_file_, false));
  }

  // Make sure the UI is deleted on the ui thread.
  ChromeThread::DeleteSoon(ChromeThread::UI, FROM_HERE, client_);
  client_ = NULL;
}

void CrxInstaller::InstallCrx(const FilePath& source_file) {
  source_file_ = source_file;

  FilePath user_data_temp_dir;
  CHECK(PathService::Get(chrome::DIR_USER_DATA_TEMP, &user_data_temp_dir));

  scoped_refptr<SandboxedExtensionUnpacker> unpacker(
      new SandboxedExtensionUnpacker(
          source_file,
          user_data_temp_dir,
          g_browser_process->resource_dispatcher_host(),
          this));

  ChromeThread::PostTask(
      ChromeThread::FILE, FROM_HERE,
      NewRunnableMethod(
          unpacker.get(), &SandboxedExtensionUnpacker::Start));
}

void CrxInstaller::InstallUserScript(const FilePath& source_file,
                                     const GURL& original_url) {
  DCHECK(!original_url.is_empty());

  source_file_ = source_file;
  original_url_ = original_url;

  ChromeThread::PostTask(
      ChromeThread::FILE, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ConvertUserScriptOnFileThread));
}

void CrxInstaller::ConvertUserScriptOnFileThread() {
  std::string error;
  Extension* extension = ConvertUserScriptToExtension(source_file_,
                                                      original_url_, &error);
  if (!extension) {
    ReportFailureFromFileThread(error);
    return;
  }

  OnUnpackSuccess(extension->path(), extension->path(), extension);
}

void CrxInstaller::OnUnpackFailure(const std::string& error_message) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ReportFailureFromFileThread(error_message);
}

void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
                                   const FilePath& extension_dir,
                                   Extension* extension) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));

  // Note: We take ownership of |extension| and |temp_dir|.
  extension_.reset(extension);
  temp_dir_ = temp_dir;

  // If the extension was downloaded, apps_require_extension_mime_type_
  // will be set.  In this case, check that if the extension is an app,
  // it was served with the right mime type.  Make an exception for file
  // URLs, which come from the users computer and have no headers.
  if (extension->is_app() &&
      !original_url_.SchemeIsFile() &&
      apps_require_extension_mime_type_ &&
      original_mime_type_ != Extension::kMimeType) {
    ReportFailureFromFileThread(StringPrintf(
        "Applications must be served with content type %s.",
        Extension::kMimeType));
    return;
  }

  // The unpack dir we don't have to delete explicity since it is a child of
  // the temp dir.
  unpacked_extension_root_ = extension_dir;

  // Determine whether to allow installation. We always allow themes and
  // external installs.
  if (!extensions_enabled_ && !extension->is_theme() &&
      !Extension::IsExternalLocation(install_source_)) {
    ReportFailureFromFileThread("Extensions are not enabled.");
    return;
  }

  // Make sure the expected id matches.
  // TODO(aa): Also support expected version?
  if (!expected_id_.empty() && expected_id_ != extension->id()) {
    ReportFailureFromFileThread(StringPrintf(
        "ID in new extension manifest (%s) does not match expected id (%s)",
        extension->id().c_str(),
        expected_id_.c_str()));
    return;
  }

  // Require that apps are served from the domain they claim in their extent,
  // or some ancestor domain.
  if (extension_->is_app() && limit_web_extent_to_download_host_) {
    URLPattern pattern;
    pattern.set_host(original_url_.host());
    pattern.set_match_subdomains(true);

    for (size_t i = 0; i < extension_->web_extent().patterns().size(); ++i) {
      if (!pattern.MatchesHost(extension_->web_extent().patterns()[i].host())) {
        ReportFailureFromFileThread(StringPrintf(
            "Apps must be served from the host that they affect."));
        return;
      }
    }
  }

  if (client_ || extension_->GetFullLaunchURL().is_valid()) {
    Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE,
                          &install_icon_);
  }

  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ConfirmInstall));
}

void CrxInstaller::ConfirmInstall() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) {
    LOG(INFO) << "This extension: " << extension_->id()
      << " is blacklisted. Install failed.";
    ReportFailureFromUIThread("This extension is blacklisted.");
    return;
  }

  GURL overlapping_url;
  Extension* overlapping_extension =
      frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
  if (overlapping_extension) {
    ReportFailureFromUIThread(l10n_util::GetStringFUTF8(
        IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
        UTF8ToUTF16(overlapping_extension->name())));
    return;
  }

  current_version_ =
      frontend_->extension_prefs()->GetVersionString(extension_->id());

  if (client_) {
    AddRef();  // Balanced in Proceed() and Abort().
    client_->ConfirmInstall(this, extension_.get());
  } else {
    ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableMethod(this, &CrxInstaller::CompleteInstall));
  }
  return;
}

void CrxInstaller::InstallUIProceed(bool create_app_shortcut) {
  if (create_app_shortcut) {
    DCHECK(extension_->GetFullLaunchURL().is_valid());
    create_app_shortcut_ = true;
  }

  ChromeThread::PostTask(
        ChromeThread::FILE, FROM_HERE,
        NewRunnableMethod(this, &CrxInstaller::CompleteInstall));

  Release();  // balanced in ConfirmInstall().
}

void CrxInstaller::InstallUIAbort() {
  // Kill the theme loading bubble.
  NotificationService* service = NotificationService::current();
  service->Notify(NotificationType::NO_THEME_DETECTED,
                  Source<CrxInstaller>(this),
                  NotificationService::NoDetails());
  Release();  // balanced in ConfirmInstall().

  // We're done. Since we don't post any more tasks to ourself, our ref count
  // should go to zero and we die. The destructor will clean up the temp dir.
}

void CrxInstaller::CompleteInstall() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));

  if (!current_version_.empty()) {
    scoped_ptr<Version> current_version(
        Version::GetVersionFromString(current_version_));
    if (current_version->CompareTo(*(extension_->version())) > 0) {
      ReportFailureFromFileThread("Attempted to downgrade extension.");
      return;
    }
  }

  FilePath version_dir = extension_file_util::InstallExtension(
      unpacked_extension_root_,
      extension_->id(),
      extension_->VersionString(),
      install_directory_);
  if (version_dir.empty()) {
    ReportFailureFromFileThread(
        l10n_util::GetStringUTF8(
            IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED));
    return;
  }

  if (create_app_shortcut_) {
    SkBitmap icon = install_icon_.get() ? *install_icon_ :
        *ResourceBundle::GetSharedInstance().GetBitmapNamed(
            IDR_EXTENSION_DEFAULT_ICON);

    ShellIntegration::ShortcutInfo shortcut_info;
    shortcut_info.url = extension_->GetFullLaunchURL();
    shortcut_info.extension_id = UTF8ToUTF16(extension_->id());
    shortcut_info.title = UTF8ToUTF16(extension_->name());
    shortcut_info.description = UTF8ToUTF16(extension_->description());
    shortcut_info.favicon = icon;
    shortcut_info.create_on_desktop = true;

    // TODO(aa): Seems nasty to be reusing the old webapps code this way. What
    // baggage am I inheriting?
    web_app::CreateShortcut(frontend_->profile()->GetPath(), shortcut_info,
                            NULL);
  }

  // This is lame, but we must reload the extension because absolute paths
  // inside the content scripts are established inside InitFromValue() and we
  // just moved the extension.
  // TODO(aa): All paths to resources inside extensions should be created
  // lazily and based on the Extension's root path at that moment.
  std::string error;
  extension_.reset(extension_file_util::LoadExtension(version_dir, true,
                                                      &error));
  DCHECK(error.empty());
  extension_->set_location(install_source_);

  ReportSuccessFromFileThread();
}

void CrxInstaller::ReportFailureFromFileThread(const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ReportFailureFromUIThread, error));
}

void CrxInstaller::ReportFailureFromUIThread(const std::string& error) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  NotificationService* service = NotificationService::current();
  service->Notify(NotificationType::EXTENSION_INSTALL_ERROR,
                  Source<CrxInstaller>(this),
                  Details<const std::string>(&error));

  // This isn't really necessary, it is only used because unit tests expect to
  // see errors get reported via this interface.
  //
  // TODO(aa): Need to go through unit tests and clean them up too, probably get
  // rid of this line.
  ExtensionErrorReporter::GetInstance()->ReportError(error, false);  // quiet

  if (client_)
    client_->OnInstallFailure(error);
}

void CrxInstaller::ReportSuccessFromFileThread() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &CrxInstaller::ReportSuccessFromUIThread));
}

void CrxInstaller::ReportSuccessFromUIThread() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  // If there is a client, tell the client about installation.
  if (client_)
    client_->OnInstallSuccess(extension_.get());

  // Tell the frontend about the installation and hand off ownership of
  // extension_ to it.
  frontend_->OnExtensionInstalled(extension_.release(),
                                  allow_privilege_increase_);

  // We're done. We don't post any more tasks to ourselves so we are deleted
  // soon.
}
<|endoftext|>