<commit_before>/*
Copyright (c) 2013, David C Horton

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

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

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

namespace drachtio {
    class SipDialogController ;
}

#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>

#include "pending-request-controller.hpp"
#include "controller.hpp"
#include "cdr.hpp"
#include "request-router.hpp"
#include "request-handler.hpp"

#define CLIENT_TIMEOUT (64000)

namespace drachtio {

  PendingRequest_t::PendingRequest_t(msg_t* msg, sip_t* sip, tport_t* tp ) : m_msg( msg ), m_tp(tp), m_canceled(false),
    m_callId(sip->sip_call_id->i_id), m_seq(sip->sip_cseq->cs_seq), m_methodName(sip->sip_cseq->cs_method_name) {
    //DR_LOG(log_debug) << "PendingRequest_t::PendingRequest_t" ;
    generateUuid( m_transactionId ) ;

    msg_ref_create( m_msg ) ;

  }
  PendingRequest_t::~PendingRequest_t()  {
    msg_destroy( m_msg ) ;
  }
  msg_t* PendingRequest_t::getMsg() { return m_msg ; }
  sip_t* PendingRequest_t::getSipObject() { return sip_object(m_msg); }
  const string& PendingRequest_t::getCallId() { return m_callId; }
  const string& PendingRequest_t::getTransactionId() { return m_transactionId; }
  const string& PendingRequest_t::getMethodName() { return m_methodName; }
  tport_t* PendingRequest_t::getTport() { return m_tp; }
  uint32_t PendingRequest_t::getCSeq() { return m_seq; }

  PendingRequestController::PendingRequestController( DrachtioController* pController) : m_pController(pController),
    m_agent(pController->getAgent()), m_pClientController(pController->getClientController()),
    m_timerQueue(pController->getRoot(), "pending-request" ) {

    assert(m_agent) ;

  }
  PendingRequestController::~PendingRequestController() {
  }

  int PendingRequestController::processNewRequest(  msg_t* msg, sip_t* sip, tport_t* tp_incoming, string& transactionId ) {
    assert(sip->sip_request->rq_method != sip_method_invite || NULL == sip->sip_to->a_tag ) ; //new INVITEs only

    client_ptr client ;
    RequestRouter& router = m_pController->getRequestRouter() ;
    string httpMethod, httpUrl ;
    bool verifyPeer ;

    if( !router.getRoute( sip->sip_request->rq_method_name, httpMethod, httpUrl, verifyPeer ) ) {

      //using inbound connections for this call
      client = m_pClientController->selectClientForRequestOutsideDialog( sip->sip_request->rq_method_name ) ;
      if( !client ) {
        DR_LOG(log_error) << "processNewRequest - No providers available for " << sip->sip_request->rq_method_name  ;
        generateUuid( transactionId ) ;
        return 503 ;
      }
    }

    boost::shared_ptr<PendingRequest_t> p = add( msg, sip ) ;
    transactionId = p->getTransactionId() ;

    msg_destroy( msg ) ;  //our PendingRequest_t is now the holder of the message

    string encodedMessage ;
    EncodeStackMessage( sip, encodedMessage ) ;
    SipMsgData_t meta( msg ) ;
    p->setMeta(meta);
    p->setEncodedMsg(encodedMessage);

    if( !httpUrl.empty() ) {
      // using outbound connection for this call

      vector< pair<string, string> > v;
      v.push_back( make_pair("method", sip->sip_request->rq_method_name )) ;
      v.push_back( make_pair("domain", sip->sip_request->rq_url->url_host )) ;
      v.push_back( make_pair("protocol", meta.getProtocol() )) ;
      v.push_back( make_pair("source_address", meta.getAddress() )) ;
      v.push_back( make_pair("fromUser", sip->sip_from->a_url->url_user ? sip->sip_from->a_url->url_user : "" )) ;
      v.push_back( make_pair("toUser", sip->sip_to->a_url->url_user ? sip->sip_to->a_url->url_user : ""  )) ;

      // add request uri params to the querystring as well
      if (sip->sip_request->rq_url->url_params) {
        string paramString(sip->sip_request->rq_url->url_params);
        vector<string> strs;
        boost::split(strs, paramString, boost::is_any_of(";"));
        for (vector<string>::iterator it = strs.begin(); it != strs.end(); ++it) {
          vector<string> kv ;
          boost::split(kv, *it, boost::is_any_of("="));
          v.push_back(pair<string,string>(kv[0], kv.size() == 2 ? kv[1] : ""));
        }
      }

      //tmp!!
      httpUrl.append("/");
      int i = 0 ;
      pair<string,string> p;
      BOOST_FOREACH(p, v) {
          if( i++ > 0 ) {
              httpUrl.append("&") ;
          }
          else {
            httpUrl.append("?");
          }
          httpUrl.append(p.first) ;
          httpUrl.append("=") ;
          httpUrl.append(urlencode(p.second));
      }

      boost::shared_ptr<RequestHandler> pHandler = RequestHandler::getInstance();
      pHandler->makeRequestForRoute(transactionId, httpMethod, httpUrl, encodedMessage) ;
    }
    else {
      m_pClientController->addNetTransaction( client, p->getTransactionId() ) ;

      m_pClientController->getIOService().post( boost::bind(&Client::sendSipMessageToClient, client, p->getTransactionId(),
          encodedMessage, meta ) ) ;
    }
    return 0 ;
  }

  int PendingRequestController::routeNewRequestToClient( client_ptr client, const string& transactionId) {
    boost::shared_ptr<PendingRequest_t> p = this->find( transactionId ) ;
    if( !p ) {
      DR_LOG(log_error) << "PendingRequestController::routeNewRequestToClient: transactionId not found: " << transactionId ;
      return 500 ;
    }
    m_pClientController->addNetTransaction( client, p->getTransactionId() ) ;
    m_pClientController->getIOService().post( boost::bind(&Client::sendSipMessageToClient, client, p->getTransactionId(),
        p->getEncodedMsg(), p->getMeta() ) ) ;
    return 0 ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::add( msg_t* msg, sip_t* sip ) {
    tport_t *tp = nta_incoming_transport(m_pController->getAgent(), NULL, msg);
    tport_unref(tp) ; //because the above increments the refcount and we don't need to

    boost::shared_ptr<PendingRequest_t> p = boost::make_shared<PendingRequest_t>( msg, sip, tp ) ;

    DR_LOG(log_debug) << "PendingRequestController::add - tport: " << std::hex << (void*) tp <<
      ", Call-ID: " << p->getCallId() << ", transactionId " << p->getTransactionId() ;

    // give client 4 seconds to respond before clearing state
    TimerEventHandle handle = m_timerQueue.add( boost::bind(&PendingRequestController::timeout, shared_from_this(), p->getTransactionId()), NULL, CLIENT_TIMEOUT ) ;
    p->setTimerHandle( handle ) ;

    string id ;
    p->getUniqueSipTransactionIdentifier(id) ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    m_mapCallId2Invite.insert( mapCallId2Invite::value_type(id, p) ) ;
    m_mapTxnId2Invite.insert( mapTxnId2Invite::value_type(p->getTransactionId(), p) ) ;

    return p ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::findAndRemove( const string& transactionId, bool timeout ) {
    boost::shared_ptr<PendingRequest_t> p ;
    string id ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    mapTxnId2Invite::iterator it = m_mapTxnId2Invite.find( transactionId ) ;
    if( it != m_mapTxnId2Invite.end() ) {
      p = it->second ;
      m_mapTxnId2Invite.erase( it ) ;

      p->getUniqueSipTransactionIdentifier(id) ;
      mapCallId2Invite::iterator it2 = m_mapCallId2Invite.find( id ) ;
      assert( it2 != m_mapCallId2Invite.end()) ;
      m_mapCallId2Invite.erase( it2 ) ;

      if( !timeout ) {
        m_timerQueue.remove( p->getTimerHandle() ) ;
      }
    }
    return p ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::find( const string& transactionId ) {
    boost::shared_ptr<PendingRequest_t> p ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    mapTxnId2Invite::iterator it = m_mapTxnId2Invite.find( transactionId ) ;
    if( it != m_mapTxnId2Invite.end() ) {
      p = it->second ;
    }
    return p ;
  }

  void PendingRequestController::timeout(const string& transactionId) {
    DR_LOG(log_debug) << "PendingRequestController::timeout: giving up on transactionId " << transactionId ;

    this->findAndRemove( transactionId, true ) ;
    m_pClientController->removeNetTransaction( transactionId ) ;
  }

  void PendingRequestController::logStorageCount(void)  {
    boost::lock_guard<boost::mutex> lock(m_mutex) ;

    DR_LOG(log_debug) << "PendingRequestController storage counts"  ;
    DR_LOG(log_debug) << "----------------------------------"  ;
    DR_LOG(log_debug) << "m_mapCallId2Invite size:                                         " << m_mapCallId2Invite.size()  ;
    DR_LOG(log_debug) << "m_mapTxnId2Invite size:                                          " << m_mapTxnId2Invite.size()  ;
  }

} ;
<commit_msg>add content-type, uri, and uriUser to the params sent via http for routing instructions<commit_after>/*
Copyright (c) 2013, David C Horton

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

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

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

namespace drachtio {
    class SipDialogController ;
}

#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>

#include "pending-request-controller.hpp"
#include "controller.hpp"
#include "cdr.hpp"
#include "request-router.hpp"
#include "request-handler.hpp"

#define CLIENT_TIMEOUT (64000)

namespace drachtio {

  PendingRequest_t::PendingRequest_t(msg_t* msg, sip_t* sip, tport_t* tp ) : m_msg( msg ), m_tp(tp), m_canceled(false),
    m_callId(sip->sip_call_id->i_id), m_seq(sip->sip_cseq->cs_seq), m_methodName(sip->sip_cseq->cs_method_name) {
    //DR_LOG(log_debug) << "PendingRequest_t::PendingRequest_t" ;
    generateUuid( m_transactionId ) ;

    msg_ref_create( m_msg ) ;

  }
  PendingRequest_t::~PendingRequest_t()  {
    msg_destroy( m_msg ) ;
  }
  msg_t* PendingRequest_t::getMsg() { return m_msg ; }
  sip_t* PendingRequest_t::getSipObject() { return sip_object(m_msg); }
  const string& PendingRequest_t::getCallId() { return m_callId; }
  const string& PendingRequest_t::getTransactionId() { return m_transactionId; }
  const string& PendingRequest_t::getMethodName() { return m_methodName; }
  tport_t* PendingRequest_t::getTport() { return m_tp; }
  uint32_t PendingRequest_t::getCSeq() { return m_seq; }

  PendingRequestController::PendingRequestController( DrachtioController* pController) : m_pController(pController),
    m_agent(pController->getAgent()), m_pClientController(pController->getClientController()),
    m_timerQueue(pController->getRoot(), "pending-request" ) {

    assert(m_agent) ;

  }
  PendingRequestController::~PendingRequestController() {
  }

  int PendingRequestController::processNewRequest(  msg_t* msg, sip_t* sip, tport_t* tp_incoming, string& transactionId ) {
    assert(sip->sip_request->rq_method != sip_method_invite || NULL == sip->sip_to->a_tag ) ; //new INVITEs only

    client_ptr client ;
    RequestRouter& router = m_pController->getRequestRouter() ;
    string httpMethod, httpUrl ;
    bool verifyPeer ;

    if( !router.getRoute( sip->sip_request->rq_method_name, httpMethod, httpUrl, verifyPeer ) ) {

      //using inbound connections for this call
      client = m_pClientController->selectClientForRequestOutsideDialog( sip->sip_request->rq_method_name ) ;
      if( !client ) {
        DR_LOG(log_error) << "processNewRequest - No providers available for " << sip->sip_request->rq_method_name  ;
        generateUuid( transactionId ) ;
        return 503 ;
      }
    }

    boost::shared_ptr<PendingRequest_t> p = add( msg, sip ) ;
    transactionId = p->getTransactionId() ;

    msg_destroy( msg ) ;  //our PendingRequest_t is now the holder of the message

    string encodedMessage ;
    EncodeStackMessage( sip, encodedMessage ) ;
    SipMsgData_t meta( msg ) ;
    p->setMeta(meta);
    p->setEncodedMsg(encodedMessage);

    if( !httpUrl.empty() ) {
      // using outbound connection for this call

      vector< pair<string, string> > v;
      v.push_back( make_pair("method", sip->sip_request->rq_method_name )) ;
      v.push_back( make_pair("domain", sip->sip_request->rq_url->url_host )) ;
      v.push_back( make_pair("protocol", meta.getProtocol() )) ;
      v.push_back( make_pair("source_address", meta.getAddress() )) ;
      v.push_back( make_pair("fromUser", sip->sip_from->a_url->url_user ? sip->sip_from->a_url->url_user : "" )) ;
      v.push_back( make_pair("toUser", sip->sip_to->a_url->url_user ? sip->sip_to->a_url->url_user : ""  )) ;
      v.push_back( make_pair("uriUser", sip->sip_request->rq_url->url_user ? sip->sip_request->rq_url->url_user : ""  )) ;

      // add content-type
      string ct = "";
      if (sip->sip_content_type && sip->sip_content_type->c_type) {
        ct = sip->sip_content_type->c_type;
      }
      v.push_back( make_pair("contentType", ct)) ;

      // uri
      char buf[4096];
      url_e(buf, 4096, sip->sip_request->rq_url);
      v.push_back( make_pair("uri", buf)) ;

      // add request uri params to the querystring as well
      if (sip->sip_request->rq_url->url_params) {
        string paramString(sip->sip_request->rq_url->url_params);
        vector<string> strs;
        boost::split(strs, paramString, boost::is_any_of(";"));
        for (vector<string>::iterator it = strs.begin(); it != strs.end(); ++it) {
          vector<string> kv ;
          boost::split(kv, *it, boost::is_any_of("="));
          v.push_back(pair<string,string>(kv[0], kv.size() == 2 ? kv[1] : ""));
        }
      }

      //tmp!!
      httpUrl.append("/");
      int i = 0 ;
      pair<string,string> p;
      BOOST_FOREACH(p, v) {
          if( i++ > 0 ) {
              httpUrl.append("&") ;
          }
          else {
            httpUrl.append("?");
          }
          httpUrl.append(p.first) ;
          httpUrl.append("=") ;
          httpUrl.append(urlencode(p.second));
      }

      boost::shared_ptr<RequestHandler> pHandler = RequestHandler::getInstance();
      pHandler->makeRequestForRoute(transactionId, httpMethod, httpUrl, encodedMessage) ;
    }
    else {
      m_pClientController->addNetTransaction( client, p->getTransactionId() ) ;

      m_pClientController->getIOService().post( boost::bind(&Client::sendSipMessageToClient, client, p->getTransactionId(),
          encodedMessage, meta ) ) ;
    }
    return 0 ;
  }

  int PendingRequestController::routeNewRequestToClient( client_ptr client, const string& transactionId) {
    boost::shared_ptr<PendingRequest_t> p = this->find( transactionId ) ;
    if( !p ) {
      DR_LOG(log_error) << "PendingRequestController::routeNewRequestToClient: transactionId not found: " << transactionId ;
      return 500 ;
    }
    m_pClientController->addNetTransaction( client, p->getTransactionId() ) ;
    m_pClientController->getIOService().post( boost::bind(&Client::sendSipMessageToClient, client, p->getTransactionId(),
        p->getEncodedMsg(), p->getMeta() ) ) ;
    return 0 ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::add( msg_t* msg, sip_t* sip ) {
    tport_t *tp = nta_incoming_transport(m_pController->getAgent(), NULL, msg);
    tport_unref(tp) ; //because the above increments the refcount and we don't need to

    boost::shared_ptr<PendingRequest_t> p = boost::make_shared<PendingRequest_t>( msg, sip, tp ) ;

    DR_LOG(log_debug) << "PendingRequestController::add - tport: " << std::hex << (void*) tp <<
      ", Call-ID: " << p->getCallId() << ", transactionId " << p->getTransactionId() ;

    // give client 4 seconds to respond before clearing state
    TimerEventHandle handle = m_timerQueue.add( boost::bind(&PendingRequestController::timeout, shared_from_this(), p->getTransactionId()), NULL, CLIENT_TIMEOUT ) ;
    p->setTimerHandle( handle ) ;

    string id ;
    p->getUniqueSipTransactionIdentifier(id) ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    m_mapCallId2Invite.insert( mapCallId2Invite::value_type(id, p) ) ;
    m_mapTxnId2Invite.insert( mapTxnId2Invite::value_type(p->getTransactionId(), p) ) ;

    return p ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::findAndRemove( const string& transactionId, bool timeout ) {
    boost::shared_ptr<PendingRequest_t> p ;
    string id ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    mapTxnId2Invite::iterator it = m_mapTxnId2Invite.find( transactionId ) ;
    if( it != m_mapTxnId2Invite.end() ) {
      p = it->second ;
      m_mapTxnId2Invite.erase( it ) ;

      p->getUniqueSipTransactionIdentifier(id) ;
      mapCallId2Invite::iterator it2 = m_mapCallId2Invite.find( id ) ;
      assert( it2 != m_mapCallId2Invite.end()) ;
      m_mapCallId2Invite.erase( it2 ) ;

      if( !timeout ) {
        m_timerQueue.remove( p->getTimerHandle() ) ;
      }
    }
    return p ;
  }

  boost::shared_ptr<PendingRequest_t> PendingRequestController::find( const string& transactionId ) {
    boost::shared_ptr<PendingRequest_t> p ;
    boost::lock_guard<boost::mutex> lock(m_mutex) ;
    mapTxnId2Invite::iterator it = m_mapTxnId2Invite.find( transactionId ) ;
    if( it != m_mapTxnId2Invite.end() ) {
      p = it->second ;
    }
    return p ;
  }

  void PendingRequestController::timeout(const string& transactionId) {
    DR_LOG(log_debug) << "PendingRequestController::timeout: giving up on transactionId " << transactionId ;

    this->findAndRemove( transactionId, true ) ;
    m_pClientController->removeNetTransaction( transactionId ) ;
  }

  void PendingRequestController::logStorageCount(void)  {
    boost::lock_guard<boost::mutex> lock(m_mutex) ;

    DR_LOG(log_debug) << "PendingRequestController storage counts"  ;
    DR_LOG(log_debug) << "----------------------------------"  ;
    DR_LOG(log_debug) << "m_mapCallId2Invite size:                                         " << m_mapCallId2Invite.size()  ;
    DR_LOG(log_debug) << "m_mapTxnId2Invite size:                                          " << m_mapTxnId2Invite.size()  ;
  }

} ;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Toni Gundogdu.
 *
 * This file is part of cclive.
 *
 * cclive is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * cclive 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include <fstream>
#include <string>
#include <vector>

#ifdef HAVE_ICONV
#include <cerrno>
#include <iconv.h>
#endif

#include "hosthandler.h"
#include "opts.h"
#include "log.h"
#include "curl.h"

HostHandler::HostHandler()
    : pageContent(""), props(VideoProperties())
{
}

HostHandler::~HostHandler() {
}

const bool
HostHandler::isHost(std::string url) {
    return Util::toLower(url).find(props.getDomain())
        != std::string::npos;
}

void
HostHandler::parsePage(const std::string& url) {

    props.setPageLink(url);
    pageContent = curlmgr.fetchToMem(url);

    // Call overridden functions.
    parseTitle();
    parseId   ();
    parseLink ();

    // Handle title encoding. Done here since we still have page html.
    toUnicode();

    // Apply regexp.
    std::string title = props.getTitle();

    if (optsmgr.getOptions().regexp_given)
        applyRegexp(title);

    // Remove leading and trailing whitespace.
    pcrecpp::RE("^[\\s]+").Replace("", &title);
    pcrecpp::RE("\\s+$").Replace("", &title);

    props.setTitle(title);

    pageContent.clear();
}

void
HostHandler::toUnicode() {
#ifdef HAVE_ICONV
    std::string charset;

    // Skip if charset was not found.
    try   { partialMatch("(?i)charset=\"?(.*?)([\"\\/>\\s]|$)", &charset); }
    catch (const HostHandler::ParseException& x) { return; }

    std::string from = charset;
    std::string to   = "UTF-8//TRANSLIT";

    iconv_t cd =
        iconv_open( to.c_str(), from.c_str() );

    if (cd == (iconv_t)-1) {
        if (errno == EINVAL) {
            logmgr.cerr()
                << "error: conversion from \""
                << from
                << "\" to \""
                << to
                << "\" unavailable"
                << std::endl;
        }
        else {
            perror("iconv_popen");
                return;
        }
    }

    char inbuf[256];
    ICONV_CONST char *inptr = inbuf;
    size_t insize = props.getTitle().length();

    if (insize >= sizeof(inbuf))
        insize = sizeof(inbuf);

    snprintf(inbuf, sizeof(inbuf),
        "%s", props.getTitle().c_str());

    char outbuf[256];
    size_t avail = sizeof(outbuf);
    char *wptr   = (char *)outbuf;
    memset(wptr, 0, sizeof(outbuf));

    const size_t rc =
        iconv(cd, &inptr, &insize, &wptr, &avail);

    iconv_close(cd);
    cd = 0;

    if (rc == (size_t)-1) {
        logmgr.cerr()
            << "error: converting characters from \""
            << from
            << "\" to \""
            << to
            << "\" failed"
            << std::endl;
    }

    props.setTitle(outbuf);
#endif
}

void
HostHandler::applyRegexp(std::string& title) {

    const Options opts = optsmgr.getOptions();

    if (opts.find_all_given) {
        pcrecpp::StringPiece sp(title);
        pcrecpp::RE re(opts.regexp_arg, pcrecpp::UTF8());

        title.clear();

        std::string s;
        while (re.FindAndConsume(&sp, &s))
            title += s;
    }
    else {
        std::string tmp = title;
        title.clear();

        pcrecpp::RE(opts.regexp_arg, pcrecpp::UTF8())
            .PartialMatch(tmp, &title);
    }

    props.setTitle(title);
}

void
HostHandler::partialMatch(
    const std::string& re,
    const pcrecpp::Arg& dst,
    const std::string& data/*=""*/)
{
    const std::string& content = !data.empty() ? data : pageContent;
    if (!pcrecpp::RE(re).PartialMatch(content, dst))
        throw HostHandler::ParseException("no match: "+re);
}

