<commit_before>#include "neonrequest.h"

#include <glibmm/error.h>
#include <glibmm/quark.h>
#include <cstring>

namespace Davix {

/*
  authentification handle for neon
 */

std::string  translate_neon_status(int ne_status, ne_session* sess, int* errno_code){
    switch(ne_status){
        case NE_OK:
            *errno_code =0;
            return "Success, no Error";
        case NE_ERROR:
             *errno_code = ECOMM;
             return ne_get_error(sess);
        case NE_LOOKUP:
             *errno_code = ENOSYS;
             return "Domain Name resolution failed";
        case NE_AUTH:
            *errno_code = EPERM;
            return "Authentification Failed on server";
        case NE_PROXYAUTH:
            *errno_code = EPERM;
            return "Authentification Failed on proxy";
        case NE_CONNECT:
            *errno_code = ECOMM;
            return "Could not connect to server";
        case NE_TIMEOUT:
            *errno_code = ETIME;
            return "Connection timed out";
        case NE_FAILED:
            *errno_code = EINVAL;
            return "The precondition failed";
        case NE_RETRY:
            *errno_code = EAGAIN;
            return "Retry Request";
        default:
            *errno_code = ECOMM;
            return "Unknow Error from libneon";
    }
}

static int validate_all_certificate(void *userdata, int failures,
                                const ne_ssl_certificate *cert){
    return 0;
}

void NEONRequest::provide_clicert_fn(void *userdata, ne_session *sess,
                                         const ne_ssl_dname *const *dnames,
                                         int dncount){

    NEONRequest* req = (NEONRequest*) userdata;
    davix_log_debug("NEONRequest > clicert callback ");
    if( req->_call == NULL){
        davix_log_debug("NEONRequest : No credential specified, cancel authentification");
        return;
    }else{
        req->try_pkcs12_authentification(sess, dnames);

    }
}

int NEONRequest::provide_login_passwd_fn(void *userdata, const char *realm, int attempt,
                                char *username, char *password){
    NEONRequest * req = static_cast<NEONRequest*>(userdata);

     davix_log_debug("NEONRequest > Try to get auth/password authentification ");
     davix_auth_info_t auth_info;
    // memset(&auth_info,0,sizeof(davix_auth_info_t));
     auth_info.auth = DAVIX_LOGIN_PASSWORD;
     GError* tmp_err=NULL;

     if( req->_call == NULL){
         davix_log_debug("NEONRequest : No credential specified, cancel login/password authentification");
         return -1;
     }

     davix_log_debug("NEONRequest > call authentification callback ");
     int ret = req->_call(static_cast<Request*>(req), &auth_info, req->_user_auth_callback_data, &tmp_err); // try to get authentification
     davix_log_debug("NEONRequest > return from authentification callback ");
     if(ret != 0){
             throw Glib::Error(tmp_err);
     }

     if( req->_passwd.empty()
        || req->_login.empty() ){
        davix_log_debug("NEONRequest > Login/Password missings ....");
        return -1;
    }
    davix_log_debug("NEONRequest > setup authentification pwd/login....");
    g_strlcpy(username, req->_login.c_str(), NE_ABUFSIZ);
    g_strlcpy(password, req->_passwd.c_str(), NE_ABUFSIZ);
    req->_login.clear();
    req->_passwd.clear();
    return 0;

}

NEONRequest::NEONRequest(NEONSessionFactory* f, ne_session * sess, RequestType typ, const std::string & path,
                         void * user_auth_callback_data,
                         davix_auth_callback call) : _request_type("GET")
{
    _sess=sess;
    _login.clear();
    _passwd.clear();
    _path = path;
    _req=NULL;
    _call = call;
    _f = f;
    req_started= req_running =false;
    _user_auth_callback_data = user_auth_callback_data;
    ne_ssl_provide_clicert(sess, &NEONRequest::provide_clicert_fn, this);
    ne_set_server_auth(sess, &NEONRequest::provide_login_passwd_fn, this);
}

NEONRequest::~NEONRequest(){
    // safe destruction of the request
    if(req_running) ne_end_request(_req);

    free_request();
    //ne_forget_auth(_sess);

    _f->internal_release_session_handle(_sess);
}

void NEONRequest::create_req(){
    if(_req != NULL || req_started)
        throw Glib::Error(Glib::Quark("NEONRequest::create_req"), EINVAL, "Request already started, impossible to create");

    _req= ne_request_create(_sess, _request_type.c_str(), _path.c_str());

    for(size_t i=0; i< _headers_field.size(); ++i){
        ne_add_request_header(_req, _headers_field[i].first.c_str(),  _headers_field[i].second.c_str());
    }
    if(_content_body.size() > 0)
        ne_set_request_body_buffer(_req, _content_body.c_str(), _content_body.size());
}

void NEONRequest::negotiate_request(){

    const int n_limit = 10;
    int code, err_code, status, end_status = NE_RETRY;
    int n =0;
    if(req_started)
        throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, "request already started errors ....");

    req_started = req_running= true;

    while(end_status == NE_RETRY && n < n_limit){
        davix_log_debug(" ->   NEON start internal request ... ");

        if( (status = ne_begin_request(_req)) != NE_OK){
            std::string err_str = translate_neon_status(status, _sess, &err_code);
            throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("Request error : ").append(err_str));
        }

        code = get_request_code();
        switch(code){
            case 401: // authentification requested, do retry
                ne_discard_response(_req);
                end_status = ne_end_request(_req);
                if( end_status != NE_RETRY){
                    req_running = false;
                    std::string err_str = translate_neon_status(status, _sess, &err_code);
                    throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("End Request error : ").append(err_str));
                }
                davix_log_debug(" ->   NEON receive %d code, %d .... request again ... ", code, end_status);
                break;
            default:
                end_status = 0;
                break;

        }
        n++;
    }

    if(n >= n_limit)
       throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("too much retry, end of negociate_request"));
    davix_log_debug(" ->   NEON end internal request ... ");
}

void NEONRequest::set_requestcustom(const std::string &request_str){
    _request_type = request_str;
}

void NEONRequest::add_header_field(const std::string &field, const std::string &value){
    _headers_field.push_back(std::pair<std::string, std::string> (field, value));
}

int NEONRequest::execute_sync(){
    int err_code;
    ssize_t read_status=1;

    create_req();
    davix_log_debug(" -> NEON start synchronous  request... ");
    negotiate_request();

    while(read_status > 0){
        davix_log_debug(" -> NEON Read data flow... ");
        size_t s = _vec.size();
        _vec.resize(s + NEON_BUFFER_SIZE);
        read_status= ne_read_response_block(_req, &(_vec[s]), NEON_BUFFER_SIZE );
        if( read_status > 0 && read_status != NEON_BUFFER_SIZE){
           _vec.resize(s +  read_status);
        }

    }

    if(read_status < 0){
        std::string err_str = translate_neon_status(read_status, _sess,&err_code);
        throw Glib::Error(Glib::Quark("NEONRequest::Execute_sync"), err_code, std::string(" NEON reading error : ").append(err_str));
    }

   finish_block();

    davix_log_debug(" -> End synchronous request ... ");
    return 0;
}

void NEONRequest::execute_block(){
    create_req();
    negotiate_request();
}

ssize_t NEONRequest::read_block(char* buffer, size_t max_size){
    ssize_t read_status=1;

    if(_req == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EINVAL, "No request started");

    read_status= ne_read_response_block(_req, buffer, max_size );
    if(read_status <0){
       throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EIO, "Invalid Read in request");
    }
    return read_status;
}

void NEONRequest::finish_block(){
    int status;
    int err_code;

    if(_req == NULL || req_running == false)
            throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EINVAL, "No request started");

    req_running = false;
    if( (status = ne_end_request(_req)) != NE_OK){
        std::string err_str = translate_neon_status(status, _sess,&err_code);
        davix_log_debug("NEONRequest::finish_block -> error %d Error closing request -> %s ", err_code, err_str.c_str());
    }
}

void NEONRequest::clear_result(){
    _vec.clear();
}