const VideoProperties&
HostHandler::getVideoProperties() const {
    return props;
}

HostHandler::
    ParseException::ParseException(const std::string& error)
        : RuntimeException(CCLIVE_PARSE, error)
{
}
<commit_msg>iconv: correct use of translit.<commit_after>/*
 * Copyright (C) 2009 Toni Gundogdu.
 *
 * This file is part of cclive.
 *
 * cclive is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * cclive 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include <fstream>
#include <string>
#include <vector>

#ifdef HAVE_ICONV
#include <cerrno>
#include <iconv.h>
#endif

#include "hosthandler.h"
#include "opts.h"
#include "log.h"
#include "curl.h"

HostHandler::HostHandler()
    : pageContent(""), props(VideoProperties())
{
}

HostHandler::~HostHandler() {
}

const bool
HostHandler::isHost(std::string url) {
    return Util::toLower(url).find(props.getDomain())
        != std::string::npos;
}

void
HostHandler::parsePage(const std::string& url) {

    props.setPageLink(url);
    pageContent = curlmgr.fetchToMem(url);

    // Call overridden functions.
    parseTitle();
    parseId   ();
    parseLink ();

    // Handle title encoding. Done here since we still have page html.
    toUnicode();

    // Apply regexp.
    std::string title = props.getTitle();

    if (optsmgr.getOptions().regexp_given)
        applyRegexp(title);

    // Remove leading and trailing whitespace.
    pcrecpp::RE("^[\\s]+").Replace("", &title);
    pcrecpp::RE("\\s+$").Replace("", &title);

    props.setTitle(title);

    pageContent.clear();
}

void
HostHandler::toUnicode() {
#ifdef HAVE_ICONV
    std::string charset;

    // Skip if charset was not found.
    try   { partialMatch("(?i)charset=\"?(.*?)([\"\\/>\\s]|$)", &charset); }
    catch (const HostHandler::ParseException& x) { return; }

    std::string from = charset;
    std::string to   = "UTF-8";

    // Try with TRANSLIT first.
    iconv_t cd =
        iconv_open( to.c_str(), std::string(from+"//TRANSLIT").c_str() );

    if (cd == (iconv_t)-1) {
        // Without TRANSLIT.
        cd = iconv_open( to.c_str(), from.c_str());
    }

    if (cd == (iconv_t)-1) {
        if (errno == EINVAL) {
            logmgr.cerr()
                << "error: conversion from \""
                << from
                << "\" to \""
                << to
                << "\" unavailable"
                << std::endl;
        }
        else {
            perror("iconv_popen");
                return;
        }
    }

    char inbuf[256];
    ICONV_CONST char *inptr = inbuf;
    size_t insize = props.getTitle().length();

    if (insize >= sizeof(inbuf))
        insize = sizeof(inbuf);

    snprintf(inbuf, sizeof(inbuf),
        "%s", props.getTitle().c_str());

    char outbuf[256];
    size_t avail = sizeof(outbuf);
    char *wptr   = (char *)outbuf;
    memset(wptr, 0, sizeof(outbuf));

    const size_t rc =
        iconv(cd, &inptr, &insize, &wptr, &avail);

    iconv_close(cd);
    cd = 0;

    if (rc == (size_t)-1) {
        logmgr.cerr()
            << "error: converting characters from \""
            << from
            << "\" to \""
            << to
            << "\" failed"
            << std::endl;
    }

    props.setTitle(outbuf);
#endif
}

void
HostHandler::applyRegexp(std::string& title) {

    const Options opts = optsmgr.getOptions();

    if (opts.find_all_given) {
        pcrecpp::StringPiece sp(title);
        pcrecpp::RE re(opts.regexp_arg, pcrecpp::UTF8());

        title.clear();

        std::string s;
        while (re.FindAndConsume(&sp, &s))
            title += s;
    }
    else {
        std::string tmp = title;
        title.clear();

        pcrecpp::RE(opts.regexp_arg, pcrecpp::UTF8())
            .PartialMatch(tmp, &title);
    }

    props.setTitle(title);
}

void
HostHandler::partialMatch(
    const std::string& re,
    const pcrecpp::Arg& dst,
    const std::string& data/*=""*/)
{
    const std::string& content = !data.empty() ? data : pageContent;
    if (!pcrecpp::RE(re).PartialMatch(content, dst))
        throw HostHandler::ParseException("no match: "+re);
}

const VideoProperties&
HostHandler::getVideoProperties() const {
    return props;
}

HostHandler::
    ParseException::ParseException(const std::string& error)
        : RuntimeException(CCLIVE_PARSE, error)
{
}
<|endoftext|>


<commit_before>#include "config.h"

#include <algorithm>
#include <functional>

#include "http_client.h"
#include "exception.h"
#include <cinttypes>
#ifndef HAVE_LIBCURL
#include "buffered_socket.h"
#else
#include <cstring>
#endif

namespace arg3
{
    namespace net
    {
#define THIS_USER_AGENT "libarg3net"

#ifdef HAVE_LIBCURL

        size_t curl_append_response_callback(void *ptr, size_t size, size_t nmemb, string *s)
        {
            if (s == NULL) return 0;

            const size_t new_len = size * nmemb;

            char buf[new_len + 1];

            memcpy(buf, ptr, size * nmemb);

            buf[new_len] = '\0';

            s->append(buf);

            return new_len;
        }
#endif

        size_t skip_newline(const string &s, size_t pos)
        {
            for (int i = 0; i < 2; i++, pos++)
            {
                if (s[pos] != '\r' && s[pos] != '\n')
                    break;
            }

            return pos;
        }

        http_transfer::http_transfer() : version_(http::VERSION_1_1) {}

        http_transfer::http_transfer(const http_transfer &other) : payload_(other.payload_), headers_(other.headers_), version_(other.version_)
        {}

        http_transfer::http_transfer(http_transfer &&other) : payload_(std::move(other.payload_)),
            headers_(std::move(other.headers_)), version_(std::move(other.version_))
        {}

        http_transfer::~http_transfer() {}

        http_transfer &http_transfer::operator=(const http_transfer &other)
        {
            payload_ = other.payload_;
            headers_ = other.headers_;
            version_ = other.version_;
            return *this;
        }

        http_transfer &http_transfer::operator=(http_transfer && other)
        {
            payload_ = std::move(other.payload_);
            headers_ = std::move(other.headers_);
            version_ = std::move(other.version_);
            return *this;
        }

        string http_transfer::header(const string &key)
        {
            return headers_[key];
        }

        const map<string, string> http_transfer::headers() const
        {
            return headers_;
        }

        string http_transfer::payload() const
        {
            return payload_;
        }

        string http_transfer::version() const
        {
            return version_;
        }

        void http_transfer::set_version(const string &value)
        {
            version_ = value;
        }

        http_response::http_response() : responseCode_(0)
        {}

        http_response::http_response(const string &fullResponse) : response_(fullResponse), responseCode_(0)
        {
            parse();
        }

        http_response::http_response(const http_response &other) : http_transfer(other), response_(other.response_),
            responseCode_(other.responseCode_)
        {}

        http_response::http_response(http_response &&other) : http_transfer(std::move(other)), response_(std::move(other.response_)),
            responseCode_(std::move(other.responseCode_))
        {}

        http_response::~http_response() {}

        http_response &http_response::operator=(const http_response &other)
        {
            http_transfer::operator=(other);

            response_ = other.response_;

            responseCode_ = other.responseCode_;

            return *this;
        }

        http_response &http_response::operator=(http_response && other)
        {
            http_transfer::operator=(std::move(other));

            response_ = std::move(other.response_);

            responseCode_ = std::move(other.responseCode_);

            return *this;
        }

        string http_response::full_response() const
        {
            return response_;
        }

        http_response::operator string() const
        {
            return payload_;
        }

        int http_response::code() const
        {
            return responseCode_;
        }

        void http_response::parse(const string &value)
        {
            response_ = value;

            parse();
        }

        void http_response::clear()
        {
            response_.clear();
            responseCode_ = 0;
            headers_.clear();
            payload_.clear();

        }

        void http_response::parse()
        {
            auto pos = response_.find("\r\n");

            if (pos == string::npos)
            {
                payload_ = response_;
                return;
            }

            string line = response_.substr(0, pos);

            char buf[http::MAX_URL_LEN + 1] = {0};

            char version[http::MAX_URL_LEN + 1] = {0};

            if (sscanf(line.c_str(), http::RESPONSE_PREAMBLE, version, &responseCode_, buf) != 3)
            {
                payload_ = response_;
                return;
            }

            version_ = version;

            pos = skip_newline(response_, pos);

            while (!line.empty())
            {
                auto next = response_.find("\r\n", pos);

                if (next == string::npos) break;

                line = response_.substr(pos, next - pos);

                auto sep = line.find(':');

                if (sep != string::npos)
                {
                    auto key = line.substr(0, sep);

                    auto value = line.substr(sep + 2);

                    headers_[key] = value;
                }

                pos = skip_newline(response_, next);
            }

            if (pos != string::npos)
                payload_ = response_.substr(pos);
        }