void NEONRequest::disable_ssl_ca_check(){
     davix_log_debug("NEONRequest : disable ssl verification");
     ne_ssl_set_verify(_sess, validate_all_certificate, NULL);
}

int NEONRequest::get_request_code(){
    if(_req == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::get_request_code"), EINVAL, "No request started and try to get req code ..");
    return ne_get_status(_req)->code;
}

const std::vector<char> & NEONRequest::get_result(){
    return _vec;
}

void NEONRequest::try_set_pkcs12_cert(const char *filename_pkcs12, const char *passwd){
    int ret;
    ne_ssl_client_cert * cert = ne_ssl_clicert_read(filename_pkcs12);
    if(cert == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), EINVAL, "Unable to load credential " + std::string(filename_pkcs12) + ", failure");
    // try to decrypt
    int crypt_state = ne_ssl_clicert_encrypted(cert);
    if(crypt_state ==0 ){
        davix_log_debug("NEONRequest : Credential unencrypted, use it directly");
    }else{
        davix_log_debug("NEONRequest : Credential is encrypted, try to decrypt credential");

        if(passwd == NULL)
           throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), DAVIX_ERROR_NOPASSWD, " No password provided for encrypted credential ");
        if ((ret= ne_ssl_clicert_decrypt(cert, passwd)) != 0)
            throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), DAVIX_ERROR_BADPASSWD, " Unable to decrypt credential bad password ");
    }
    ne_ssl_set_clicert(_sess, cert);
    ne_ssl_clicert_free(cert);
    davix_log_debug("NEONRequest : associate credential to the current session");

}

void NEONRequest::try_set_login_passwd(const char *login, const char *passwd){
   this->_login = (char*) login;
   this->_passwd = (char*)  passwd;
}

int NEONRequest::try_pkcs12_authentification(ne_session *sess, const ne_ssl_dname *const *dnames){
    davix_log_debug("NEONRequest : Try to decrypt credential ");
    davix_auth_info_t auth_info;
    memset(&auth_info,0,sizeof(davix_auth_info_t));
    auth_info.auth = DAVIX_CLI_CERT_PKCS12;
    GError* tmp_err=NULL;
    davix_log_debug("NEONRequest > call authentification callback ");

    int ret = _call(static_cast<Request*>(this), &auth_info, _user_auth_callback_data, &tmp_err); // try to get authentification
    davix_log_debug("NEONRequest > return from authentification callback ");
    if(ret != 0)
            throw Glib::Error(tmp_err);
    return 0;
}

void NEONRequest::add_full_request_content(const std::string & body){
    davix_log_debug("NEONRequest : add request content of size %s ", body.c_str());
    _content_body = std::string(body);
}

void NEONRequest::free_request(){
    if(_req != NULL){
        ne_request_destroy(_req);
        _req=NULL;
    }
}

} // namespace Davix
<commit_msg>- try fix for memory corruption<commit_after>#include "neonrequest.h"

#include <glibmm/error.h>
#include <glibmm/quark.h>
#include <cstring>

namespace Davix {

/*
  authentification handle for neon
 */

std::string  translate_neon_status(int ne_status, ne_session* sess, int* errno_code){
    switch(ne_status){
        case NE_OK:
            *errno_code =0;
            return "Success, no Error";
        case NE_ERROR:
             *errno_code = ECOMM;
             return ne_get_error(sess);
        case NE_LOOKUP:
             *errno_code = ENOSYS;
             return "Domain Name resolution failed";
        case NE_AUTH:
            *errno_code = EPERM;
            return "Authentification Failed on server";
        case NE_PROXYAUTH:
            *errno_code = EPERM;
            return "Authentification Failed on proxy";
        case NE_CONNECT:
            *errno_code = ECOMM;
            return "Could not connect to server";
        case NE_TIMEOUT:
            *errno_code = ETIME;
            return "Connection timed out";
        case NE_FAILED:
            *errno_code = EINVAL;
            return "The precondition failed";
        case NE_RETRY:
            *errno_code = EAGAIN;
            return "Retry Request";
        default:
            *errno_code = ECOMM;
            return "Unknow Error from libneon";
    }
}

static int validate_all_certificate(void *userdata, int failures,
                                const ne_ssl_certificate *cert){
    return 0;
}

void NEONRequest::provide_clicert_fn(void *userdata, ne_session *sess,
                                         const ne_ssl_dname *const *dnames,
                                         int dncount){

    NEONRequest* req = (NEONRequest*) userdata;
    davix_log_debug("NEONRequest > clicert callback ");
    if( req->_call == NULL){
        davix_log_debug("NEONRequest : No credential specified, cancel authentification");
        return;
    }else{
        req->try_pkcs12_authentification(sess, dnames);

    }
}

int NEONRequest::provide_login_passwd_fn(void *userdata, const char *realm, int attempt,
                                char *username, char *password){
    NEONRequest * req = static_cast<NEONRequest*>(userdata);

     davix_log_debug("NEONRequest > Try to get auth/password authentification ");
     davix_auth_info_t auth_info;
    // memset(&auth_info,0,sizeof(davix_auth_info_t));
     auth_info.auth = DAVIX_LOGIN_PASSWORD;
     GError* tmp_err=NULL;

     if( req->_call == NULL){
         davix_log_debug("NEONRequest : No credential specified, cancel login/password authentification");
         return -1;
     }

     davix_log_debug("NEONRequest > call authentification callback ");
     int ret = req->_call(static_cast<Request*>(req), &auth_info, req->_user_auth_callback_data, &tmp_err); // try to get authentification
     davix_log_debug("NEONRequest > return from authentification callback ");
     if(ret != 0){
             throw Glib::Error(tmp_err);
     }

     if( req->_passwd.empty()
        || req->_login.empty() ){
        davix_log_debug("NEONRequest > Login/Password missings ....");
        return -1;
    }
    davix_log_debug("NEONRequest > setup authentification pwd/login....");
    g_strlcpy(username, req->_login.c_str(), NE_ABUFSIZ);
    g_strlcpy(password, req->_passwd.c_str(), NE_ABUFSIZ);
    req->_login.clear();
    req->_passwd.clear();
    return 0;

}

NEONRequest::NEONRequest(NEONSessionFactory* f, ne_session * sess, RequestType typ, const std::string & path,
                         void * user_auth_callback_data,
                         davix_auth_callback call) : _request_type("GET")
{
    _sess=sess;
    _login.clear();
    _passwd.clear();
    _path = path;
    _req=NULL;
    _call = call;
    _f = f;
    req_started= req_running =false;
    _user_auth_callback_data = user_auth_callback_data;
    ne_ssl_provide_clicert(sess, &NEONRequest::provide_clicert_fn, this);
    ne_set_server_auth(sess, &NEONRequest::provide_login_passwd_fn, this);
}

NEONRequest::~NEONRequest(){
    // safe destruction of the request
    if(req_running) finish_block();

    free_request();
    //ne_forget_auth(_sess);

    _f->internal_release_session_handle(_sess);
}

void NEONRequest::create_req(){
    if(_req != NULL || req_started)
        throw Glib::Error(Glib::Quark("NEONRequest::create_req"), EINVAL, "Request already started, impossible to create");

    _req= ne_request_create(_sess, _request_type.c_str(), _path.c_str());

    for(size_t i=0; i< _headers_field.size(); ++i){
        ne_add_request_header(_req, _headers_field[i].first.c_str(),  _headers_field[i].second.c_str());
    }
    if(_content_body.size() > 0)
        ne_set_request_body_buffer(_req, _content_body.c_str(), _content_body.size());
}

void NEONRequest::negotiate_request(){

    const int n_limit = 10;
    int code, err_code, status, end_status = NE_RETRY;
    int n =0;
    if(req_started)
        throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, "request already started errors ....");

    req_started = req_running= true;

    while(end_status == NE_RETRY && n < n_limit){
        davix_log_debug(" ->   NEON start internal request ... ");

        if( (status = ne_begin_request(_req)) != NE_OK){
            std::string err_str = translate_neon_status(status, _sess, &err_code);
            throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("Request error : ").append(err_str));
        }