        http_client::http_client(const string &host) : scheme_(http::SCHEME), host_(host)
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::http_client()
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::~http_client()
        {
        }

        http_client::http_client(const http_client &other) : http_transfer(other), scheme_(other.scheme_), host_(other.host_),
            response_(other.response_)
        {
        }

        http_client::http_client(http_client &&other) : http_transfer(std::move(other)), scheme_(std::move(other.scheme_)), host_(std::move(other.host_)),
            response_(std::move(other.response_))
        {
        }

        http_client &http_client::operator=(const http_client &other)
        {
            http_transfer::operator=(other);
            scheme_ = other.scheme_;
            host_ = other.host_;
            headers_ = other.headers_;
            return *this;
        }

        http_client &http_client::operator=(http_client && other)
        {
            http_transfer::operator=(std::move(other));
            scheme_ = std::move(other.scheme_);
            host_ = std::move(other.host_);
            response_ = std::move(other.response_);
            return *this;
        }

        http_client &http_client::add_header(const string &key, const string &value)
        {
            headers_[key] = value;
            return *this;
        }

        void http_client::remove_header(const string &key)
        {
            headers_.erase(key);
        }

        string http_client::host() const
        {
            return host_;
        }

        http_response http_client::response() const
        {
            return response_;
        }

        bool http_client::is_secure() const
        {
            return scheme_ == http::SECURE_SCHEME;
        }

        http_client &http_client::set_host(const string &host)
        {
            host_ = host;
            return *this;
        }

        http_client &http_client::set_secure(bool value)
        {
            scheme_ = value ? http::SECURE_SCHEME : http::SCHEME;
            return *this;
        }

        http_client &http_client::set_payload(const string &payload)
        {
            payload_ = payload;
            return *this;
        }

#ifdef HAVE_LIBCURL
        void http_client::request_curl(http::method method, const string &path)
        {

            char buf[http::MAX_URL_LEN + 1] = {0};

            struct curl_slist *headers = NULL;

            CURL *curl_ = curl_easy_init();

            if (curl_ == NULL)
            {
                throw rest_exception("unable to initialize request");
            }

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, "%s://%s", scheme_.c_str(), host_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, "%s://%s%s", scheme_.c_str(), host_.c_str(), path.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, "%s://%s/%s", scheme_.c_str(), host_.c_str(), path.c_str());

            curl_easy_setopt(curl_, CURLOPT_URL, buf);

            curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curl_append_response_callback);

            curl_easy_setopt(curl_, CURLOPT_HEADER, 1L);

#ifdef DEBUG
            curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);
#endif

            switch (method)
            {
            case http::GET:
                curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L);
                break;
            case http::POST:
                curl_easy_setopt(curl_, CURLOPT_POST, 1L);
                if (!payload_.empty())
                {
                    curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                    curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                }
                break;
            case http::PUT:
                curl_easy_setopt(curl_, CURLOPT_PUT, 1L);
                if (!payload_.empty())
                {
                    curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                    curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                }
            case http::DELETE:
                curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, http::method_names[http::DELETE]);
                break;
            }

            for (auto &h : headers_)
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                headers = curl_slist_append(headers, buf);
            }

            curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers);

            curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response_.response_);

            CURLcode res = curl_easy_perform(curl_);

            if (res != CURLE_OK)
            {
                curl_easy_cleanup(curl_);

                throw rest_exception(curl_easy_strerror(res));
            }

            curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &response_.responseCode_);

            curl_easy_cleanup(curl_);

            response_.parse();
        }
#else
        void http_client::request_socket(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            buffered_socket sock;

            // create the socket based on hostname and port
            auto pos = host().find(':');

            if (is_secure())
                sock.set_secure(true);

            if (pos != string::npos)
            {
                string hostname = host().substr(0, pos);
                int port = stoi(host().substr(pos + 1));

                if (!sock.connect(hostname, port))
                    throw socket_exception("unable to connect to " + host());
            }
            else
            {
                if (!sock.connect(host(), is_secure() ? http::DEFAULT_SECURE_PORT : http::DEFAULT_PORT))
                    throw socket_exception("unable to connect to " + host());
            }

            // send the method and path

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], "/", version_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], path.c_str(), version_.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], ("/" + path).c_str(), version_.c_str());

            sock.writeln(buf);

            bool chunked = headers_.count(http::HEADER_TRANSFER_ENCODING) != 0 && !strcasecmp(headers_[http::HEADER_TRANSFER_ENCODING].c_str(), "chunked");

            // specify the host
            if (headers_.count(http::HEADER_HOST) == 0)
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", http::HEADER_HOST, host().c_str());
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_ACCEPT) == 0)
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: */*", http::HEADER_ACCEPT);
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_CONNECTION) == 0)
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: close", http::HEADER_CONNECTION);
                sock.writeln(buf);
            }

            // add the headers
            for (const auto &h : headers_)
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                sock.writeln(buf);
            }

            // if we have a payload, add the size
            if (!chunked && !payload_.empty())
            {
                snprintf(buf, http::MAX_URL_LEN, "%s: %zu", http::HEADER_CONTENT_SIZE, payload_.size());

                sock.writeln(buf);
            }

            // finish header
            sock.writeln();

            // add the payload
            if (!payload_.empty())
            {
                sock.write(payload_);
            }

#ifdef DEBUG
            cout << string(sock.output().begin(), sock.output().end());
#endif

            if (!sock.write_from_buffer())
                throw socket_exception("unable to write to socket");

            if (!sock.read_to_buffer())
                throw socket_exception("unable to read from socket");

            auto input = sock.input();

            response_.parse(string(input.begin(), input.end()));

            //sock.close();
        }
#endif

        http_client &http_client::request(http::method method, const string &path)
        {
            response_.clear();

            if (host_.empty())
                throw socket_exception("no host");

#ifdef HAVE_LIBCURL
            request_curl(method, path);
#else
            request_socket(method, path);
#endif

            return *this;
        }

        http_client &http_client::get(const string &path)
        {
            return request(http::GET, path);
        }

        http_client &http_client::post(const string &path)
        {
            return request(http::POST, path);
        }

        http_client &http_client::put(const string &path)
        {
            return request(http::PUT, path);
        }

        http_client &http_client::de1ete(const string &path)
        {
            return request(http::DELETE, path);
        }
    }
}
<commit_msg>fix header issue<commit_after>#include "config.h"

#include <algorithm>
#include <functional>

#include "http_client.h"
#include "exception.h"
#include <cinttypes>
#ifndef HAVE_LIBCURL
#include "buffered_socket.h"
#else
#include <strings.h>
#endif

namespace arg3
{
    namespace net
    {
#define THIS_USER_AGENT "libarg3net"

#ifdef HAVE_LIBCURL

        size_t curl_append_response_callback(void *ptr, size_t size, size_t nmemb, string *s)
        {
            if (s == NULL) return 0;

            const size_t new_len = size * nmemb;

            char buf[new_len + 1];

            memcpy(buf, ptr, size * nmemb);

            buf[new_len] = '\0';

            s->append(buf);

            return new_len;
        }
#endif

        size_t skip_newline(const string &s, size_t pos)
        {
            for (int i = 0; i < 2; i++, pos++) {
                if (s[pos] != '\r' && s[pos] != '\n') break;
            }

            return pos;
        }

        http_transfer::http_transfer() : version_(http::VERSION_1_1)
        {
        }

        http_transfer::http_transfer(const http_transfer &other) : payload_(other.payload_), headers_(other.headers_), version_(other.version_)
        {
        }

        http_transfer::http_transfer(http_transfer &&other)
            : payload_(std::move(other.payload_)), headers_(std::move(other.headers_)), version_(std::move(other.version_))
        {
        }

        http_transfer::~http_transfer()
        {
        }

        http_transfer &http_transfer::operator=(const http_transfer &other)
        {
            payload_ = other.payload_;
            headers_ = other.headers_;
            version_ = other.version_;
            return *this;
        }

        http_transfer &http_transfer::operator=(http_transfer &&other)
        {
            payload_ = std::move(other.payload_);
            headers_ = std::move(other.headers_);
            version_ = std::move(other.version_);
            return *this;
        }

        string http_transfer::header(const string &key)
        {
            return headers_[key];
        }

        const map<string, string> http_transfer::headers() const
        {
            return headers_;
        }

        string http_transfer::payload() const
        {
            return payload_;
        }

        string http_transfer::version() const
        {
            return version_;
        }

        void http_transfer::set_version(const string &value)
        {
            version_ = value;
        }

        http_response::http_response() : responseCode_(0)
        {
        }

        http_response::http_response(const string &fullResponse) : response_(fullResponse), responseCode_(0)
        {
            parse();
        }

        http_response::http_response(const http_response &other)
            : http_transfer(other), response_(other.response_), responseCode_(other.responseCode_)
        {
        }

        http_response::http_response(http_response &&other)
            : http_transfer(std::move(other)), response_(std::move(other.response_)), responseCode_(std::move(other.responseCode_))
        {
        }

        http_response::~http_response()
        {
        }

        http_response &http_response::operator=(const http_response &other)
        {
            http_transfer::operator=(other);

            response_ = other.response_;

            responseCode_ = other.responseCode_;

            return *this;
        }

        http_response &http_response::operator=(http_response &&other)
        {
            http_transfer::operator=(std::move(other));

            response_ = std::move(other.response_);

            responseCode_ = std::move(other.responseCode_);

            return *this;
        }

        string http_response::full_response() const
        {
            return response_;
        }

        http_response::operator string() const
        {
            return payload_;
        }

        int http_response::code() const
        {
            return responseCode_;
        }

        void http_response::parse(const string &value)
        {
            response_ = value;

            parse();
        }

        void http_response::clear()
        {
            response_.clear();
            responseCode_ = 0;
            headers_.clear();
            payload_.clear();
        }

        void http_response::parse()
        {
            auto pos = response_.find("\r\n");

            if (pos == string::npos) {
                payload_ = response_;
                return;
            }

            string line = response_.substr(0, pos);

            char buf[http::MAX_URL_LEN + 1] = {0};

            char version[http::MAX_URL_LEN + 1] = {0};

            if (sscanf(line.c_str(), http::RESPONSE_PREAMBLE, version, &responseCode_, buf) != 3) {
                payload_ = response_;
                return;
            }

            version_ = version;

            pos = skip_newline(response_, pos);

            while (!line.empty()) {
                auto next = response_.find("\r\n", pos);

                if (next == string::npos) break;

                line = response_.substr(pos, next - pos);

                auto sep = line.find(':');

                if (sep != string::npos) {
                    auto key = line.substr(0, sep);

                    auto value = line.substr(sep + 2);

                    headers_[key] = value;
                }

                pos = skip_newline(response_, next);
            }

            if (pos != string::npos) payload_ = response_.substr(pos);
        }

        http_client::http_client(const string &host) : scheme_(http::SCHEME), host_(host)
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::http_client()
        {
            add_header(http::HEADER_USER_AGENT, THIS_USER_AGENT);
        }

        http_client::~http_client()
        {
        }

        http_client::http_client(const http_client &other)
            : http_transfer(other), scheme_(other.scheme_), host_(other.host_), response_(other.response_)
        {
        }

        http_client::http_client(http_client &&other)
            : http_transfer(std::move(other)), scheme_(std::move(other.scheme_)), host_(std::move(other.host_)), response_(std::move(other.response_))
        {
        }

        http_client &http_client::operator=(const http_client &other)
        {
            http_transfer::operator=(other);
            scheme_ = other.scheme_;
            host_ = other.host_;
            headers_ = other.headers_;
            return *this;
        }

        http_client &http_client::operator=(http_client &&other)
        {
            http_transfer::operator=(std::move(other));
            scheme_ = std::move(other.scheme_);
            host_ = std::move(other.host_);
            response_ = std::move(other.response_);
            return *this;
        }

        http_client &http_client::add_header(const string &key, const string &value)
        {
            headers_[key] = value;
            return *this;
        }

        void http_client::remove_header(const string &key)
        {
            headers_.erase(key);
        }

        string http_client::host() const
        {
            return host_;
        }

        http_response http_client::response() const
        {
            return response_;
        }

        bool http_client::is_secure() const
        {
            return scheme_ == http::SECURE_SCHEME;
        }

        http_client &http_client::set_host(const string &host)
        {
            host_ = host;
            return *this;
        }

        http_client &http_client::set_secure(bool value)
        {
            scheme_ = value ? http::SECURE_SCHEME : http::SCHEME;
            return *this;
        }

        http_client &http_client::set_payload(const string &payload)
        {
            payload_ = payload;
            return *this;
        }

#ifdef HAVE_LIBCURL
        void http_client::request_curl(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            struct curl_slist *headers = NULL;

            CURL *curl_ = curl_easy_init();

            if (curl_ == NULL) {
                throw rest_exception("unable to initialize request");
            }

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, "%s://%s", scheme_.c_str(), host_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, "%s://%s%s", scheme_.c_str(), host_.c_str(), path.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, "%s://%s/%s", scheme_.c_str(), host_.c_str(), path.c_str());

            curl_easy_setopt(curl_, CURLOPT_URL, buf);

            curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curl_append_response_callback);

            curl_easy_setopt(curl_, CURLOPT_HEADER, 1L);

#ifdef DEBUG
            curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);
#endif

            switch (method) {
                case http::GET:
                    curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L);
                    break;
                case http::POST:
                    curl_easy_setopt(curl_, CURLOPT_POST, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                    break;
                case http::PUT:
                    curl_easy_setopt(curl_, CURLOPT_PUT, 1L);
                    if (!payload_.empty()) {
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, payload_.c_str());
                        curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, payload_.size());
                    }
                case http::DELETE:
                    curl_easy_setopt(curl_, CURLOPT_CUSTOMREQUEST, http::method_names[http::DELETE]);
                    break;
            }

            for (auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                headers = curl_slist_append(headers, buf);
            }

            curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers);

            curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response_.response_);

            CURLcode res = curl_easy_perform(curl_);

            if (res != CURLE_OK) {
                curl_easy_cleanup(curl_);

                throw rest_exception(curl_easy_strerror(res));
            }

            curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &response_.responseCode_);

            curl_easy_cleanup(curl_);

            response_.parse();
        }
#else
        void http_client::request_socket(http::method method, const string &path)
        {
            char buf[http::MAX_URL_LEN + 1] = {0};

            buffered_socket sock;

            // create the socket based on hostname and port
            auto pos = host().find(':');

            if (is_secure()) sock.set_secure(true);

            if (pos != string::npos) {
                string hostname = host().substr(0, pos);
                int port = stoi(host().substr(pos + 1));

                if (!sock.connect(hostname, port)) throw socket_exception("unable to connect to " + host());
            } else {
                if (!sock.connect(host(), is_secure() ? http::DEFAULT_SECURE_PORT : http::DEFAULT_PORT))
                    throw socket_exception("unable to connect to " + host());
            }

            // send the method and path

            if (path.empty())
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], "/", version_.c_str());
            else if (path[0] == '/')
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], path.c_str(), version_.c_str());
            else
                snprintf(buf, http::MAX_URL_LEN, http::REQUEST_PREAMBLE, http::method_names[method], ("/" + path).c_str(), version_.c_str());

            sock.writeln(buf);

            bool chunked =
                headers_.count(http::HEADER_TRANSFER_ENCODING) != 0 && !strcasecmp(headers_[http::HEADER_TRANSFER_ENCODING].c_str(), "chunked");

            // specify the host
            if (headers_.count(http::HEADER_HOST) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", http::HEADER_HOST, host().c_str());
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_ACCEPT) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: */*", http::HEADER_ACCEPT);
                sock.writeln(buf);
            }

            if (headers_.count(http::HEADER_CONNECTION) == 0) {
                snprintf(buf, http::MAX_URL_LEN, "%s: close", http::HEADER_CONNECTION);
                sock.writeln(buf);
            }

            // add the headers
            for (const auto &h : headers_) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %s", h.first.c_str(), h.second.c_str());

                sock.writeln(buf);
            }

            // if we have a payload, add the size
            if (!chunked && !payload_.empty()) {
                snprintf(buf, http::MAX_URL_LEN, "%s: %zu", http::HEADER_CONTENT_SIZE, payload_.size());

                sock.writeln(buf);
            }

            // finish header
            sock.writeln();

            // add the payload
            if (!payload_.empty()) {
                sock.write(payload_);
            }

#ifdef DEBUG
            cout << string(sock.output().begin(), sock.output().end());
#endif

            if (!sock.write_from_buffer()) throw socket_exception("unable to write to socket");

            if (!sock.read_to_buffer()) throw socket_exception("unable to read from socket");

            auto input = sock.input();

            response_.parse(string(input.begin(), input.end()));

            // sock.close();
        }
#endif

        http_client &http_client::request(http::method method, const string &path)
        {
            response_.clear();

            if (host_.empty()) throw socket_exception("no host");

#ifdef HAVE_LIBCURL
            request_curl(method, path);
#else
            request_socket(method, path);
#endif

            return *this;
        }

        http_client &http_client::get(const string &path)
        {
            return request(http::GET, path);
        }

        http_client &http_client::post(const string &path)
        {
            return request(http::POST, path);
        }

        http_client &http_client::put(const string &path)
        {
            return request(http::PUT, path);
        }

        http_client &http_client::de1ete(const string &path)
        {
            return request(http::DELETE, path);
        }
    }
}
<|endoftext|>


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

#include "http_client.h"

#include "str_helpers.h"

#include <iomanip>
#include <sstream>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

multipart_form_data::multipart_form_data()
{
    boost::uuids::random_generator gen;
    m_boundary = boost::uuids::to_string(gen());
}

void multipart_form_data::add_value(const std::string& name, const std::string& value)
{
    m_body += "--" + m_boundary + "\r\n";
    m_body += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n";
    m_body += value;
    m_body += "\r\n";
}

void multipart_form_data::add_file(const std::string& name, const std::string& filename, const std::string& file_content)
{
    m_body += "--" + m_boundary + "\r\n";
    m_body += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n";
    m_body += "Content-Type: application/octet-stream\r\n";
    m_body += "Content-Transfer-Encoding: binary\r\n";
    m_body += "\r\n";
    m_body += file_content;
    m_body += "\r\n";
}

std::string multipart_form_data::content_type() const
{
    return "multipart/form-data; boundary=" + m_boundary;
}

std::string multipart_form_data::body() const
{
    return m_body + "--" + m_boundary + "--\r\n\r\n";
}

void urlencoded_data::add_value(const std::string& name, const std::string& value)
{
    if (!m_body.empty())
        m_body += '&';
    m_body += name;
    m_body += '=';
    m_body += http_client::url_encode(value);
}

std::string http_client::url_encode(const std::string& s)
{
    std::ostringstream escaped;
    escaped.fill('0');
    escaped << std::hex;

    for (auto c: s)
    {
        if (c == '-' || c == '_' || c == '.' || c == '~' ||
            (c >= 'a' && c <= 'z') ||
            (c >= 'A' && c <= 'Z') ||
            (c >= '0' && c <= '9'))
        {
            escaped << c;
        }
        else
        {
            escaped << '%' << std::setw(2) << int((unsigned char)c);
        }
    }

    return escaped.str();
}