        code = get_request_code();
        switch(code){
            case 401: // authentification requested, do retry
                ne_discard_response(_req);
                end_status = ne_end_request(_req);
                if( end_status != NE_RETRY){
                    req_running = false;
                    std::string err_str = translate_neon_status(status, _sess, &err_code);
                    throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("End Request error : ").append(err_str));
                }
                davix_log_debug(" ->   NEON receive %d code, %d .... request again ... ", code, end_status);
                break;
            default:
                end_status = 0;
                break;

        }
        n++;
    }

    if(n >= n_limit)
       throw Glib::Error(Glib::Quark("NEONRequest::negotiate_request"), err_code, std::string("too much retry, end of negociate_request"));
    davix_log_debug(" ->   NEON end internal request ... ");
}

void NEONRequest::set_requestcustom(const std::string &request_str){
    _request_type = request_str;
}

void NEONRequest::add_header_field(const std::string &field, const std::string &value){
    _headers_field.push_back(std::pair<std::string, std::string> (field, value));
}

int NEONRequest::execute_sync(){
    int err_code;
    ssize_t read_status=1;

    create_req();
    davix_log_debug(" -> NEON start synchronous  request... ");
    negotiate_request();

    while(read_status > 0){
        davix_log_debug(" -> NEON Read data flow... ");
        size_t s = _vec.size();
        _vec.resize(s + NEON_BUFFER_SIZE);
        read_status= ne_read_response_block(_req, &(_vec[s]), NEON_BUFFER_SIZE );
        if( read_status > 0 && read_status != NEON_BUFFER_SIZE){
           _vec.resize(s +  read_status);
        }

    }

    if(read_status < 0){
        std::string err_str = translate_neon_status(read_status, _sess,&err_code);
        throw Glib::Error(Glib::Quark("NEONRequest::Execute_sync"), err_code, std::string(" NEON reading error : ").append(err_str));
    }

   finish_block();

    davix_log_debug(" -> End synchronous request ... ");
    return 0;
}

void NEONRequest::execute_block(){
    create_req();
    negotiate_request();
}

ssize_t NEONRequest::read_block(char* buffer, size_t max_size){
    ssize_t read_status=1;

    if(_req == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EINVAL, "No request started");

    read_status= ne_read_response_block(_req, buffer, max_size );
    if(read_status <0){
       throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EIO, "Invalid Read in request");
    }
    return read_status;
}

void NEONRequest::finish_block(){
    int status;
    int err_code;

    if(_req == NULL || req_running == false)
            throw Glib::Error(Glib::Quark("NEONRequest::read_block"), EINVAL, "No request started");

    req_running = false;
    if( (status = ne_end_request(_req)) != NE_OK){
        std::string err_str = translate_neon_status(status, _sess,&err_code);
        davix_log_debug("NEONRequest::finish_block -> error %d Error closing request -> %s ", err_code, err_str.c_str());
    }
}

void NEONRequest::clear_result(){
    _vec.clear();
}

void NEONRequest::disable_ssl_ca_check(){
     davix_log_debug("NEONRequest : disable ssl verification");
     ne_ssl_set_verify(_sess, validate_all_certificate, NULL);
}

int NEONRequest::get_request_code(){
    if(_req == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::get_request_code"), EINVAL, "No request started and try to get req code ..");
    return ne_get_status(_req)->code;
}

const std::vector<char> & NEONRequest::get_result(){
    return _vec;
}

void NEONRequest::try_set_pkcs12_cert(const char *filename_pkcs12, const char *passwd){
    int ret;
    ne_ssl_client_cert * cert = ne_ssl_clicert_read(filename_pkcs12);
    if(cert == NULL)
        throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), EINVAL, "Unable to load credential " + std::string(filename_pkcs12) + ", failure");
    // try to decrypt
    int crypt_state = ne_ssl_clicert_encrypted(cert);
    if(crypt_state ==0 ){
        davix_log_debug("NEONRequest : Credential unencrypted, use it directly");
    }else{
        davix_log_debug("NEONRequest : Credential is encrypted, try to decrypt credential");

        if(passwd == NULL)
           throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), DAVIX_ERROR_NOPASSWD, " No password provided for encrypted credential ");
        if ((ret= ne_ssl_clicert_decrypt(cert, passwd)) != 0)
            throw Glib::Error(Glib::Quark("NEONRequest::try_set_pkcs12_cert"), DAVIX_ERROR_BADPASSWD, " Unable to decrypt credential bad password ");
    }
    ne_ssl_set_clicert(_sess, cert);
    ne_ssl_clicert_free(cert);
    davix_log_debug("NEONRequest : associate credential to the current session");

}

void NEONRequest::try_set_login_passwd(const char *login, const char *passwd){
   this->_login = (char*) login;
   this->_passwd = (char*)  passwd;
}

int NEONRequest::try_pkcs12_authentification(ne_session *sess, const ne_ssl_dname *const *dnames){
    davix_log_debug("NEONRequest : Try to decrypt credential ");
    davix_auth_info_t auth_info;
    memset(&auth_info,0,sizeof(davix_auth_info_t));
    auth_info.auth = DAVIX_CLI_CERT_PKCS12;
    GError* tmp_err=NULL;
    davix_log_debug("NEONRequest > call authentification callback ");

    int ret = _call(static_cast<Request*>(this), &auth_info, _user_auth_callback_data, &tmp_err); // try to get authentification
    davix_log_debug("NEONRequest > return from authentification callback ");
    if(ret != 0)
            throw Glib::Error(tmp_err);
    return 0;
}

void NEONRequest::add_full_request_content(const std::string & body){
    davix_log_debug("NEONRequest : add request content of size %s ", body.c_str());
    _content_body = std::string(body);
}

void NEONRequest::free_request(){
    if(_req != NULL){
        ne_request_destroy(_req);
        _req=NULL;
    }
}

} // namespace Davix
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 *  $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/framework/XMLRecognizer.hpp>
#include <string.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local data
//
//  gEncodingNameMap
//      This array maps the Encodings enum values to their canonical names.
//      Be sure to keep this in sync with that enum!
// ---------------------------------------------------------------------------
static const XMLCh* gEncodingNameMap[XMLRecognizer::Encodings_Count] =
{
    XMLUni::fgEBCDICEncodingString
    , XMLUni::fgUCS4BEncodingString
    , XMLUni::fgUCS4LEncodingString
    , XMLUni::fgUSASCIIEncodingString
    , XMLUni::fgUTF8EncodingString
    , XMLUni::fgUTF16BEncodingString
    , XMLUni::fgUTF16LEncodingString
};

// ---------------------------------------------------------------------------
//  XMLRecognizer: Public, const static data
//
//  gXXXPre
//  gXXXPreLen
//      The byte sequence prefixes for all of the encodings that we can
//      auto sense. Also included is the length of each sequence.
// ---------------------------------------------------------------------------
const char           XMLRecognizer::fgASCIIPre[]  = { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20 };
const unsigned int   XMLRecognizer::fgASCIIPreLen = 6;
const XMLByte        XMLRecognizer::fgEBCDICPre[] = { 0x4C, 0x6F, 0xA7, 0x94, 0x93, 0x40 };
const unsigned int   XMLRecognizer::fgEBCDICPreLen = 6;
const XMLByte        XMLRecognizer::fgUTF16BPre[] = { 0x00, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00, 0x20 };
const XMLByte        XMLRecognizer::fgUTF16LPre[] = { 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00, 0x20, 0x00 };
const unsigned int   XMLRecognizer::fgUTF16PreLen = 12;
const XMLByte        XMLRecognizer::fgUCS4BPre[]  =
{
        0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3F
    ,   0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6D
    ,   0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x20
};
const XMLByte        XMLRecognizer::fgUCS4LPre[]  =
{
        0x3C, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00
    ,   0x78, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00
    ,   0x6C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
};
const unsigned int   XMLRecognizer::fgUCS4PreLen = 24;

const char           XMLRecognizer::fgUTF8BOM[] = {(char)0xEF, (char)0xBB, (char)0xBF};
const unsigned int   XMLRecognizer::fgUTF8BOMLen = 3;