std::string http_client::url_encode(const std::wstring& s)
{
    return url_encode(str::to_utf8(s));
}
<commit_msg>Use + in urlencoded data in http_client<commit_after>/*
 *  This file is part of Poedit (http://poedit.net)
 *
 *  Copyright (C) 2015 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "http_client.h"

#include "str_helpers.h"

#include <iomanip>
#include <sstream>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

multipart_form_data::multipart_form_data()
{
    boost::uuids::random_generator gen;
    m_boundary = boost::uuids::to_string(gen());
}

void multipart_form_data::add_value(const std::string& name, const std::string& value)
{
    m_body += "--" + m_boundary + "\r\n";
    m_body += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n";
    m_body += value;
    m_body += "\r\n";
}

void multipart_form_data::add_file(const std::string& name, const std::string& filename, const std::string& file_content)
{
    m_body += "--" + m_boundary + "\r\n";
    m_body += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n";
    m_body += "Content-Type: application/octet-stream\r\n";
    m_body += "Content-Transfer-Encoding: binary\r\n";
    m_body += "\r\n";
    m_body += file_content;
    m_body += "\r\n";
}

std::string multipart_form_data::content_type() const
{
    return "multipart/form-data; boundary=" + m_boundary;
}

std::string multipart_form_data::body() const
{
    return m_body + "--" + m_boundary + "--\r\n\r\n";
}

void urlencoded_data::add_value(const std::string& name, const std::string& value)
{
    if (!m_body.empty())
        m_body += '&';
    m_body += name;
    m_body += '=';
    m_body += http_client::url_encode(value);
}

std::string http_client::url_encode(const std::string& s)
{
    std::ostringstream escaped;
    escaped.fill('0');
    escaped << std::hex;

    for (auto c: s)
    {
        if (c == '-' || c == '_' || c == '.' || c == '~' ||
            (c >= 'a' && c <= 'z') ||
            (c >= 'A' && c <= 'Z') ||
            (c >= '0' && c <= '9'))
        {
            escaped << c;
        }
        else if (c == ' ')
        {
            escaped << '+';
        }
        else
        {
            escaped << '%' << std::setw(2) << int((unsigned char)c);
        }
    }

    return escaped.str();
}

std::string http_client::url_encode(const std::wstring& s)
{
    return url_encode(str::to_utf8(s));
}
<|endoftext|>


<commit_before>#include <string>
#include <fstream>
#include <iostream>
#include <utility>
#include <cstdio>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>

#include "dwarf/dwarf++.hh"
#include "elf/elf++.hh"

#include "linenoise.h"

class breakpoint {
public:
    breakpoint(pid_t pid, std::intptr_t addr) : m_pid{pid}, m_addr{addr}, m_enabled{false}, m_saved_data{} {}
    void enable() {
        m_saved_data = ptrace(PTRACE_PEEKTEXT, m_pid, (void*)m_addr, 0);
        auto int3 = 0xcc;
        auto data_with_int3 = (m_saved_data & ~0xff | int3);
        ptrace(PTRACE_POKETEXT, m_pid, (void*)m_addr, data_with_int3);

        m_enabled = true;
    }

    void disable() {
        ptrace(PTRACE_POKETEXT, m_pid, (void*)m_addr, m_saved_data);
        m_enabled = false;
    }

    std::intptr_t get_address() { return m_addr; }
private:
    pid_t m_pid;
    std::intptr_t m_addr;
    bool m_enabled;
    unsigned m_saved_data;
};

class debugger {
public:
    debugger (std::string prog_name, pid_t pid)
        : m_prog_name{std::move(prog_name)}, m_pid{pid} {
            auto fd = open(m_prog_name.c_str(), O_RDONLY);

            m_elf = elf::elf{elf::create_mmap_loader(fd)};
            m_dwarf = dwarf::dwarf{dwarf::elf::create_loader(m_elf)};
        }

    void run();
    void dump_registers();
    void continue_execution();
    void single_step_instruction();
    siginfo_t get_signal_info();
    void set_breakpoint_at_address(std::intptr_t addr);
    void set_breakpoint_at_source_line(const std::string& file, unsigned line);
    void print_source(const std::string& file_name, unsigned line, unsigned n_lines_context=2);

private:
    void handle_command(const std::string& line);
    void handle_sigtrap(siginfo_t info);
    void wait_for_signal();
    uint64_t get_pc();
    void set_pc(uint64_t pc);
    void decrement_pc();
    dwarf::line_table::entry get_current_line_entry();

    std::string m_prog_name;
    pid_t m_pid;
    dwarf::dwarf m_dwarf;
    elf::elf m_elf;
    unsigned m_saved_data;
    std::unique_ptr<breakpoint> m_breakpoint;
};

uint64_t debugger::get_pc() {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  return regs.rip;
}

void debugger::set_pc(uint64_t pc) {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  regs.rip = pc;
  ptrace(PTRACE_SETREGS, m_pid, nullptr, &regs);
}

void debugger::decrement_pc() {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  regs.rip -= 1;
  ptrace(PTRACE_SETREGS, m_pid, nullptr, &regs);
}

dwarf::line_table::entry debugger::get_current_line_entry() {
    auto pc = get_pc();

    for (auto &cu : m_dwarf.compilation_units()) {
        if (die_pc_range(cu.root()).contains(pc)) {
            auto &lt = cu.get_line_table();
            auto it = lt.find_address(pc);
            if (it == lt.end()) {
                throw std::out_of_range{"Cannot find line entry"};
            }
            else {
                return *it;
            }
        }
    }

    throw std::out_of_range{"Cannot find line entry"};
}

void debugger::run() {
    char* line = nullptr;
    while((line = linenoise("minidbg> ")) != nullptr) {
        handle_command(line);
        linenoiseHistoryAdd(line);
        linenoiseFree(line);
    }
}

void debugger::print_source(const std::string& file_name, unsigned line, unsigned n_lines_context) {
    std::ifstream file {file_name};
    auto start_line = line < n_lines_context ? 0 : line - n_lines_context;
    auto end_line = line + n_lines_context + (line < n_lines_context ? n_lines_context - line : 0) + 1;

    char c{};
    auto current_line = 1u;
    while (current_line != start_line && file.get(c)) {
        if (c == '\n') {
            ++current_line;
        }
    }
    std::cout << (current_line==line ? "> " : "  ");
    while (current_line != end_line && file.get(c)) {
        std::cout << c;
        if (c == '\n') {
            ++current_line;
            std::cout << (current_line==line ? "> " : "  ");
        }
    }
    std::cout << std::endl;
}

bool is_prefix(const std::string& s, const std::string& of) {
    if (s.size() > of.size()) return false;
    return std::equal(s.begin(), s.end(), of.begin());
}

bool is_suffix(const std::string& s, const std::string& of) {
    if (s.size() > of.size()) return false;
    auto diff = of.size() - s.size();
    return std::equal(s.begin(), s.end(), of.begin() + diff);
}

siginfo_t debugger::get_signal_info() {
    siginfo_t info;
    ptrace(PTRACE_GETSIGINFO, m_pid, nullptr, &info);
    return info;
}

void debugger::handle_sigtrap(siginfo_t info) {
    switch (info.si_code) {
    case SI_KERNEL:
    case TRAP_BRKPT:
    {
        std::cout << "Hit breakpoint at address 0x" << std::hex << get_pc() << std::endl;
        auto line_entry = get_current_line_entry();
        print_source(line_entry.file->path, line_entry.line);
        return;
    }
    case TRAP_TRACE:
        std::cout << "Finished single stepping" << std::endl;
        return;
    default:
        std::cout << "Unknown SIGTRAP code " << info.si_code << std::endl;
        return;
    }
}

void debugger::wait_for_signal() {
    int wait_status;
    auto options = 0;
    waitpid(m_pid, &wait_status, options);

    auto siginfo = get_signal_info();

    switch (siginfo.si_signo) {
    case SIGTRAP:
        handle_sigtrap(siginfo);
        break;
    case SIGSEGV:
        std::cout << "Yay, segfault" << std::endl;
        break;
    default:
        std::cout << "Got signal " << strsignal(siginfo.si_signo) << std::endl;
    }
}

void debugger::continue_execution() {
    if (m_breakpoint && m_breakpoint->get_address() == get_pc() - 1) {
        m_breakpoint->disable();
        dump_registers();
        decrement_pc();
        dump_registers();
//        single_step_instruction();
//        m_breakpoint->enable();
    }
    ptrace(PTRACE_CONT, m_pid, nullptr, nullptr);
    wait_for_signal();
}

void debugger::single_step_instruction() {
    ptrace(PTRACE_SINGLESTEP, m_pid, nullptr, nullptr);
    wait_for_signal();
}

void debugger::set_breakpoint_at_address(std::intptr_t addr) {
    std::cout << "Set breakpoint at address 0x" << std::hex << addr << std::endl;
    m_breakpoint = std::make_unique<breakpoint>(m_pid, addr);
    m_breakpoint->enable();
}

void debugger::set_breakpoint_at_source_line(const std::string& file, unsigned line) {
    for (const auto& cu : m_dwarf.compilation_units()) {
        if (is_suffix(file, at_name(cu.root()))) {
            const auto& lt = cu.get_line_table();

            for (const auto& entry : lt) {
                if (entry.is_stmt && entry.line == line) {
                    set_breakpoint_at_address(entry.address);
                    return;
                }
            }
        }
    }
}

void debugger::dump_registers() {
    struct user_regs_struct regs;
    ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
    std::cout << "r15" << ' ' << std::hex << regs.r15 << std::endl;
    std::cout << "r14" << ' ' << std::hex << regs.r14 << std::endl;
    std::cout << "r13" << ' ' << std::hex << regs.r13 << std::endl;
    std::cout << "r12" << ' ' << std::hex << regs.r12 << std::endl;
    std::cout << "bp" << ' ' << std::hex << regs.rbp << std::endl;
    std::cout << "bx" << ' ' << std::hex << regs.rbx << std::endl;
    std::cout << "r11" << ' ' << std::hex << regs.r11 << std::endl;
    std::cout << "r10" << ' ' << std::hex << regs.r10 << std::endl;
    std::cout << "r9" << ' ' << std::hex << regs.r9 << std::endl;
    std::cout << "r8" << ' ' << std::hex << regs.r8 << std::endl;
    std::cout << "ax" << ' ' << std::hex << regs.rax << std::endl;
    std::cout << "cx" << ' ' << std::hex << regs.rcx << std::endl;
    std::cout << "dx" << ' ' << std::hex << regs.rdx << std::endl;
    std::cout << "si" << ' ' << std::hex << regs.rsi << std::endl;
    std::cout << "di" << ' ' << std::hex << regs.rdi << std::endl;
    std::cout << "orig_ax" << ' ' << std::hex << regs.orig_rax << std::endl;
    std::cout << "ip" << ' ' << std::hex << regs.rip << std::endl;
    std::cout << "cs" << ' ' << std::hex << regs.cs << std::endl;
    std::cout << "flags" << ' ' << std::hex << regs.eflags << std::endl;
    std::cout << "sp" << ' ' << std::hex << regs.rsp << std::endl;
    std::cout << "ss" << ' ' << std::hex << regs.ss << std::endl;
    std::cout << "fs_base" << ' ' << std::hex << regs.fs_base << std::endl;
    std::cout << "gs_base" << ' ' << std::hex << regs.gs_base << std::endl;
    std::cout << "ds" << ' ' << std::hex << regs.ds << std::endl;
    std::cout << "es" << ' ' << std::hex << regs.es << std::endl;
    std::cout << "fs" << ' ' << std::hex << regs.fs << std::endl;
    std::cout << "gs" << ' ' << std::hex << regs.gs << std::endl;
}

void debugger::handle_command(const std::string& line) {
    if (is_prefix(line, "cont")) {
        continue_execution();
    }
    else if (is_prefix(line, "line")) {
        auto line_entry = get_current_line_entry();
        std::cout << line_entry.file->path << ':' << line_entry.line << std::endl;
    }
    else if (is_prefix(line, "registers")) {
        dump_registers();
    }
    else if (is_prefix(line, "pc")) {
        std::cout << std::hex << get_pc() << std::endl;
    }
    else if(is_prefix(line, "break")) {
        set_breakpoint_at_source_line("hello.cpp", 4);
    }
    else if(is_prefix(line, "step")) {
        single_step_instruction();
    }
    else {
        std::cerr << "Unknown command\n";
    }
}

void execute_debugger (const std::string& prog_name, pid_t pid) {
    int wait_status;
    wait(&wait_status);

    debugger dbg{prog_name, pid};
    dbg.run();
}

void execute_debugee (const std::string& prog_name) {
  if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
      std::cerr << "Error in ptrace\n";
      return;
  }
  execl(prog_name.c_str(), prog_name.c_str(), nullptr);
}

int main(int argc, char* argv[]) {
    auto prog = argv[1];

    auto pid = fork();
    if (pid == 0) {
        //child
        execute_debugee(prog);

    }
    else if (pid >= 1)  {
        //parent
        execute_debugger(prog, pid);
    }
    else {
        std::cerr << "Error forking";
    }
}
<commit_msg>Fix breakpoint saving and restoring<commit_after>#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <utility>
#include <cstdio>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/user.h>

#include "dwarf/dwarf++.hh"
#include "elf/elf++.hh"

#include "linenoise.h"

class breakpoint {
public:
    breakpoint(pid_t pid, std::intptr_t addr) : m_pid{pid}, m_addr{addr}, m_enabled{false}, m_saved_data{} {}
    void enable() {
        m_saved_data = ptrace(PTRACE_PEEKTEXT, m_pid, (void*)m_addr, 0);
        uint64_t int3 = 0xcc;
        uint64_t data_with_int3 = (m_saved_data & ~0xff | int3);
        ptrace(PTRACE_POKETEXT, m_pid, (void*)m_addr, data_with_int3);

        m_enabled = true;
    }

    void disable() {
        ptrace(PTRACE_POKETEXT, m_pid, (void*)m_addr, m_saved_data);
        m_enabled = false;
    }

    bool is_enabled() { return m_enabled; }

    std::intptr_t get_address() { return m_addr; }
private:
    pid_t m_pid;
    std::intptr_t m_addr;
    bool m_enabled;
    uint64_t m_saved_data;
};

class debugger {
public:
    debugger (std::string prog_name, pid_t pid)
        : m_prog_name{std::move(prog_name)}, m_pid{pid} {
            auto fd = open(m_prog_name.c_str(), O_RDONLY);

            m_elf = elf::elf{elf::create_mmap_loader(fd)};
            m_dwarf = dwarf::dwarf{dwarf::elf::create_loader(m_elf)};
        }

    void run();
    void dump_registers();
    void read_memory();
    void continue_execution();
    void single_step_instruction();
    siginfo_t get_signal_info();
    void set_breakpoint_at_address(std::intptr_t addr);
    void set_breakpoint_at_source_line(const std::string& file, unsigned line);
    void print_source(const std::string& file_name, unsigned line, unsigned n_lines_context=2);

private:
    void unchecked_single_step_instruction();
    void handle_command(const std::string& line);
    void handle_sigtrap(siginfo_t info);
    void wait_for_signal();
    uint64_t get_pc();
    void set_pc(uint64_t pc);
    void decrement_pc();
    dwarf::line_table::entry get_current_line_entry();

    std::string m_prog_name;
    pid_t m_pid;
    dwarf::dwarf m_dwarf;
    elf::elf m_elf;
    unsigned m_saved_data;
    std::unique_ptr<breakpoint> m_breakpoint;
};

uint64_t debugger::get_pc() {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  return regs.rip;
}

void debugger::set_pc(uint64_t pc) {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  regs.rip = pc;
  ptrace(PTRACE_SETREGS, m_pid, nullptr, &regs);
}

void debugger::decrement_pc() {
  struct user_regs_struct regs;
  ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
  regs.rip -= 1;
  ptrace(PTRACE_SETREGS, m_pid, nullptr, &regs);
}

dwarf::line_table::entry debugger::get_current_line_entry() {
    auto pc = get_pc();

    for (auto &cu : m_dwarf.compilation_units()) {
        if (die_pc_range(cu.root()).contains(pc)) {
            auto &lt = cu.get_line_table();
            auto it = lt.find_address(pc);
            if (it == lt.end()) {
                throw std::out_of_range{"Cannot find line entry"};
            }
            else {
                return *it;
            }
        }
    }

    throw std::out_of_range{"Cannot find line entry"};
}

void debugger::run() {
    char* line = nullptr;
    while((line = linenoise("minidbg> ")) != nullptr) {
        handle_command(line);
        linenoiseHistoryAdd(line);
        linenoiseFree(line);
    }
}

void debugger::print_source(const std::string& file_name, unsigned line, unsigned n_lines_context) {
    std::ifstream file {file_name};
    auto start_line = line < n_lines_context ? 0 : line - n_lines_context;
    auto end_line = line + n_lines_context + (line < n_lines_context ? n_lines_context - line : 0) + 1;

    char c{};
    auto current_line = 1u;
    while (current_line != start_line && file.get(c)) {
        if (c == '\n') {
            ++current_line;
        }
    }
    std::cout << (current_line==line ? "> " : "  ");
    while (current_line != end_line && file.get(c)) {
        std::cout << c;
        if (c == '\n') {
            ++current_line;
            std::cout << (current_line==line ? "> " : "  ");
        }
    }
    std::cout << std::endl;
}

bool is_prefix(const std::string& s, const std::string& of) {
    if (s.size() > of.size()) return false;
    return std::equal(s.begin(), s.end(), of.begin());
}

bool is_suffix(const std::string& s, const std::string& of) {
    if (s.size() > of.size()) return false;
    auto diff = of.size() - s.size();
    return std::equal(s.begin(), s.end(), of.begin() + diff);
}

siginfo_t debugger::get_signal_info() {
    siginfo_t info;
    ptrace(PTRACE_GETSIGINFO, m_pid, nullptr, &info);
    return info;
}

void debugger::handle_sigtrap(siginfo_t info) {
    switch (info.si_code) {
    case SI_KERNEL:
    case TRAP_BRKPT:
    {
        decrement_pc();
        std::cout << "Hit breakpoint at address 0x" << std::hex << get_pc() << std::endl;
        auto line_entry = get_current_line_entry();
        print_source(line_entry.file->path, line_entry.line);
        return;
    }
    case TRAP_TRACE:
        std::cout << "Finished single stepping" << std::endl;
        return;
    default:
        std::cout << "Unknown SIGTRAP code " << info.si_code << std::endl;
        return;
    }
}

void debugger::wait_for_signal() {
    int wait_status;
    auto options = 0;
    waitpid(m_pid, &wait_status, options);

    auto siginfo = get_signal_info();

    switch (siginfo.si_signo) {
    case SIGTRAP:
        handle_sigtrap(siginfo);
        break;
    case SIGSEGV:
        std::cout << "Yay, segfault. Reason: " << siginfo.si_code << std::endl;
        break;
    default:
        std::cout << "Got signal " << strsignal(siginfo.si_signo) << std::endl;
    }
}

void debugger::continue_execution() {
    if (m_breakpoint && m_breakpoint->get_address() == get_pc()) {
        m_breakpoint->disable();
        unchecked_single_step_instruction();
        m_breakpoint->enable();
    }
    ptrace(PTRACE_CONT, m_pid, nullptr, nullptr);
    wait_for_signal();
}

void debugger::unchecked_single_step_instruction() {
    ptrace(PTRACE_SINGLESTEP, m_pid, nullptr, nullptr);
    wait_for_signal();
}

void debugger::single_step_instruction() {
    if (m_breakpoint && m_breakpoint->get_address() == get_pc()) {
        m_breakpoint->disable();
        unchecked_single_step_instruction();
        m_breakpoint->enable();
        return;
    }

    unchecked_single_step_instruction();
}

void debugger::set_breakpoint_at_address(std::intptr_t addr) {
    std::cout << "Set breakpoint at address 0x" << std::hex << addr << std::endl;
    m_breakpoint = std::make_unique<breakpoint>(m_pid, addr);
    m_breakpoint->enable();
}

void debugger::set_breakpoint_at_source_line(const std::string& file, unsigned line) {
    for (const auto& cu : m_dwarf.compilation_units()) {
        if (is_suffix(file, at_name(cu.root()))) {
            const auto& lt = cu.get_line_table();

            for (const auto& entry : lt) {
                if (entry.is_stmt && entry.line == line) {
                    set_breakpoint_at_address(entry.address);
                    return;
                }
            }
        }
    }
}

void debugger::dump_registers() {
    struct user_regs_struct regs;
    ptrace(PTRACE_GETREGS, m_pid, nullptr, &regs);
    std::cout << "rax 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rax << std::endl;
    std::cout << "rbx 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rbx << std::endl;
    std::cout << "rcx 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rcx << std::endl;
    std::cout << "rdx 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rdx << std::endl;
    std::cout << "rdi 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rdi << std::endl;
    std::cout << "rsi 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rsi << std::endl;
    std::cout << "rbp 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rbp << std::endl;
    std::cout << "rsp 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rsp << std::endl;
    std::cout << "r8 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r8 << std::endl;
    std::cout << "r9 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r9 << std::endl;
    std::cout << "r10 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r10 << std::endl;
    std::cout << "r11 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r11 << std::endl;
    std::cout << "r12 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r12 << std::endl;
    std::cout << "r13 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r13 << std::endl;
    std::cout << "r14 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r14 << std::endl;
    std::cout << "r15 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.r15 << std::endl;
    std::cout << "rip 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.rip << std::endl;
    std::cout << "rflags 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.eflags << std::endl;
    std::cout << "cs 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.cs << std::endl;
    std::cout << "fs 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.fs << std::endl;
    std::cout << "gs 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.gs << std::endl;
    std::cout << "ss 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.ss << std::endl;
    std::cout << "ds 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.ds << std::endl;
    std::cout << "es 0x" << std::setfill('0') << std::setw(16) << std::hex << regs.es << std::endl;
}

void debugger::read_memory() {
    std::cout << std::hex << ptrace(PTRACE_PEEKDATA, m_pid, 0x40089a, nullptr) << std::endl;
    std::cout << std::hex << ptrace(PTRACE_PEEKDATA, m_pid, 0x40089e, nullptr) << std::endl;
    std::cout << std::hex << ptrace(PTRACE_PEEKDATA, m_pid, 0x400893, nullptr) << std::endl;
}

void debugger::handle_command(const std::string& line) {
    if (is_prefix(line, "cont")) {
        continue_execution();
    }
    else if (is_prefix(line, "line")) {
        auto line_entry = get_current_line_entry();
        std::cout << line_entry.file->path << ':' << line_entry.line << std::endl;
    }
    else if (is_prefix(line, "registers")) {
        dump_registers();
    }
    else if (is_prefix(line, "pc")) {
        std::cout << std::hex << get_pc() << std::endl;
    }
    else if(is_prefix(line, "break")) {
        set_breakpoint_at_source_line("hello.cpp", 4);
    }
    else if(is_prefix(line, "step")) {
        single_step_instruction();
    }
    else if(is_prefix(line, "memory")) {
        read_memory();
    }
    else {
        std::cerr << "Unknown command\n";
    }
}

void execute_debugger (const std::string& prog_name, pid_t pid) {
    int wait_status;
    wait(&wait_status);

    debugger dbg{prog_name, pid};
    dbg.run();
}

void execute_debugee (const std::string& prog_name) {
  if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
      std::cerr << "Error in ptrace\n";
      return;
  }
  execl(prog_name.c_str(), prog_name.c_str(), nullptr);
}

int main(int argc, char* argv[]) {
    auto prog = argv[1];

    auto pid = fork();
    if (pid == 0) {
        //child
        execute_debugee(prog);

    }
    else if (pid >= 1)  {
        //parent
        execute_debugger(prog, pid);
    }
    else {
        std::cerr << "Error forking";
    }
}
<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2012, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "image_helper.hh"

bool ishere(int hayx,int neex,int neey,int x,int y,
	    const PixelPacket *hay_pixel,
	    const PixelPacket *nee_pixel)
{
  // Check diagonal first. Seems to speed up things.

  for(int i=0;i<neey&&i<neex;i++) {
      if (*(hay_pixel+hayx*(y+i)+x+i) !=
	  *(nee_pixel+neex*i+i)) {
	return false;
      }
  }

  for(int _y=0;_y<neey;_y++) {
    for(int _x=0;_x<neex;_x++) {
      if (*(hay_pixel+hayx*(y+_y)+x+_x) !=
	  *(nee_pixel+neex*_y+_x)) {
	return false;
      }
    }
  }
  return true;
}

void img_search(std::vector<std::pair<int,int> >& res,Image& haystack,
		Image& needle)
{
  int hayx=haystack.columns(),hayy=haystack.rows();
  haystack.modifyImage();
  haystack.type(TrueColorType);
  const PixelPacket *hay_pixel=haystack.getConstPixels(0,0,hayx,hayy);

  int neex=needle.columns(),neey=needle.rows();
  needle.modifyImage();
  needle.type(TrueColorType);
  const PixelPacket *nee_pixel=needle.getConstPixels(0,0,neex,neey);

  for(int y=0;y<hayy-neey;y++) {
    for(int x=0;x<hayx-neex;x++) {
      if (ishere(hayx,neex,neey,x,y,hay_pixel,nee_pixel)) {
	res.push_back(std::pair<int,int>(x,y));
      }
    }
  }
}

/*
 * g++ -o image_helper -O3 -Wall `pkg-config --cflags --libs Magick++` image_helper.cc
 */