// ---------------------------------------------------------------------------
//  XMLRecognizer: Encoding recognition methods
// ---------------------------------------------------------------------------
XMLRecognizer::Encodings
XMLRecognizer::basicEncodingProbe(  const   XMLByte* const  rawBuffer
                                    , const unsigned int    rawByteCount)
{
    //
    //  As an optimization to check the 90% case, check first for the ASCII
    //  sequence '<?xml', which means its either US-ASCII, UTF-8, or some
    //  other encoding that we don't do manually but which happens to share
    //  the US-ASCII code points for these characters. So just return UTF-8
    //  to get us through the first line.
    //
    if (rawByteCount >= fgASCIIPreLen)
    {
        if (!memcmp(rawBuffer, fgASCIIPre, fgASCIIPreLen))
            return UTF_8;
    }

    //
    //  If the count of raw bytes is less than 2, it cannot be anything
    //  we understand, so return UTF-8 as a fallback.
    //
    if (rawByteCount < 2)
        return UTF_8;

    //
    //  We know its at least two bytes, so lets check for a UTF-16 BOM. That
    //  is quick to check and enough to identify two major encodings.
    //
    if ((rawBuffer[0] == 0xFE) && (rawBuffer[1] == 0xFF))
        return UTF_16B;
    else if ((rawBuffer[0] == 0xFF) && (rawBuffer[1] == 0xFE))
        return UTF_16L;

    //
    //  Oh well, not one of those. So now lets see if we have at least 4
    //  bytes. If not, then we are out of ideas and can return UTF-8 as the
    //  fallback.
    //
    if (rawByteCount < 4)
        return UTF_8;

    //
    //  We have at least 4 bytes. So lets check the 4 byte sequences that
    //  indicate other UTF-16 and UCS encodings.
    //
    if ((rawBuffer[0] == 0x00) || (rawBuffer[0] == 0x3C))
    {
        if (rawByteCount >= fgUCS4PreLen && !memcmp(rawBuffer, fgUCS4BPre, fgUCS4PreLen))
            return UCS_4B;
        else if (rawByteCount >= fgUCS4PreLen && !memcmp(rawBuffer, fgUCS4LPre, fgUCS4PreLen))
            return UCS_4L;
        else if (rawByteCount >= fgUTF16PreLen && !memcmp(rawBuffer, fgUTF16BPre, fgUTF16PreLen))
            return UTF_16B;
        else if (rawByteCount >= fgUTF16PreLen && !memcmp(rawBuffer, fgUTF16LPre, fgUTF16PreLen))
            return UTF_16L;
    }

    //
    //  See if we have enough bytes to possibly match the EBCDIC prefix.
    //  If so, try it.
    //
    if (rawByteCount > fgEBCDICPreLen)
    {
        if (!memcmp(rawBuffer, fgEBCDICPre, fgEBCDICPreLen))
            return EBCDIC;
    }

    //
    //  Does not seem to be anything we know, so go with UTF-8 to get at
    //  least through the first line and see what it really is.
    //
    return UTF_8;
}

XMLRecognizer::Encodings
XMLRecognizer::encodingForName(const XMLCh* const encName)
{
    //
    //  Compare the passed string, case insensitively, to the variations
    //  that we recognize.
    //
    //  !!NOTE: Note that we don't handle EBCDIC here because we don't handle
    //  that one ourselves. It is allowed to fall into 'other'.
    //
   if (encName == XMLUni::fgXMLChEncodingString ||
        !XMLString::compareIString(encName, XMLUni::fgXMLChEncodingString))
   {
        return XMLRecognizer::OtherEncoding;
   }
   else if (!XMLString::compareIString(encName, XMLUni::fgUTF8EncodingString)
    ||  !XMLString::compareIString(encName, XMLUni::fgUTF8EncodingString2))
    {
        return XMLRecognizer::UTF_8;
    }
     else if (!XMLString::compareIString(encName, XMLUni::fgUSASCIIEncodingString)
          ||  !XMLString::compareIString(encName, XMLUni::fgUSASCIIEncodingString2)
          ||  !XMLString::compareIString(encName, XMLUni::fgUSASCIIEncodingString3)
          ||  !XMLString::compareIString(encName, XMLUni::fgUSASCIIEncodingString4))
    {
        return XMLRecognizer::US_ASCII;
    }
     else if (!XMLString::compareIString(encName, XMLUni::fgUTF16LEncodingString)
          ||  !XMLString::compareIString(encName, XMLUni::fgUTF16LEncodingString2))
    {
        return XMLRecognizer::UTF_16L;
    }
     else if (!XMLString::compareIString(encName, XMLUni::fgUTF16BEncodingString)
          ||  !XMLString::compareIString(encName, XMLUni::fgUTF16BEncodingString2))
    {
        return XMLRecognizer::UTF_16B;
    }
     else if (!XMLString::compareIString(encName, XMLUni::fgUCS4LEncodingString)
          ||  !XMLString::compareIString(encName, XMLUni::fgUCS4LEncodingString2))
    {
        return XMLRecognizer::UCS_4L;
    }
     else if (!XMLString::compareIString(encName, XMLUni::fgUCS4BEncodingString)
          ||  !XMLString::compareIString(encName, XMLUni::fgUCS4BEncodingString2))
    {
        return XMLRecognizer::UCS_4B;
    }

    // Return 'other' since we don't recognizer it
    return XMLRecognizer::OtherEncoding;
}

const XMLCh*
XMLRecognizer::nameForEncoding(const XMLRecognizer::Encodings theEncoding)
{
    if (theEncoding > Encodings_Count)
        ThrowXML(RuntimeException, XMLExcepts::XMLRec_UnknownEncoding);

    return gEncodingNameMap[theEncoding];
}

XERCES_CPP_NAMESPACE_END
<commit_msg>Performance: 1. XERCES_XMLCH should not be classified as XMLRecognizer::OtherEncodings 2. Pre uppercase the encodingString before calling encodingForName to avoid calling compareIString<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 *  $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/RuntimeException.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/framework/XMLRecognizer.hpp>
#include <string.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local data
//
//  gEncodingNameMap
//      This array maps the Encodings enum values to their canonical names.
//      Be sure to keep this in sync with that enum!
// ---------------------------------------------------------------------------
static const XMLCh* gEncodingNameMap[XMLRecognizer::Encodings_Count] =
{
    XMLUni::fgEBCDICEncodingString
    , XMLUni::fgUCS4BEncodingString
    , XMLUni::fgUCS4LEncodingString
    , XMLUni::fgUSASCIIEncodingString
    , XMLUni::fgUTF8EncodingString
    , XMLUni::fgUTF16BEncodingString
    , XMLUni::fgUTF16LEncodingString
    , XMLUni::fgXMLChEncodingString
};

// ---------------------------------------------------------------------------
//  XMLRecognizer: Public, const static data
//
//  gXXXPre
//  gXXXPreLen
//      The byte sequence prefixes for all of the encodings that we can
//      auto sense. Also included is the length of each sequence.
// ---------------------------------------------------------------------------
const char           XMLRecognizer::fgASCIIPre[]  = { 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20 };
const unsigned int   XMLRecognizer::fgASCIIPreLen = 6;
const XMLByte        XMLRecognizer::fgEBCDICPre[] = { 0x4C, 0x6F, 0xA7, 0x94, 0x93, 0x40 };
const unsigned int   XMLRecognizer::fgEBCDICPreLen = 6;
const XMLByte        XMLRecognizer::fgUTF16BPre[] = { 0x00, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00, 0x20 };
const XMLByte        XMLRecognizer::fgUTF16LPre[] = { 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00, 0x20, 0x00 };
const unsigned int   XMLRecognizer::fgUTF16PreLen = 12;
const XMLByte        XMLRecognizer::fgUCS4BPre[]  =
{
        0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3F
    ,   0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6D
    ,   0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x20
};
const XMLByte        XMLRecognizer::fgUCS4LPre[]  =
{
        0x3C, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00
    ,   0x78, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00
    ,   0x6C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
};
const unsigned int   XMLRecognizer::fgUCS4PreLen = 24;