int main(int argc,char** argv)
{
  Image i1(argv[1]);
  Image i2(argv[2]);

  std::vector<std::pair<int,int> > r;

  img_search(r,i1,i2);

  for(unsigned i=0;i<r.size();i++) {
    printf("%i %i\n",r[i].first,r[i].second);
  }

  return 0;
}
<commit_msg>image_helper<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2012, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "image_helper.hh"

bool ishere(int hayx,int neex,int neey,int x,int y,
	    const PixelPacket *hay_pixel,
	    const PixelPacket *nee_pixel)
{
  // Check diagonal first. Seems to speed up things.

  for(int i=0;i<neey&&i<neex;i++) {
      if (*(hay_pixel+hayx*(y+i)+x+i) !=
	  *(nee_pixel+neex*i+i)) {
	return false;
      }
  }

  for(int _y=0;_y<neey;_y++) {
    for(int _x=0;_x<neex;_x++) {
      if (*(hay_pixel+hayx*(y+_y)+x+_x) !=
	  *(nee_pixel+neex*_y+_x)) {
	return false;
      }
    }
  }
  return true;
}

void img_search(std::vector<std::pair<int,int> >& res,Image& haystack,
		Image& needle)
{
  int hayx=haystack.columns(),hayy=haystack.rows();
  haystack.modifyImage();
  haystack.type(TrueColorType);
  const PixelPacket *hay_pixel=haystack.getConstPixels(0,0,hayx,hayy);

  int neex=needle.columns(),neey=needle.rows();
  needle.modifyImage();
  needle.type(TrueColorType);
  const PixelPacket *nee_pixel=needle.getConstPixels(0,0,neex,neey);

  for(int y=0;y<hayy-neey;y++) {
    for(int x=0;x<hayx-neex;x++) {
      if (ishere(hayx,neex,neey,x,y,hay_pixel,nee_pixel)) {
	res.push_back(std::pair<int,int>(x,y));
      }
    }
  }
}

/*
 * g++ -o image_helper -O3 -Wall `pkg-config --cflags --libs Magick++` image_helper.cc
 * image_helper x:'root' x:'root[300x400+879+122]'
 * If you are lucky, it will print you "879 122"
 */
#ifdef IMAGE_HELPER_MAIN

int main(int argc,char** argv)
{
  Image i1(argv[1]);
  Image i2(argv[2]);

  std::vector<std::pair<int,int> > r;

  img_search(r,i1,i2);

  for(unsigned i=0;i<r.size();i++) {
    printf("%i %i\n",r[i].first,r[i].second);
  }

  return 0;
}
#endif
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliMUONTracker.h"
#include "AliMUONTrackReconstructorK.h"
#include "AliMUONTrackReconstructor.h"
#include "AliMUONRecData.h"
#include "AliLog.h"

//_____________________________________________________________________________
AliMUONTracker::AliMUONTracker()
  : AliTracker(),
    fTriggerCircuit(0x0),
    fMUONData(0x0),
    fTrackReco(0x0)
{
  /// constructor

}
//_____________________________________________________________________________
AliMUONTracker::~AliMUONTracker()
{
  /// dtr
  delete fTrackReco;
}

//_____________________________________________________________________________
void AliMUONTracker::SetOption(Option_t* option)
{
  /// set reconstructor class

  if (!fMUONData)
    AliError("MUONData not defined");

  if (!fTriggerCircuit)
    AliError("TriggerCircuit not defined");

  if (strstr(option,"Original"))
    fTrackReco = new AliMUONTrackReconstructor(fMUONData);
  else if (strstr(option,"Combi"))
    fTrackReco = new AliMUONTrackReconstructorK(fMUONData,"Combi");
  else
    fTrackReco = new AliMUONTrackReconstructorK(fMUONData,"Kalman");

  fTrackReco->SetTriggerCircuit(fTriggerCircuit);

}

//_____________________________________________________________________________
Int_t AliMUONTracker::Clusters2Tracks(AliESD* /*esd*/)
{

  /// clusters2Tracks method
  /// in general tracking framework

  // open TClonesArray for reading
  fMUONData->SetTreeAddress("TC,RC");

  // open for writing
  // trigger branch
  fMUONData->MakeBranch("RL"); //trigger track
  fMUONData->SetTreeAddress("RL");
  fTrackReco->EventReconstructTrigger();
  fMUONData->Fill("RL");

  // tracking branch
  fMUONData->MakeBranch("RT"); //track
  fMUONData->SetTreeAddress("RT");
  fTrackReco->EventReconstruct();
  fMUONData->Fill("RT");

  fMUONData->ResetRecTracks();
  fMUONData->ResetRecTriggerTracks();

  return kTRUE;
}
<commit_msg>Adding class description (Christian)<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/// \class AliMUONTracker
/// Interface class for use of global tracking framework;
/// reconstruct tracks from recpoints
///
/// \author Christian Finck, SUBATECH Nantes

#include "AliMUONTracker.h"
#include "AliMUONTrackReconstructorK.h"
#include "AliMUONTrackReconstructor.h"
#include "AliMUONRecData.h"
#include "AliLog.h"

//_____________________________________________________________________________
AliMUONTracker::AliMUONTracker()
  : AliTracker(),
    fTriggerCircuit(0x0),
    fMUONData(0x0),
    fTrackReco(0x0)
{
  /// constructor

}
//_____________________________________________________________________________
AliMUONTracker::~AliMUONTracker()
{
  /// dtr
  delete fTrackReco;
}

//_____________________________________________________________________________
void AliMUONTracker::SetOption(Option_t* option)
{
  /// set reconstructor class

  if (!fMUONData)
    AliError("MUONData not defined");

  if (!fTriggerCircuit)
    AliError("TriggerCircuit not defined");

  if (strstr(option,"Original"))
    fTrackReco = new AliMUONTrackReconstructor(fMUONData);
  else if (strstr(option,"Combi"))
    fTrackReco = new AliMUONTrackReconstructorK(fMUONData,"Combi");
  else
    fTrackReco = new AliMUONTrackReconstructorK(fMUONData,"Kalman");

  fTrackReco->SetTriggerCircuit(fTriggerCircuit);

}

//_____________________________________________________________________________
Int_t AliMUONTracker::Clusters2Tracks(AliESD* /*esd*/)
{

  /// clusters2Tracks method
  /// in general tracking framework

  // open TClonesArray for reading
  fMUONData->SetTreeAddress("TC,RC");

  // open for writing
  // trigger branch
  fMUONData->MakeBranch("RL"); //trigger track
  fMUONData->SetTreeAddress("RL");
  fTrackReco->EventReconstructTrigger();
  fMUONData->Fill("RL");

  // tracking branch
  fMUONData->MakeBranch("RT"); //track
  fMUONData->SetTreeAddress("RT");
  fTrackReco->EventReconstruct();
  fMUONData->Fill("RT");

  fMUONData->ResetRecTracks();
  fMUONData->ResetRecTriggerTracks();

  return kTRUE;
}
<|endoftext|>