const char           XMLRecognizer::fgUTF8BOM[] = {(char)0xEF, (char)0xBB, (char)0xBF};
const unsigned int   XMLRecognizer::fgUTF8BOMLen = 3;

// ---------------------------------------------------------------------------
//  XMLRecognizer: Encoding recognition methods
// ---------------------------------------------------------------------------
XMLRecognizer::Encodings
XMLRecognizer::basicEncodingProbe(  const   XMLByte* const  rawBuffer
                                    , const unsigned int    rawByteCount)
{
    //
    //  As an optimization to check the 90% case, check first for the ASCII
    //  sequence '<?xml', which means its either US-ASCII, UTF-8, or some
    //  other encoding that we don't do manually but which happens to share
    //  the US-ASCII code points for these characters. So just return UTF-8
    //  to get us through the first line.
    //
    if (rawByteCount >= fgASCIIPreLen)
    {
        if (!memcmp(rawBuffer, fgASCIIPre, fgASCIIPreLen))
            return UTF_8;
    }

    //
    //  If the count of raw bytes is less than 2, it cannot be anything
    //  we understand, so return UTF-8 as a fallback.
    //
    if (rawByteCount < 2)
        return UTF_8;

    //
    //  We know its at least two bytes, so lets check for a UTF-16 BOM. That
    //  is quick to check and enough to identify two major encodings.
    //
    if ((rawBuffer[0] == 0xFE) && (rawBuffer[1] == 0xFF))
        return UTF_16B;
    else if ((rawBuffer[0] == 0xFF) && (rawBuffer[1] == 0xFE))
        return UTF_16L;

    //
    //  Oh well, not one of those. So now lets see if we have at least 4
    //  bytes. If not, then we are out of ideas and can return UTF-8 as the
    //  fallback.
    //
    if (rawByteCount < 4)
        return UTF_8;

    //
    //  We have at least 4 bytes. So lets check the 4 byte sequences that
    //  indicate other UTF-16 and UCS encodings.
    //
    if ((rawBuffer[0] == 0x00) || (rawBuffer[0] == 0x3C))
    {
        if (rawByteCount >= fgUCS4PreLen && !memcmp(rawBuffer, fgUCS4BPre, fgUCS4PreLen))
            return UCS_4B;
        else if (rawByteCount >= fgUCS4PreLen && !memcmp(rawBuffer, fgUCS4LPre, fgUCS4PreLen))
            return UCS_4L;
        else if (rawByteCount >= fgUTF16PreLen && !memcmp(rawBuffer, fgUTF16BPre, fgUTF16PreLen))
            return UTF_16B;
        else if (rawByteCount >= fgUTF16PreLen && !memcmp(rawBuffer, fgUTF16LPre, fgUTF16PreLen))
            return UTF_16L;
    }

    //
    //  See if we have enough bytes to possibly match the EBCDIC prefix.
    //  If so, try it.
    //
    if (rawByteCount > fgEBCDICPreLen)
    {
        if (!memcmp(rawBuffer, fgEBCDICPre, fgEBCDICPreLen))
            return EBCDIC;
    }

    //
    //  Does not seem to be anything we know, so go with UTF-8 to get at
    //  least through the first line and see what it really is.
    //
    return UTF_8;
}

XMLRecognizer::Encodings
XMLRecognizer::encodingForName(const XMLCh* const encName)
{
    //
    //  Compare the passed string, assume input string is already uppercased,
    //  to the variations that we recognize.
    //
    //  !!NOTE: Note that we don't handle EBCDIC here because we don't handle
    //  that one ourselves. It is allowed to fall into 'other'.
    //
   if (encName == XMLUni::fgXMLChEncodingString ||
        !XMLString::compareString(encName, XMLUni::fgXMLChEncodingString))
   {
        return XMLRecognizer::XERCES_XMLCH;
   }
   else if (!XMLString::compareString(encName, XMLUni::fgUTF8EncodingString)
    ||  !XMLString::compareString(encName, XMLUni::fgUTF8EncodingString2))
    {
        return XMLRecognizer::UTF_8;
    }
     else if (!XMLString::compareString(encName, XMLUni::fgUSASCIIEncodingString)
          ||  !XMLString::compareString(encName, XMLUni::fgUSASCIIEncodingString2)
          ||  !XMLString::compareString(encName, XMLUni::fgUSASCIIEncodingString3)
          ||  !XMLString::compareString(encName, XMLUni::fgUSASCIIEncodingString4))
    {
        return XMLRecognizer::US_ASCII;
    }
     else if (!XMLString::compareString(encName, XMLUni::fgUTF16LEncodingString)
          ||  !XMLString::compareString(encName, XMLUni::fgUTF16LEncodingString2))
    {
        return XMLRecognizer::UTF_16L;
    }
     else if (!XMLString::compareString(encName, XMLUni::fgUTF16BEncodingString)
          ||  !XMLString::compareString(encName, XMLUni::fgUTF16BEncodingString2))
    {
        return XMLRecognizer::UTF_16B;
    }
     else if (!XMLString::compareString(encName, XMLUni::fgUCS4LEncodingString)
          ||  !XMLString::compareString(encName, XMLUni::fgUCS4LEncodingString2))
    {
        return XMLRecognizer::UCS_4L;
    }
     else if (!XMLString::compareString(encName, XMLUni::fgUCS4BEncodingString)
          ||  !XMLString::compareString(encName, XMLUni::fgUCS4BEncodingString2))
    {
        return XMLRecognizer::UCS_4B;
    }

    // Return 'other' since we don't recognizer it
    return XMLRecognizer::OtherEncoding;
}

const XMLCh*
XMLRecognizer::nameForEncoding(const XMLRecognizer::Encodings theEncoding)
{
    if (theEncoding > Encodings_Count)
        ThrowXML(RuntimeException, XMLExcepts::XMLRec_UnknownEncoding);

    return gEncodingNameMap[theEncoding];
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>#include <string>

#include "caffe/layer.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/vision_layers.hpp"

namespace caffe {

// GetLayer() defines the overall layer factory. The Get*Layer() functions
// define factories for layers with multiple computational engines.

// Get convolution layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetConvolutionLayer(
    const LayerParameter& param) {
  ConvolutionParameter_Engine engine = param.convolution_param().engine();
  if (engine == ConvolutionParameter_Engine_DEFAULT) {
    engine = ConvolutionParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ConvolutionParameter_Engine_CUDNN;
#endif
  }
  if (engine == ConvolutionParameter_Engine_CAFFE) {
    return new ConvolutionLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == ConvolutionParameter_Engine_CUDNN) {
    return new CuDNNConvolutionLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get pooling layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetPoolingLayer(const LayerParameter& param) {
  PoolingParameter_Engine engine = param.pooling_param().engine();
  if (engine == PoolingParameter_Engine_DEFAULT) {
    engine = PoolingParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = PoolingParameter_Engine_CUDNN;
#endif
  }
  if (engine == PoolingParameter_Engine_CAFFE) {
    return new PoolingLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == PoolingParameter_Engine_CUDNN) {
    if (p_param.pad_h() || p_param.pad_w() || param.top_size() > 1) {
      LOG(INFO) << "CUDNN does not support padding or multiple tops. "
                << "Using Caffe's own pooling layer.";
      return new PoolingLayer<DType>(param);
    }
    return new CuDNNPoolingLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get relu layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetReLULayer(const LayerParameter& param) {
  ReLUParameter_Engine engine = param.relu_param().engine();
  if (engine == ReLUParameter_Engine_DEFAULT) {
    engine = ReLUParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ReLUParameter_Engine_CUDNN;
#endif
  }
  if (engine == ReLUParameter_Engine_CAFFE) {
    return new ReLULayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == ReLUParameter_Engine_CUDNN) {
    return new CuDNNReLULayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get sigmoid layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetSigmoidLayer(const LayerParameter& param) {
  SigmoidParameter_Engine engine = param.sigmoid_param().engine();
  if (engine == SigmoidParameter_Engine_DEFAULT) {
    engine = SigmoidParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SigmoidParameter_Engine_CUDNN;
#endif
  }
  if (engine == SigmoidParameter_Engine_CAFFE) {
    return new SigmoidLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == SigmoidParameter_Engine_CUDNN) {
    return new CuDNNSigmoidLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get tanh layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetTanHLayer(const LayerParameter& param) {
  TanHParameter_Engine engine = param.tanh_param().engine();
  if (engine == TanHParameter_Engine_DEFAULT) {
    engine = TanHParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = TanHParameter_Engine_CUDNN;
#endif
  }
  if (engine == TanHParameter_Engine_CAFFE) {
    return new TanHLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == TanHParameter_Engine_CUDNN) {
    return new CuDNNTanHLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get softmax layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetSoftmaxLayer(const LayerParameter& param) {
  SoftmaxParameter_Engine engine = param.softmax_param().engine();
  if (engine == SoftmaxParameter_Engine_DEFAULT) {
    engine = SoftmaxParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SoftmaxParameter_Engine_CUDNN;
#endif
  }
  if (engine == SoftmaxParameter_Engine_CAFFE) {
    return new SoftmaxLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == SoftmaxParameter_Engine_CUDNN) {
    return new CuDNNSoftmaxLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Layers that have a specific creator function.
REGISTER_LAYER_CREATOR(CONVOLUTION, GetConvolutionLayer);
REGISTER_LAYER_CREATOR(POOLING, GetPoolingLayer);
REGISTER_LAYER_CREATOR(RELU, GetReLULayer);
REGISTER_LAYER_CREATOR(SIGMOID, GetSigmoidLayer);
REGISTER_LAYER_CREATOR(SOFTMAX, GetSoftmaxLayer);
REGISTER_LAYER_CREATOR(TANH, GetTanHLayer);

// Layers that use their constructor as their default creator.
REGISTER_LAYER_CLASS(ACCURACY, AccuracyLayer);
REGISTER_LAYER_CLASS(ABSVAL, AbsValLayer);
REGISTER_LAYER_CLASS(ARGMAX, ArgMaxLayer);
REGISTER_LAYER_CLASS(BNLL, BNLLLayer);
REGISTER_LAYER_CLASS(CONCAT, ConcatLayer);
REGISTER_LAYER_CLASS(CONTRASTIVE_LOSS, ContrastiveLossLayer);
REGISTER_LAYER_CLASS(DATA, DataLayer);
REGISTER_LAYER_CLASS(DROPOUT, DropoutLayer);
REGISTER_LAYER_CLASS(DUMMY_DATA, DummyDataLayer);
REGISTER_LAYER_CLASS(EUCLIDEAN_LOSS, EuclideanLossLayer);
REGISTER_LAYER_CLASS(ELTWISE, EltwiseLayer);
REGISTER_LAYER_CLASS(FLATTEN, FlattenLayer);
REGISTER_LAYER_CLASS(HDF5_DATA, HDF5DataLayer);
REGISTER_LAYER_CLASS(HDF5_OUTPUT, HDF5OutputLayer);
REGISTER_LAYER_CLASS(HINGE_LOSS, HingeLossLayer);
REGISTER_LAYER_CLASS(IMAGE_DATA, ImageDataLayer);
REGISTER_LAYER_CLASS(IM2COL, Im2colLayer);
REGISTER_LAYER_CLASS(INFOGAIN_LOSS, InfogainLossLayer);
REGISTER_LAYER_CLASS(INNER_PRODUCT, InnerProductLayer);
REGISTER_LAYER_CLASS(LRN, LRNLayer);
REGISTER_LAYER_CLASS(MEMORY_DATA, MemoryDataLayer);
REGISTER_LAYER_CLASS(MVN, MVNLayer);
REGISTER_LAYER_CLASS(MULTINOMIAL_LOGISTIC_LOSS, MultinomialLogisticLossLayer);
REGISTER_LAYER_CLASS(POWER, PowerLayer);
REGISTER_LAYER_CLASS(SILENCE, SilenceLayer);
REGISTER_LAYER_CLASS(SIGMOID_CROSS_ENTROPY_LOSS, SigmoidCrossEntropyLossLayer);
REGISTER_LAYER_CLASS(SLICE, SliceLayer);
REGISTER_LAYER_CLASS(SOFTMAX_LOSS, SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SPLIT, SplitLayer);
REGISTER_LAYER_CLASS(THRESHOLD, ThresholdLayer);
REGISTER_LAYER_CLASS(WINDOW_DATA, WindowDataLayer);

}  // namespace caffe
<commit_msg>add explicit declaration - does that help the flakyness?<commit_after>#include <string>

#include "caffe/layer.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/vision_layers.hpp"

namespace caffe {

template <>
LayerRegistry<float>::CreatorRegistry LayerRegistry<float>::registry_;
template <>
LayerRegistry<double>::CreatorRegistry LayerRegistry<double>::registry_;

// GetLayer() defines the overall layer factory. The Get*Layer() functions
// define factories for layers with multiple computational engines.

// Get convolution layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetConvolutionLayer(
    const LayerParameter& param) {
  ConvolutionParameter_Engine engine = param.convolution_param().engine();
  if (engine == ConvolutionParameter_Engine_DEFAULT) {
    engine = ConvolutionParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ConvolutionParameter_Engine_CUDNN;
#endif
  }
  if (engine == ConvolutionParameter_Engine_CAFFE) {
    return new ConvolutionLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == ConvolutionParameter_Engine_CUDNN) {
    return new CuDNNConvolutionLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get pooling layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetPoolingLayer(const LayerParameter& param) {
  PoolingParameter_Engine engine = param.pooling_param().engine();
  if (engine == PoolingParameter_Engine_DEFAULT) {
    engine = PoolingParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = PoolingParameter_Engine_CUDNN;
#endif
  }
  if (engine == PoolingParameter_Engine_CAFFE) {
    return new PoolingLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == PoolingParameter_Engine_CUDNN) {
    if (p_param.pad_h() || p_param.pad_w() || param.top_size() > 1) {
      LOG(INFO) << "CUDNN does not support padding or multiple tops. "
                << "Using Caffe's own pooling layer.";
      return new PoolingLayer<DType>(param);
    }
    return new CuDNNPoolingLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get relu layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetReLULayer(const LayerParameter& param) {
  ReLUParameter_Engine engine = param.relu_param().engine();
  if (engine == ReLUParameter_Engine_DEFAULT) {
    engine = ReLUParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = ReLUParameter_Engine_CUDNN;
#endif
  }
  if (engine == ReLUParameter_Engine_CAFFE) {
    return new ReLULayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == ReLUParameter_Engine_CUDNN) {
    return new CuDNNReLULayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get sigmoid layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetSigmoidLayer(const LayerParameter& param) {
  SigmoidParameter_Engine engine = param.sigmoid_param().engine();
  if (engine == SigmoidParameter_Engine_DEFAULT) {
    engine = SigmoidParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SigmoidParameter_Engine_CUDNN;
#endif
  }
  if (engine == SigmoidParameter_Engine_CAFFE) {
    return new SigmoidLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == SigmoidParameter_Engine_CUDNN) {
    return new CuDNNSigmoidLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get tanh layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetTanHLayer(const LayerParameter& param) {
  TanHParameter_Engine engine = param.tanh_param().engine();
  if (engine == TanHParameter_Engine_DEFAULT) {
    engine = TanHParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = TanHParameter_Engine_CUDNN;
#endif
  }
  if (engine == TanHParameter_Engine_CAFFE) {
    return new TanHLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == TanHParameter_Engine_CUDNN) {
    return new CuDNNTanHLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Get softmax layer according to engine.
template <typename Dtype>
Layer<Dtype>* GetSoftmaxLayer(const LayerParameter& param) {
  SoftmaxParameter_Engine engine = param.softmax_param().engine();
  if (engine == SoftmaxParameter_Engine_DEFAULT) {
    engine = SoftmaxParameter_Engine_CAFFE;
#ifdef USE_CUDNN
    engine = SoftmaxParameter_Engine_CUDNN;
#endif
  }
  if (engine == SoftmaxParameter_Engine_CAFFE) {
    return new SoftmaxLayer<Dtype>(param);
#ifdef USE_CUDNN
  } else if (engine == SoftmaxParameter_Engine_CUDNN) {
    return new CuDNNSoftmaxLayer<Dtype>(param);
#endif
  } else {
    LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";
  }
}

// Layers that have a specific creator function.
REGISTER_LAYER_CREATOR(CONVOLUTION, GetConvolutionLayer);
REGISTER_LAYER_CREATOR(POOLING, GetPoolingLayer);
REGISTER_LAYER_CREATOR(RELU, GetReLULayer);
REGISTER_LAYER_CREATOR(SIGMOID, GetSigmoidLayer);
REGISTER_LAYER_CREATOR(SOFTMAX, GetSoftmaxLayer);
REGISTER_LAYER_CREATOR(TANH, GetTanHLayer);

// Layers that use their constructor as their default creator.
REGISTER_LAYER_CLASS(ACCURACY, AccuracyLayer);
REGISTER_LAYER_CLASS(ABSVAL, AbsValLayer);
REGISTER_LAYER_CLASS(ARGMAX, ArgMaxLayer);
REGISTER_LAYER_CLASS(BNLL, BNLLLayer);
REGISTER_LAYER_CLASS(CONCAT, ConcatLayer);
REGISTER_LAYER_CLASS(CONTRASTIVE_LOSS, ContrastiveLossLayer);
REGISTER_LAYER_CLASS(DATA, DataLayer);
REGISTER_LAYER_CLASS(DROPOUT, DropoutLayer);
REGISTER_LAYER_CLASS(DUMMY_DATA, DummyDataLayer);
REGISTER_LAYER_CLASS(EUCLIDEAN_LOSS, EuclideanLossLayer);
REGISTER_LAYER_CLASS(ELTWISE, EltwiseLayer);
REGISTER_LAYER_CLASS(FLATTEN, FlattenLayer);
REGISTER_LAYER_CLASS(HDF5_DATA, HDF5DataLayer);
REGISTER_LAYER_CLASS(HDF5_OUTPUT, HDF5OutputLayer);
REGISTER_LAYER_CLASS(HINGE_LOSS, HingeLossLayer);
REGISTER_LAYER_CLASS(IMAGE_DATA, ImageDataLayer);
REGISTER_LAYER_CLASS(IM2COL, Im2colLayer);
REGISTER_LAYER_CLASS(INFOGAIN_LOSS, InfogainLossLayer);
REGISTER_LAYER_CLASS(INNER_PRODUCT, InnerProductLayer);
REGISTER_LAYER_CLASS(LRN, LRNLayer);
REGISTER_LAYER_CLASS(MEMORY_DATA, MemoryDataLayer);
REGISTER_LAYER_CLASS(MVN, MVNLayer);
REGISTER_LAYER_CLASS(MULTINOMIAL_LOGISTIC_LOSS, MultinomialLogisticLossLayer);
REGISTER_LAYER_CLASS(POWER, PowerLayer);
REGISTER_LAYER_CLASS(SILENCE, SilenceLayer);
REGISTER_LAYER_CLASS(SIGMOID_CROSS_ENTROPY_LOSS, SigmoidCrossEntropyLossLayer);
REGISTER_LAYER_CLASS(SLICE, SliceLayer);
REGISTER_LAYER_CLASS(SOFTMAX_LOSS, SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SPLIT, SplitLayer);
REGISTER_LAYER_CLASS(THRESHOLD, ThresholdLayer);
REGISTER_LAYER_CLASS(WINDOW_DATA, WindowDataLayer);

}  // namespace caffe
<|endoftext|>


<commit_before>#pragma once

#include <cstdint>
#include <string>

#include <boost/mpl/set.hpp>

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

class size_t;
template<class> class datetime_t;

template<class Watcher>
struct config_t;

template<>
struct config_t<watcher::size_t> {
    std::uint64_t size;

    config_t(std::uint64_t size = 1 * 1024 * 1024) :
        size(size)
    {}
};

template<class TimePicker>
struct config_t<watcher::datetime_t<TimePicker>> {
    enum class period_t {
        hourly,
        daily,
        weekly,
        monthly
    };

    std::string marker;
};

template<class TimePicker>
struct config_t<boost::mpl::set<watcher::size_t, watcher::datetime_t<TimePicker>>> {
    std::uint64_t size;
    std::string marker;

    config_t(std::uint64_t size = 1 * 1024 * 1024, const std::string& marker = std::string()) :
        size(size),
        marker(marker)
    {}
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<commit_msg>Proper datetime marker initialization.<commit_after>#pragma once

#include <cstdint>
#include <string>

#include <boost/mpl/set.hpp>

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

class size_t;
template<class> class datetime_t;

template<class Watcher>
struct config_t;

template<>
struct config_t<watcher::size_t> {
    std::uint64_t size;

    config_t(std::uint64_t size = 1 * 1024 * 1024) :
        size(size)
    {}
};

template<class TimePicker>
struct config_t<watcher::datetime_t<TimePicker>> {
    enum class period_t {
        hourly,
        daily,
        weekly,
        monthly
    };

    std::string marker;
};

template<class TimePicker>
struct config_t<boost::mpl::set<watcher::size_t, watcher::datetime_t<TimePicker>>> {
    std::uint64_t size;
    std::string marker;

    config_t(std::uint64_t size = 1 * 1024 * 1024, const std::string& marker = "d") :
        size(size),
        marker(marker)
    {}
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<|endoftext|>


<commit_before>// Copyright (c) 2015, Galaxy Authors. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sdk/galaxy.h"

#include <cstdio>
#include <cstdlib>
#include <errno.h>
#include <string.h>
#include <gflags/gflags.h>

DECLARE_string(master_host);
DECLARE_string(master_port);
DECLARE_string(flagfile);

const std::string kGalaxyUsage = "\n./galaxy_client submit <job_name> <job_package> <replica> <cpu> <mem> <start_cmd>\n"
                                 "./galaxy_client list <jobid>\n"
                                 "./galaxy_client kill <jobid>";

int AddJob(int argc, char* argv[]) {
    baidu::galaxy::Galaxy* galaxy = baidu::galaxy::Galaxy::ConnectGalaxy(FLAGS_master_host + ":" + FLAGS_master_port);
    baidu::galaxy::JobDescription job;
    job.job_name = argv[0];
    job.binary = argv[1];
    job.replica = atoi(argv[2]);
    job.cpu_required = atoi(argv[3]);
    job.mem_required = atoi(argv[4]);
    job.deploy_step = 0;
    std::string jobid = galaxy->SubmitJob(job);
    if (jobid.empty()) {
        fprintf(stderr, "Submit job fail\n");
        return 1;
    }
    printf("Submit job %s\n", jobid.c_str());
    return 0;
}

int main(int argc, char* argv[]) {
    FLAGS_flagfile = "./galaxy.flag";
    ::google::SetUsageMessage(kGalaxyUsage);
    ::google::ParseCommandLineFlags(&argc, &argv, true);
    if(argc < 2){
        fprintf(stderr,"Usage:%s\n", kGalaxyUsage.c_str());
        return -1;
    }
    if (strcmp(argv[1], "submit") == 0) {
        return AddJob(argc -2, argv + 2);
    } else {
        fprintf(stderr,"Usage:%s\n", kGalaxyUsage.c_str());
        return -1;
    }
    return 0;
}

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<commit_msg>Add ListJob to client<commit_after>// Copyright (c) 2015, Galaxy Authors. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sdk/galaxy.h"

#include <cstdio>
#include <cstdlib>
#include <errno.h>
#include <string.h>
#include <gflags/gflags.h>

#include <tprinter.h>
#include <string_util.h>

DECLARE_string(master_host);
DECLARE_string(master_port);
DECLARE_string(flagfile);

const std::string kGalaxyUsage = "\n./galaxy_client submit <job_name> <job_package> <replica> <cpu> <mem> <start_cmd>\n"
                                 "./galaxy_client list <jobid>\n"
                                 "./galaxy_client kill <jobid>";

int AddJob(int argc, char* argv[]) {
    baidu::galaxy::Galaxy* galaxy = baidu::galaxy::Galaxy::ConnectGalaxy(FLAGS_master_host + ":" + FLAGS_master_port);
    baidu::galaxy::JobDescription job;
    job.job_name = argv[0];
    job.binary = argv[1];
    job.replica = atoi(argv[2]);
    job.cpu_required = atoi(argv[3]);
    job.mem_required = atoi(argv[4]);
    job.deploy_step = 0;
    std::string jobid = galaxy->SubmitJob(job);
    if (jobid.empty()) {
        fprintf(stderr, "Submit job fail\n");
        return 1;
    }
    printf("Submit job %s\n", jobid.c_str());
    return 0;
}

int ListJob(int argc, char* argv[]) {
    baidu::galaxy::Galaxy* galaxy = baidu::galaxy::Galaxy::ConnectGalaxy(FLAGS_master_host + ":" + FLAGS_master_port);
    std::vector<baidu::galaxy::JobInformation> infos;
    baidu::common::TPrinter tp(7);
    tp.AddRow(7, "", "id", "name", "running", "replica", "cpu", "memory");
    if (galaxy->ListJobs(&infos)) {
        for (uint32_t i = 0; i < infos.size(); i++) {
            std::vector<std::string> vs;
            vs.push_back(baidu::common::NumToString(i + 1));
            vs.push_back(infos[i].job_id);
            vs.push_back(infos[i].job_name);
            vs.push_back(baidu::common::NumToString(infos[i].running_num));
            vs.push_back(baidu::common::NumToString(infos[i].replica));
            vs.push_back(baidu::common::NumToString(infos[i].cpu_used));
            vs.push_back(baidu::common::NumToString(infos[i].mem_used));
            tp.AddRow(vs);
        }
        printf("%s\n", tp.ToString().c_str());
        return 0;
    }
    fprintf(stderr, "List fail\n");
    return 1;
}
int main(int argc, char* argv[]) {
    FLAGS_flagfile = "./galaxy.flag";
    ::google::SetUsageMessage(kGalaxyUsage);
    ::google::ParseCommandLineFlags(&argc, &argv, true);
    if(argc < 2){
        fprintf(stderr,"Usage:%s\n", kGalaxyUsage.c_str());
        return -1;
    }
    if (strcmp(argv[1], "submit") == 0) {
        return AddJob(argc - 2, argv + 2);
    } else if (strcmp(argv[1], "list") == 0) {
        return ListJob(argc - 2, argv + 2);
    } else {
        fprintf(stderr,"Usage:%s\n", kGalaxyUsage.c_str());
        return -1;
    }
    return 0;
}

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_num_timers(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_connect(-1);
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
				++m_num_timers;
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);
		--m_num_timers;

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e && m_num_connecting == 0 && m_num_timers > 0) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			++m_num_timers;
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<commit_msg>fix connection queue timeout logic<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_num_timers(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_connect(-1);
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
				++m_num_timers;
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);
		--m_num_timers;

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);

		// if there was an error, it's most likely operation aborted,
		// we should just quit. However, in case there are still connections
		// in connecting state, and there are no other timer invocations
		// we need to stick around still.
		if (e && (m_num_connecting == 0 || m_num_timers > 0)) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			++m_num_timers;
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/****************************************************************************

  Basic Threads

**************************************************************************/
#include "P_EventSystem.h"
#include "tscore/ink_string.h"

///////////////////////////////////////////////
// Common Interface impl                     //
///////////////////////////////////////////////

ink_hrtime Thread::cur_time = ink_get_hrtime_internal();
inkcoreapi ink_thread_key Thread::thread_data_key;

namespace
{
static bool initialized ATS_UNUSED = ([]() -> bool {
  // File scope initialization goes here.
  ink_thread_key_create(&Thread::thread_data_key, nullptr);
  return true;
})();
}

Thread::Thread()
{
  mutex = new_ProxyMutex();
  MUTEX_TAKE_LOCK(mutex, (EThread *)this);
  mutex->nthread_holding += THREAD_MUTEX_THREAD_HOLDING;
}

Thread::~Thread()
{
  ink_release_assert(mutex->thread_holding == (EThread *)this);

  if (ink_thread_getspecific(Thread::thread_data_key) == this) {
    // Clear pointer to this object stored in thread-specific data by set_specific.
    //
    ink_thread_setspecific(Thread::thread_data_key, nullptr);
  }

  mutex->nthread_holding -= THREAD_MUTEX_THREAD_HOLDING;
  MUTEX_UNTAKE_LOCK(mutex, (EThread *)this);
}

///////////////////////////////////////////////
// Unix & non-NT Interface impl              //
///////////////////////////////////////////////

struct thread_data_internal {
  ThreadFunction f;                  ///< Function to excecute in the thread.
  Thread *me;                        ///< The class instance.
  char name[MAX_THREAD_NAME_LENGTH]; ///< Name for the thread.
};

static void *
spawn_thread_internal(void *a)
{
  auto *p = static_cast<thread_data_internal *>(a);

  p->me->set_specific();
  ink_set_thread_name(p->name);

  if (p->f) {
    p->f();
  } else {
    p->me->execute();
  }

  delete p;
  return nullptr;
}

void
Thread::start(const char *name, void *stack, size_t stacksize, ThreadFunction const &f)
{
  auto *p = new thread_data_internal{f, this, ""};

  ink_zero(p->name);
  ink_strlcpy(p->name, name, MAX_THREAD_NAME_LENGTH);
  if (stacksize == 0) {
    stacksize = DEFAULT_STACKSIZE;
  }
  ink_thread_create(&tid, spawn_thread_internal, p, 0, stacksize, stack);
}
<commit_msg>cppcheck: Change to C++ style pointer casting in Thread.cc<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/****************************************************************************

  Basic Threads

**************************************************************************/
#include "P_EventSystem.h"
#include "tscore/ink_string.h"

///////////////////////////////////////////////
// Common Interface impl                     //
///////////////////////////////////////////////

ink_hrtime Thread::cur_time = ink_get_hrtime_internal();
inkcoreapi ink_thread_key Thread::thread_data_key;

namespace
{
static bool initialized ATS_UNUSED = ([]() -> bool {
  // File scope initialization goes here.
  ink_thread_key_create(&Thread::thread_data_key, nullptr);
  return true;
})();
}

Thread::Thread()
{
  mutex = new_ProxyMutex();
  MUTEX_TAKE_LOCK(mutex, static_cast<EThread *>(this));
  mutex->nthread_holding += THREAD_MUTEX_THREAD_HOLDING;
}

Thread::~Thread()
{
  ink_release_assert(mutex->thread_holding == static_cast<EThread *>(this));

  if (ink_thread_getspecific(Thread::thread_data_key) == this) {
    // Clear pointer to this object stored in thread-specific data by set_specific.
    //
    ink_thread_setspecific(Thread::thread_data_key, nullptr);
  }

  mutex->nthread_holding -= THREAD_MUTEX_THREAD_HOLDING;
  MUTEX_UNTAKE_LOCK(mutex, static_cast<EThread *>(this));
}

///////////////////////////////////////////////
// Unix & non-NT Interface impl              //
///////////////////////////////////////////////

struct thread_data_internal {
  ThreadFunction f;                  ///< Function to excecute in the thread.
  Thread *me;                        ///< The class instance.
  char name[MAX_THREAD_NAME_LENGTH]; ///< Name for the thread.
};

static void *
spawn_thread_internal(void *a)
{
  auto *p = static_cast<thread_data_internal *>(a);

  p->me->set_specific();
  ink_set_thread_name(p->name);

  if (p->f) {
    p->f();
  } else {
    p->me->execute();
  }

  delete p;
  return nullptr;
}

void
Thread::start(const char *name, void *stack, size_t stacksize, ThreadFunction const &f)
{
  auto *p = new thread_data_internal{f, this, ""};

  ink_zero(p->name);
  ink_strlcpy(p->name, name, MAX_THREAD_NAME_LENGTH);
  if (stacksize == 0) {
    stacksize = DEFAULT_STACKSIZE;
  }
  ink_thread_create(&tid, spawn_thread_internal, p, 0, stacksize, stack);
}
<|endoftext|>