<commit_before>/*
 * Worldvisions Weaver Software:
 *   Copyright (C) 1997, 1998 Worldvisions Computer Technology, Inc.
 *
 * Intelligent serial port scanner: try to find a port (or ports)
 * with a working modem, guess a basic startup init string, and find
 * the maximum baud rate.
 */
#include "wvmodemscan.h"
#include "wvmodem.h"
#include "strutils.h"
#include <time.h>
#include <assert.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>

// startup at atz atq0 atv1 ate1 ats0 carrier dtr fastdial
// baudstep reinit done
static char *commands[WvModemScan::NUM_STAGES] = {
    NULL, "", "Z", "Q0", "V1", "E1", "S0=0", "&C1", "&D2", "S11=55",
    "+FCLASS=0", NULL,
    NULL, "", NULL
};

WvModemScan::WvModemScan(const char *devname)
	: debug(devname, WvLog::Debug)
{
    stage = Startup;
    memset(status, 0, sizeof(status));

    if (devname[0] == '/')
	file = devname;
    else
	file = WvString("/dev/%s", devname);

    baud = 1200;
    modem = NULL;
    tries = 0;
    broken = false;
}

WvModemScan::~WvModemScan()
{
    if (isok() && isdone())
	debug(WvLog::Info, "Speed %s; init \"%s\"\n", maxbaud(), initstr());

    if (modem)
	delete modem;
}

bool WvModemScan::isok() const
{
    return !broken;
}

WvString WvModemScan::initstr() const
{
    WvString s;
    s.setsize(100);
    strcpy(s.str, "AT");

    for (int i = 0; i < NUM_STAGES; i++)
    {
	if (status[i] != Worked && status[i] != Test)
	    continue;
	if (!commands[i] || !commands[i][0])
	    continue;
	if ((commands[i][0]=='Z' || commands[i][0]=='I') && status[i] != Test)
	    continue;

	strcat(s.str, commands[i]);
	strcat(s.str, " ");
    }

    return trim_string(s.str);
}

void WvModemScan::execute()
{
    if (isdone() || !isok()) return;

    switch ((Stage)stage)
    {
    case Startup:
	assert(!modem);
	modem = new WvModem(file.str, baud);
	modem->die_fast = true;
	if (!modem->isok())
	{
	    if (modem->geterr()
		&& modem->geterr() != EIO
		&& modem->geterr() != ENOENT
		&& modem->geterr() != ENODEV)
	    {
		debug(WvLog::Info, "%s\n", modem->errstr());
	    }
	    broken = true;
	}
	else
	    stage++;
	break;

    case AT:
    case ATZ:
    case ATQ0:
    case ATV1:
    case ATE1:
    case ATS0:
    case Carrier:
    case DTR:
    case FastDial:
    case FCLASS:
    case Reinit:
	assert(modem);
	status[stage] = Test;
	if ( !doresult(WvString("%s\r", initstr()), stage==ATZ ? 3000 : 500)
	    || (stage <= ATZ && status[stage]==Fail) )
	{
	    tries++;

	    if (tries >= 3)
	    {
		debug("nothing.\n");
		broken = true;
	    }

	    // else try again shortly
	}
	else
	{
	    tries = 0;
	    stage++;
	}
	break;

    case GetIdent:
	assert(modem);
	status[stage] = Test;
	debug("Modem Identifier: ");
	if ( !doresult(WvString("ATI\r"), 500) || (status[stage]==Fail) )
	{
	    tries++;

	    if (tries >= 3)
	    {
	    	debug("nothing.\n");
	    }

	    // else try again shortly
	}
	else
	{
	    if (is_isdn())
	    	debug("Looks like an ISDN modem.\n");
	    tries = 0;
	    stage++;
	}

    case BaudStep:
	assert(modem);
	modem->drain();
	modem->speed(baud*2);

	// if we try 2*baud five times without success, or setting 2*baud
	// results in a lower setting than 1*baud, we have reached the
	// top speed of the modem or the serial port, respectively.
	if (tries >= 3 || modem->speed() < baud)
	{
	    // using the absolute maximum baud rate confuses many modems
	    // in obscure ways; step down one.
	    modem->speed(baud);
	    debug("Max speed is %s; ", modem->speed());
	    if (is_isdn())
	    {
	    	//if (modem->speed() != 230400)		// FIXME
	    	    modem->speed(115200);
	    	baud = modem->speed();
	    	debug ("using %s for ISDN modem.\n", baud);
	    }
	    else
	    {
		modem->speed(baud / 2);
		baud = modem->speed(); // get correct value!
		debug("using %s to be safe.\n", baud);
	    }

	    stage++;
	    status[stage] = Worked;
	    break;
	}

	debug("Speed %s: ", modem->speed());

	if (!doresult("AT\r", 500) || status[stage] == Fail)
	{
	    tries++;
	}
	else // got a response
	{
	    baud *= 2;
	    tries = 0;
	    // next time through we try a faster speed
	}
	break;

    case Done:
    case NUM_STAGES:
	assert(0);
	break; // should never happen
    }

    if (stage == Done) // we just incremented stage number to Done
    {
	if (modem)
	    delete modem;
	modem = NULL;
    }
}

bool WvModemScan::doresult(const WvString &s, int msec)
{
    char buf[1024], *cptr;
    size_t len;

    modem->drain();
    usleep(50 * 1000); // delay a bit after emptying the buffer
    modem->write(s);

    debug("%s -- ", trim_string(s.str));

    len = coagulate(buf, sizeof(buf), msec);

    if (!len)
    {
	// debug("(no answer yet)\n");
	return false;
    }

    buf[len] = 0;

    cptr = trim_string(buf);
    while (strchr(cptr, '\r'))
    {
	cptr = trim_string(strchr(cptr, '\r'));
	if (stage == GetIdent && status[stage] == Test)
	{
	    char *p = strpbrk(cptr, "\n\r");
	    if (p) *p=0;
	    identifier = cptr;
	    status[stage] = Worked;
	    debug("%s\n", identifier);
	    return true;
	}
    }
    while (strchr(cptr, '\n'))
	cptr = trim_string(strchr(cptr, '\n'));

    debug("%s\n", cptr);

    if (!strncmp(cptr, "OK", 2)
	|| (stage <= ATV1 && *(strchr(cptr,0) - 1)=='0'))
    {
	status[stage] = Worked;
    }
    else
	status[stage] = Fail;

    return true;
}

size_t WvModemScan::coagulate(char *buf, size_t size, int msec)
{
    size_t len = 0, amt;
    char *cptr = buf;

    assert(modem);

    if (!modem->isok())
    {
	broken = true;
	return 0;
    }

    while (modem->select(msec))
    {
	amt = modem->read(cptr, size-1);
	cptr[amt] = 0;

	len += amt;
	size -= amt;
	cptr += amt;

	if (strstr(buf, "OK") || strstr(buf, "ERROR"))
	    break;
    }

    return len;
}

char *WvModemScan::is_isdn() const
{
    if (!identifier.str[0])
    	return NULL;

    if (identifier == "3C882")		// 3Com Impact IQ
    	return identifier.str;
    if (identifier == "960")		// Motorola BitSurfr
    	return identifier.str;

    return NULL;
}

static int fileselect(const struct dirent *e)
{
    return !strncmp(e->d_name, "ttyS", 4);     // serial
       // (no intenral ISDN support)   || !strncmp(e->d_name, "ttyI", 4);
}

static int filesort(const void *_e1, const void *_e2)
{
    dirent const * const *e1 = (dirent const * const *)_e1;
    dirent const * const *e2 = (dirent const * const *)_e2;
    const char *p1, *p2;
    int diff;

    for (p1=(*e1)->d_name, p2=(*e2)->d_name; *p1 || *p2; p1++, p2++)
    {
	if (!isdigit(*p1) || !isdigit(*p2))
	{
	    diff = *p1 - *p2;
	    if (diff) return diff;
	}
	else // both are digits
	{
	    return atoi(p1) - atoi(p2);
	}
    }

    return 0;
}

void WvModemScanList::setup()
{
    struct dirent **namelist;
    struct stat mouse;
    int num, count, statresponse;

    log = new WvLog("Port Scan", WvLog::Debug);
    thisline = -1;
    printed = false;

    statresponse = stat("/dev/mouse", &mouse);
    num = scandir("/dev", &namelist, fileselect, filesort);

    if (num < 0)
	return;

    for (count = 0; count < num; count++)
    {
	// never search the device assigned to /dev/mouse; most mouse-using
	// programs neglect to lock the device, so we could mess up the
	// mouse response!  (We are careful to put things back when done,
	// but X seems to still get confused.)  Anyway the mouse is seldom
	// a modem.
	if (statresponse==0 && mouse.st_ino == (ino_t)namelist[count]->d_ino)
	{
	    log->print("\nIgnoring %s because /dev/mouse is a link to it.\n",
		       namelist[count]->d_name);
	    continue;
	}

	append(new WvModemScan(namelist[count]->d_name), true);
    }

    while (--num >= 0)
	free(namelist[num]);
    free(namelist);
}

void WvModemScanList::shutdown()
{
    delete log;
}

// we used to try to scan all ports simultaneously; unfortunately, this
// caused problems when people had "noncritical" IRQ conflicts (ie. two
// serial ports with the same IRQ, but they work as long as only one port
// is used at a time).  Also, the log messages looked really confused.
//
// So now we do the scanning sequentially, which is slower.  The port
// being scanned is at the head of the list.  If the probe fails, we
// unlink the element.  If it succeeds, we have found a modem -- so,
// isdone() knows we are done when the _first_ element is done.
//
void WvModemScanList::execute()
{
    assert (!isdone());

    WvModemScanList::Iter i(*this);

    i.rewind();
    if (!i.next()) return; // note: the first next() is the _first_ item!

    WvModemScan *s = i.data();

    if (!s->isok())
    {
	if (!printed)
	{
	    const WvString &f = s->filename();
	    const char *cptr = strrchr(f.str, '/');
	    if (cptr)
		cptr++;
	    else
		cptr = f.str;

	    if (!strncmp(cptr, "tty", 3))
		cptr += 3;

	    ++thisline %= 8;
	    if (!thisline)
		log->print("\n");

	    log->print("%-4s ", cptr);
	}

	i.unlink();
	printed = false;
    }
    else
    {
	s->execute();

	if (s->isok())
	    printed = true;
    }

    if (isdone())
	log->write("\n", 1);
}

bool WvModemScanList::isdone()
{
    WvModemScanList::Iter i(*this);

    i.rewind();
    if (i.next())
	return i.data()->isdone();
    else
	return true; // empty list, so we are done!
}
<commit_msg><commit_after>/*
 * Worldvisions Weaver Software:
 *   Copyright (C) 1997, 1998 Worldvisions Computer Technology, Inc.
 *
 * Intelligent serial port scanner: try to find a port (or ports)
 * with a working modem, guess a basic startup init string, and find
 * the maximum baud rate.
 */
#include "wvmodemscan.h"
#include "wvmodem.h"
#include "strutils.h"
#include <time.h>
#include <assert.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>

// startup at atz atq0 atv1 ate1 ats0 carrier dtr fastdial
// baudstep reinit done
static char *commands[WvModemScan::NUM_STAGES] = {
    NULL, "", "Z", "Q0", "V1", "E1", "S0=0", "&C1", "&D2", "S11=55",
    "+FCLASS=0", NULL,
    NULL, "", NULL
};

WvModemScan::WvModemScan(const char *devname)
	: debug(devname, WvLog::Debug)
{
    stage = Startup;
    memset(status, 0, sizeof(status));

    if (devname[0] == '/')
	file = devname;
    else
	file = WvString("/dev/%s", devname);

    baud = 1200;
    modem = NULL;
    tries = 0;
    broken = false;
}

WvModemScan::~WvModemScan()
{
    if (isok() && isdone())
	debug(WvLog::Info, "Speed %s; init \"%s\"\n", maxbaud(), initstr());

    if (modem)
	delete modem;
}

bool WvModemScan::isok() const
{
    return !broken;
}

WvString WvModemScan::initstr() const
{
    WvString s;
    s.setsize(100);
    strcpy(s.str, "AT");

    for (int i = 0; i < NUM_STAGES; i++)
    {
	if (status[i] != Worked && status[i] != Test)
	    continue;
	if (!commands[i] || !commands[i][0])
	    continue;
	if ((commands[i][0]=='Z' || commands[i][0]=='I') && status[i] != Test)
	    continue;

	strcat(s.str, commands[i]);
	strcat(s.str, " ");
    }

    return trim_string(s.str);
}

void WvModemScan::execute()
{
    if (isdone() || !isok()) return;

    switch ((Stage)stage)
    {
    case Startup:
	assert(!modem);
	modem = new WvModem(file.str, baud);
	modem->die_fast = true;
	if (!modem->isok())
	{
	    if (modem->geterr()
		&& modem->geterr() != EIO
		&& modem->geterr() != ENOENT
		&& modem->geterr() != ENODEV)
	    {
		debug(WvLog::Info, "%s\n", modem->errstr());
	    }
	    broken = true;
	}
	else
	    stage++;
	break;

    case AT:
    case ATZ:
    case ATQ0:
    case ATV1:
    case ATE1:
    case ATS0:
    case Carrier:
    case DTR:
    case FastDial:
    case FCLASS:
    case Reinit:
	assert(modem);
	status[stage] = Test;
	if ( !doresult(WvString("%s\r", initstr()), stage==ATZ ? 3000 : 500)
	    || (stage <= ATZ && status[stage]==Fail) )
	{
	    tries++;

	    if (tries >= 3)
	    {
		debug("nothing.\n");
		broken = true;
	    }

	    // else try again shortly
	}
	else
	{
	    tries = 0;
	    stage++;
	}
	break;

    case GetIdent:
	assert(modem);
	status[stage] = Test;
	debug("Modem Identifier: ");
	if ( !doresult(WvString("ATI\r"), 500) || (status[stage]==Fail) )
	{
	    tries++;

	    if (tries >= 3)
	    {
	    	debug("nothing.\n");
	    }

	    // else try again shortly
	}
	else
	{
	    if (is_isdn())
	    	debug("Looks like an ISDN modem.\n");
	    tries = 0;
	    stage++;
	}

    case BaudStep:
	assert(modem);
	modem->drain();
	modem->speed(baud*2);

	// if we try 2*baud five times without success, or setting 2*baud
	// results in a lower setting than 1*baud, we have reached the
	// top speed of the modem or the serial port, respectively.
	if (tries >= 3 || modem->speed() < baud)
	{
	    // using the absolute maximum baud rate confuses many modems
	    // in obscure ways; step down one.
	    modem->speed(baud);
	    debug("Max speed is %s; ", modem->speed());
	    if (is_isdn())
	    {
	    	//if (modem->speed() != 230400)		// FIXME
	    	    modem->speed(115200);
	    	baud = modem->speed();
	    	debug ("using %s for ISDN modem.\n", baud);
	    }
	    else
	    {
		modem->speed(baud / 2);
		baud = modem->speed(); // get correct value!
		debug("using %s to be safe.\n", baud);
	    }

	    stage++;
	    status[stage] = Worked;
	    break;
	}

	debug("Speed %s: ", modem->speed());

	if (!doresult("AT\r", 500) || status[stage] == Fail)
	{
	    tries++;
	}
	else // got a response
	{
	    baud *= 2;
	    tries = 0;
	    // next time through we try a faster speed
	}
	break;

    case Done:
    case NUM_STAGES:
	assert(0);
	break; // should never happen
    }

    if (stage == Done) // we just incremented stage number to Done
    {
	if (modem)
	    delete modem;
	modem = NULL;
    }
}

bool WvModemScan::doresult(const WvString &s, int msec)
{
    char buf[1024], *cptr;
    size_t len;

    modem->drain();
    usleep(50 * 1000); // delay a bit after emptying the buffer
    modem->write(s);

    debug("%s -- ", trim_string(s.str));

    len = coagulate(buf, sizeof(buf), msec);

    if (!len)
    {
	// debug("(no answer yet)\n");
	return false;
    }

    buf[len] = 0;

    cptr = trim_string(buf);
    while (strchr(cptr, '\r'))
    {
	cptr = trim_string(strchr(cptr, '\r'));
	if (stage == GetIdent && status[stage] == Test)
	{
	    char *p = strpbrk(cptr, "\n\r");
	    if (p) *p=0;
	    identifier = cptr;
	    status[stage] = Worked;
	    debug("%s\n", identifier);
	    return true;
	}
    }
    while (strchr(cptr, '\n'))
	cptr = trim_string(strchr(cptr, '\n'));

    debug("%s\n", cptr);

    if (!strncmp(cptr, "OK", 2)
	|| (stage <= ATV1 && *(strchr(cptr,0) - 1)=='0'))
    {
	status[stage] = Worked;
    }
    else
	status[stage] = Fail;

    return true;
}

size_t WvModemScan::coagulate(char *buf, size_t size, int msec)
{
    size_t len = 0, amt;
    char *cptr = buf;

    assert(modem);

    if (!modem->isok())
    {
	broken = true;
	return 0;
    }

    while (modem->select(msec))
    {
	amt = modem->read(cptr, size-1);
	cptr[amt] = 0;

	len += amt;
	size -= amt;
	cptr += amt;

	if (strstr(buf, "OK") || strstr(buf, "ERROR"))
	    break;
    }

    return len;
}

char *WvModemScan::is_isdn() const
{
    if (!identifier.str)
    	return NULL;

    if (identifier == "3C882")		// 3Com Impact IQ
    	return identifier.str;
    if (identifier == "960")		// Motorola BitSurfr
    	return identifier.str;

    return NULL;
}

static int fileselect(const struct dirent *e)
{
    return !strncmp(e->d_name, "ttyS", 4);     // serial
       // (no internal ISDN support)   || !strncmp(e->d_name, "ttyI", 4);
}

static int filesort(const void *_e1, const void *_e2)
{
    dirent const * const *e1 = (dirent const * const *)_e1;
    dirent const * const *e2 = (dirent const * const *)_e2;
    const char *p1, *p2;
    int diff;

    for (p1=(*e1)->d_name, p2=(*e2)->d_name; *p1 || *p2; p1++, p2++)
    {
	if (!isdigit(*p1) || !isdigit(*p2))
	{
	    diff = *p1 - *p2;
	    if (diff) return diff;
	}
	else // both are digits
	{
	    return atoi(p1) - atoi(p2);
	}
    }

    return 0;
}

void WvModemScanList::setup()
{
    struct dirent **namelist;
    struct stat mouse;
    int num, count, statresponse;

    log = new WvLog("Port Scan", WvLog::Debug);
    thisline = -1;
    printed = false;

    statresponse = stat("/dev/mouse", &mouse);
    num = scandir("/dev", &namelist, fileselect, filesort);

    if (num < 0)
	return;

    for (count = 0; count < num; count++)
    {
	// never search the device assigned to /dev/mouse; most mouse-using
	// programs neglect to lock the device, so we could mess up the
	// mouse response!  (We are careful to put things back when done,
	// but X seems to still get confused.)  Anyway the mouse is seldom
	// a modem.
	if (statresponse==0 && mouse.st_ino == (ino_t)namelist[count]->d_ino)
	{
	    log->print("\nIgnoring %s because /dev/mouse is a link to it.\n",
		       namelist[count]->d_name);
	    continue;
	}

	append(new WvModemScan(namelist[count]->d_name), true);
    }

    while (--num >= 0)
	free(namelist[num]);
    free(namelist);
}

void WvModemScanList::shutdown()
{
    delete log;
}

// we used to try to scan all ports simultaneously; unfortunately, this
// caused problems when people had "noncritical" IRQ conflicts (ie. two
// serial ports with the same IRQ, but they work as long as only one port
// is used at a time).  Also, the log messages looked really confused.
//
// So now we do the scanning sequentially, which is slower.  The port
// being scanned is at the head of the list.  If the probe fails, we
// unlink the element.  If it succeeds, we have found a modem -- so,
// isdone() knows we are done when the _first_ element is done.
//
void WvModemScanList::execute()
{
    assert (!isdone());

    WvModemScanList::Iter i(*this);

    i.rewind();
    if (!i.next()) return; // note: the first next() is the _first_ item!

    WvModemScan *s = i.data();

    if (!s->isok())
    {
	if (!printed)
	{
	    const WvString &f = s->filename();
	    const char *cptr = strrchr(f.str, '/');
	    if (cptr)
		cptr++;
	    else
		cptr = f.str;

	    if (!strncmp(cptr, "tty", 3))
		cptr += 3;

	    ++thisline %= 8;
	    if (!thisline)
		log->print("\n");

	    log->print("%-4s ", cptr);
	}

	i.unlink();
	printed = false;
    }
    else
    {
	s->execute();

	if (s->isok())
	    printed = true;
    }

    if (isdone())
	log->write("\n", 1);
}

bool WvModemScanList::isdone()
{
    WvModemScanList::Iter i(*this);

    i.rewind();
    if (i.next())
	return i.data()->isdone();
    else
	return true; // empty list, so we are done!
}
<|endoftext|>


<commit_before>/*
 * 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.
 */

/*!
 * \file src/runtime/contrib/tensorrt/tensorrt_runtime.cc
 * \brief JSON runtime implementation for TensorRT.
 */

#include <dmlc/parameter.h>
#include <tvm/runtime/ndarray.h>
#include <tvm/runtime/registry.h>

#include <fstream>

#include "../../file_utils.h"
#include "../json/json_node.h"
#include "../json/json_runtime.h"

#ifdef TVM_GRAPH_RUNTIME_TENSORRT
#include "NvInfer.h"
#include "tensorrt_builder.h"
#endif

namespace tvm {
namespace runtime {
namespace contrib {

struct PairHash {
  template <class T1, class T2>
  std::size_t operator()(const std::pair<T1, T2>& pair) const {
    return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
  }
};

using namespace tvm::runtime::json;

class TensorRTRuntime : public JSONRuntimeBase {
 public:
  /*!
   * \brief The TensorRT runtime module. Deserialize the provided functions
   * on creation and store in the layer cache.
   *
   * \param symbol_name The name of the function.
   * \param graph_json serialized JSON representation of a sub-graph.
   * \param const_names The names of each constant in the sub-graph.
   */
  explicit TensorRTRuntime(const std::string& symbol_name, const std::string& graph_json,
                           const Array<String>& const_names)
      : JSONRuntimeBase(symbol_name, graph_json, const_names),
        use_implicit_batch_(true),
        max_workspace_size_(size_t(1) << 30) {}

  /*!
   * \brief The type key of the module.
   *
   * \return module type key.
   */
  const char* type_key() const override { return "tensorrt"; }

  /*!
   * \brief Initialize runtime. Create TensorRT layer from JSON
   * representation.
   *
   * \param consts The constant params from compiled model.
   */
  void Init(const Array<NDArray>& consts) override {
    ICHECK_EQ(consts.size(), const_idx_.size())
        << "The number of input constants must match the number of required.";
    LoadGlobalAttributes();
    if (GetCachedEnginesFromDisk()) return;
    SetupConstants(consts);
  }

  void LoadGlobalAttributes() {
    // These settings are global to the entire subgraph. Codegen will add them as attributes to all
    // op nodes. Read from first one.
    for (size_t i = 0; i < nodes_.size(); ++i) {
      if (nodes_[i].HasAttr("use_implicit_batch") && nodes_[i].HasAttr("max_workspace_size")) {
        use_implicit_batch_ =
            std::stoi(nodes_[i].GetAttr<std::vector<std::string>>("use_implicit_batch")[0]);
        // Allow max_workspace_size to be overridden at runtime.
        size_t runtime_max_workspace_size =
            dmlc::GetEnv("TVM_TENSORRT_MAX_WORKSPACE_SIZE", size_t(0));
        if (runtime_max_workspace_size != 0) {
          max_workspace_size_ = runtime_max_workspace_size;
        } else {
          max_workspace_size_ =
              std::stoul(nodes_[i].GetAttr<std::vector<std::string>>("max_workspace_size")[0]);
        }
        return;
      }
    }
  }

#ifdef TVM_GRAPH_RUNTIME_TENSORRT
  /*! \brief Run inference using built engine. */
  void Run() override {
    BuildEngine();
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    if (batch_size_ == 0) return;
    auto& engine_and_context = trt_engine_cache_.at(std::make_pair(symbol_name_, batch_size_));
    auto engine = engine_and_context.engine;
    auto context = engine_and_context.context;
    auto& device_buffers = engine_and_context.device_buffers;
    std::vector<void*> bindings(engine->getNbBindings(), nullptr);
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      if (nodes_[nid].GetOpType() == "input") {
        for (size_t j = 0; j < nodes_[nid].GetOpShape().size(); ++j) {
          uint32_t eid = EntryID(nid, j);
          const std::string name = nodes_[nid].GetOpName() + "_" + std::to_string(j);
          int binding_index = engine->getBindingIndex(name.c_str());
          ICHECK_NE(binding_index, -1);
          if (data_entry_[eid]->ctx.device_type == kDLGPU) {
            bindings[binding_index] = data_entry_[eid]->data;
          } else {
            device_buffers[binding_index].CopyFrom(data_entry_[eid]);
            bindings[binding_index] = device_buffers[binding_index]->data;
          }
        }
      }
    }

    for (size_t i = 0; i < outputs_.size(); ++i) {
      uint32_t eid = EntryID(outputs_[i]);
      const std::string& name = engine_and_context.outputs[i];
      int binding_index = engine->getBindingIndex(name.c_str());
      ICHECK_NE(binding_index, -1);
      if (data_entry_[eid]->ctx.device_type == kDLGPU) {
        bindings[binding_index] = data_entry_[eid]->data;
      } else {
        bindings[binding_index] = device_buffers[binding_index]->data;
      }
    }

#if TRT_VERSION_GE(6, 0, 1)
    if (use_implicit_batch_) {
      ICHECK(context->execute(batch_size_, bindings.data())) << "Running TensorRT failed.";
    } else {
      ICHECK(context->executeV2(bindings.data())) << "Running TensorRT failed.";
    }
#else
    ICHECK(context->execute(batch_size_, bindings.data())) << "Running TensorRT failed.";
#endif

    // Copy outputs from GPU buffers if needed.
    for (size_t i = 0; i < outputs_.size(); ++i) {
      uint32_t eid = EntryID(outputs_[i]);
      const std::string& name = engine_and_context.outputs[i];
      int binding_index = engine->getBindingIndex(name.c_str());
      ICHECK_NE(binding_index, -1);
      if (data_entry_[eid]->ctx.device_type != kDLGPU) {
        device_buffers[binding_index].CopyTo(const_cast<DLTensor*>(data_entry_[eid]));
      }
    }
  }

 private:
  /*!
   * \brief Build TensorRT engine from JSON representation and cache it. If engine is already built,
   * do nothing.
   */
  void BuildEngine() {
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    if (trt_engine_cache_.count(std::make_pair(symbol_name_, batch_size_))) return;
    DLOG(INFO) << "Building new TensorRT engine for subgraph " << symbol_name_
               << " with batch size " << batch_size_;
    const bool use_fp16 = dmlc::GetEnv("TVM_TENSORRT_USE_FP16", false);
    TensorRTBuilder builder(&logger_, data_entry_, max_workspace_size_, use_implicit_batch_,
                            use_fp16, batch_size_);

    // Add inputs and constants.
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      const auto& node = nodes_[nid];
      std::string name = node.GetOpName();
      if (node.GetOpType() == "input") {
        builder.AddInput(nid, EntryID(nid, 0), node);
      } else {
        ICHECK_EQ(node.GetOpType(), "const");
        uint32_t eid = EntryID(nid, 0);
        builder.AddConstant(nid, data_entry_[eid]);
      }
    }

    // Add layers.
    for (size_t nid = 0; nid < nodes_.size(); ++nid) {
      const auto& node = nodes_[nid];
      if (node.GetOpType() != "kernel") continue;
      builder.AddLayer(nid, node);
    }

    // Add outputs.
    for (size_t i = 0; i < outputs_.size(); ++i) {
      builder.AddOutput(outputs_[i], EntryID(outputs_[i]));
    }

    // Build engine.
    trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)] = builder.BuildEngine();
    DLOG(INFO) << "Finished building TensorRT engine for subgraph " << symbol_name_
               << " with batch size " << batch_size_;
    CacheEngineToDisk();
  }

  /*! \brief If TVM_TENSORRT_CACHE_DIR is set, will check that directory for
   * already built TRT engines and load into trt_engine_cache_ so they don't
   * have to be built at first inference.
   */
  bool GetCachedEnginesFromDisk() {
    std::string cache_dir = dmlc::GetEnv("TVM_TENSORRT_CACHE_DIR", std::string(""));
    if (cache_dir.empty()) return false;
    std::string key = GetSubgraphKey();
    std::string path = cache_dir + "/" + key + ".plan";
    // Check if engine is in the cache.
    std::ifstream infile(path, std::ios::binary);
    if (!infile.good()) return false;
    DLOG(INFO) << "Loading cached TensorRT engine from " << path;
    infile.close();
    std::string serialized_engine;
    LoadBinaryFromFile(path, &serialized_engine);
    // Deserialize engine
    nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger_);
    TensorRTEngineAndContext engine_and_context;
    engine_and_context.engine =
        runtime->deserializeCudaEngine(&serialized_engine[0], serialized_engine.size(), nullptr);
    engine_and_context.context = engine_and_context.engine->createExecutionContext();
    // Load metadata
    std::string meta_path = cache_dir + "/" + key + ".meta";
    std::string serialized_meta;
    LoadBinaryFromFile(meta_path, &serialized_meta);
    std::istringstream is(serialized_meta);
    dmlc::JSONReader reader(&is);
    dmlc::JSONObjectReadHelper helper;
    helper.DeclareField("inputs", &engine_and_context.inputs);
    helper.DeclareField("outputs", &engine_and_context.outputs);
    helper.ReadAllFields(&reader);
    const int batch_size = 1;
    trt_engine_cache_[std::make_pair(symbol_name_, batch_size)] = engine_and_context;
    return true;
  }

  /*! \brief If TVM_TENSORRT_CACHE_DIR is set, will save the engine to that
   * directory so it can be loaded later.
   */
  void CacheEngineToDisk() {
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    std::string cache_dir = dmlc::GetEnv("TVM_TENSORRT_CACHE_DIR", std::string(""));
    if (cache_dir.empty()) return;
    std::string key = GetSubgraphKey();
    std::string path = cache_dir + "/" + key + ".plan";
    DLOG(INFO) << "Caching TensorRT engine to " << path;
    // Serialize engine to disk
    nvinfer1::IHostMemory* serialized_engine =
        trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].engine->serialize();
    SaveBinaryToFile(path, std::string(static_cast<const char*>(serialized_engine->data()),
                                       serialized_engine->size()));
    serialized_engine->destroy();
    // Serialize metadata
    std::ostringstream os;
    dmlc::JSONWriter writer(&os);
    writer.BeginObject();
    writer.WriteObjectKeyValue("inputs",
                               trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].inputs);
    writer.WriteObjectKeyValue(
        "outputs", trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].outputs);
    writer.EndObject();
    std::string meta_path = cache_dir + "/" + key + ".meta";
    SaveBinaryToFile(meta_path, os.str());
  }

  std::string GetSubgraphKey() {
    // Using this key will only allow a single model per TVM_TENSORRT_CACHE_DIR directory. We could
    // instead use a hash of graph_json and all weights to allow many models in the same directory,
    // but the cost of computing the hash is high.
    return symbol_name_ + (dmlc::GetEnv("TVM_TENSORRT_USE_FP16", false) ? "_fp16" : "_fp32");
  }

  /*! \brief Get the batch size when in implicit_batch mode. */
  int GetBatchSize() {
    if (!use_implicit_batch_) return -1;
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      if (nodes_[nid].GetOpType() == "input") {
        // Get batch size from first input.
        return nodes_[nid].GetOpShape()[0][0];
      }
    }
    return -1;
  }

  /*! \brief Map of function name to TRT engine if built already. */
  std::unordered_map<std::pair<std::string, int>, TensorRTEngineAndContext, PairHash>
      trt_engine_cache_;

  /*! \brief TensorRT logger. */
  TensorRTLogger logger_;

  /*! \brief Batch size that the engine is optimized for. */
  int batch_size_;

#else
  void Run() override {
    LOG(FATAL) << "TensorRT runtime is not enabled. "
               << "Please build with USE_TENSORRT_RUNTIME.";
  }

  void BuildEngine() {
    LOG(WARNING) << "TensorRT runtime is not enabled. "
                 << "Please build with USE_TENSORRT_RUNTIME.";
  }

  bool GetCachedEnginesFromDisk() { return false; }

  void CacheEngineToDisk() {}
#endif

  bool use_implicit_batch_;

  size_t max_workspace_size_;
};

runtime::Module TensorRTRuntimeCreate(const String& symbol_name, const String& graph_json,
                                      const Array<String>& const_names) {
  auto n = make_object<TensorRTRuntime>(symbol_name, graph_json, const_names);
  return runtime::Module(n);
}

TVM_REGISTER_GLOBAL("runtime.tensorrt_runtime_create").set_body_typed(TensorRTRuntimeCreate);

TVM_REGISTER_GLOBAL("runtime.module.loadbinary_tensorrt")
    .set_body_typed(JSONRuntimeBase::LoadFromBinary<TensorRTRuntime>);

}  // namespace contrib
}  // namespace runtime
}  // namespace tvm
<commit_msg>Free TensorRT engine and context (#7702)<commit_after>/*
 * 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.
 */

/*!
 * \file src/runtime/contrib/tensorrt/tensorrt_runtime.cc
 * \brief JSON runtime implementation for TensorRT.
 */

#include <dmlc/parameter.h>
#include <tvm/runtime/ndarray.h>
#include <tvm/runtime/registry.h>

#include <fstream>

#include "../../file_utils.h"
#include "../json/json_node.h"
#include "../json/json_runtime.h"

#ifdef TVM_GRAPH_RUNTIME_TENSORRT
#include "NvInfer.h"
#include "tensorrt_builder.h"
#endif

namespace tvm {
namespace runtime {
namespace contrib {

struct PairHash {
  template <class T1, class T2>
  std::size_t operator()(const std::pair<T1, T2>& pair) const {
    return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
  }
};

using namespace tvm::runtime::json;

class TensorRTRuntime : public JSONRuntimeBase {
 public:
  /*!
   * \brief The TensorRT runtime module. Deserialize the provided functions
   * on creation and store in the layer cache.
   *
   * \param symbol_name The name of the function.
   * \param graph_json serialized JSON representation of a sub-graph.
   * \param const_names The names of each constant in the sub-graph.
   */
  explicit TensorRTRuntime(const std::string& symbol_name, const std::string& graph_json,
                           const Array<String>& const_names)
      : JSONRuntimeBase(symbol_name, graph_json, const_names),
        use_implicit_batch_(true),
        max_workspace_size_(size_t(1) << 30) {}

  /*!
   * \brief The type key of the module.
   *
   * \return module type key.
   */
  const char* type_key() const override { return "tensorrt"; }

  /*!
   * \brief Initialize runtime. Create TensorRT layer from JSON
   * representation.
   *
   * \param consts The constant params from compiled model.
   */
  void Init(const Array<NDArray>& consts) override {
    ICHECK_EQ(consts.size(), const_idx_.size())
        << "The number of input constants must match the number of required.";
    LoadGlobalAttributes();
    if (GetCachedEnginesFromDisk()) return;
    SetupConstants(consts);
  }

  void LoadGlobalAttributes() {
    // These settings are global to the entire subgraph. Codegen will add them as attributes to all
    // op nodes. Read from first one.
    for (size_t i = 0; i < nodes_.size(); ++i) {
      if (nodes_[i].HasAttr("use_implicit_batch") && nodes_[i].HasAttr("max_workspace_size")) {
        use_implicit_batch_ =
            std::stoi(nodes_[i].GetAttr<std::vector<std::string>>("use_implicit_batch")[0]);
        // Allow max_workspace_size to be overridden at runtime.
        size_t runtime_max_workspace_size =
            dmlc::GetEnv("TVM_TENSORRT_MAX_WORKSPACE_SIZE", size_t(0));
        if (runtime_max_workspace_size != 0) {
          max_workspace_size_ = runtime_max_workspace_size;
        } else {
          max_workspace_size_ =
              std::stoul(nodes_[i].GetAttr<std::vector<std::string>>("max_workspace_size")[0]);
        }
        return;
      }
    }
  }

#ifdef TVM_GRAPH_RUNTIME_TENSORRT
  /*! \brief Destroy engines and contexts. */
  ~TensorRTRuntime() {
    for (auto& it : trt_engine_cache_) {
      it.second.context->destroy();
      it.second.engine->destroy();
    }
  }

  /*! \brief Run inference using built engine. */
  void Run() override {
    BuildEngine();
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    if (batch_size_ == 0) return;
    auto& engine_and_context = trt_engine_cache_.at(std::make_pair(symbol_name_, batch_size_));
    auto engine = engine_and_context.engine;
    auto context = engine_and_context.context;
    auto& device_buffers = engine_and_context.device_buffers;
    std::vector<void*> bindings(engine->getNbBindings(), nullptr);
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      if (nodes_[nid].GetOpType() == "input") {
        for (size_t j = 0; j < nodes_[nid].GetOpShape().size(); ++j) {
          uint32_t eid = EntryID(nid, j);
          const std::string name = nodes_[nid].GetOpName() + "_" + std::to_string(j);
          int binding_index = engine->getBindingIndex(name.c_str());
          ICHECK_NE(binding_index, -1);
          if (data_entry_[eid]->ctx.device_type == kDLGPU) {
            bindings[binding_index] = data_entry_[eid]->data;
          } else {
            device_buffers[binding_index].CopyFrom(data_entry_[eid]);
            bindings[binding_index] = device_buffers[binding_index]->data;
          }
        }
      }
    }

    for (size_t i = 0; i < outputs_.size(); ++i) {
      uint32_t eid = EntryID(outputs_[i]);
      const std::string& name = engine_and_context.outputs[i];
      int binding_index = engine->getBindingIndex(name.c_str());
      ICHECK_NE(binding_index, -1);
      if (data_entry_[eid]->ctx.device_type == kDLGPU) {
        bindings[binding_index] = data_entry_[eid]->data;
      } else {
        bindings[binding_index] = device_buffers[binding_index]->data;
      }
    }

#if TRT_VERSION_GE(6, 0, 1)
    if (use_implicit_batch_) {
      ICHECK(context->execute(batch_size_, bindings.data())) << "Running TensorRT failed.";
    } else {
      ICHECK(context->executeV2(bindings.data())) << "Running TensorRT failed.";
    }
#else
    ICHECK(context->execute(batch_size_, bindings.data())) << "Running TensorRT failed.";
#endif

    // Copy outputs from GPU buffers if needed.
    for (size_t i = 0; i < outputs_.size(); ++i) {
      uint32_t eid = EntryID(outputs_[i]);
      const std::string& name = engine_and_context.outputs[i];
      int binding_index = engine->getBindingIndex(name.c_str());
      ICHECK_NE(binding_index, -1);
      if (data_entry_[eid]->ctx.device_type != kDLGPU) {
        device_buffers[binding_index].CopyTo(const_cast<DLTensor*>(data_entry_[eid]));
      }
    }
  }

 private:
  /*!
   * \brief Build TensorRT engine from JSON representation and cache it. If engine is already built,
   * do nothing.
   */
  void BuildEngine() {
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    if (trt_engine_cache_.count(std::make_pair(symbol_name_, batch_size_))) return;
    DLOG(INFO) << "Building new TensorRT engine for subgraph " << symbol_name_
               << " with batch size " << batch_size_;
    const bool use_fp16 = dmlc::GetEnv("TVM_TENSORRT_USE_FP16", false);
    TensorRTBuilder builder(&logger_, data_entry_, max_workspace_size_, use_implicit_batch_,
                            use_fp16, batch_size_);

    // Add inputs and constants.
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      const auto& node = nodes_[nid];
      std::string name = node.GetOpName();
      if (node.GetOpType() == "input") {
        builder.AddInput(nid, EntryID(nid, 0), node);
      } else {
        ICHECK_EQ(node.GetOpType(), "const");
        uint32_t eid = EntryID(nid, 0);
        builder.AddConstant(nid, data_entry_[eid]);
      }
    }

    // Add layers.
    for (size_t nid = 0; nid < nodes_.size(); ++nid) {
      const auto& node = nodes_[nid];
      if (node.GetOpType() != "kernel") continue;
      builder.AddLayer(nid, node);
    }

    // Add outputs.
    for (size_t i = 0; i < outputs_.size(); ++i) {
      builder.AddOutput(outputs_[i], EntryID(outputs_[i]));
    }

    // Build engine.
    trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)] = builder.BuildEngine();
    DLOG(INFO) << "Finished building TensorRT engine for subgraph " << symbol_name_
               << " with batch size " << batch_size_;
    CacheEngineToDisk();
  }

  /*! \brief If TVM_TENSORRT_CACHE_DIR is set, will check that directory for
   * already built TRT engines and load into trt_engine_cache_ so they don't
   * have to be built at first inference.
   */
  bool GetCachedEnginesFromDisk() {
    std::string cache_dir = dmlc::GetEnv("TVM_TENSORRT_CACHE_DIR", std::string(""));
    if (cache_dir.empty()) return false;
    std::string key = GetSubgraphKey();
    std::string path = cache_dir + "/" + key + ".plan";
    // Check if engine is in the cache.
    std::ifstream infile(path, std::ios::binary);
    if (!infile.good()) return false;
    DLOG(INFO) << "Loading cached TensorRT engine from " << path;
    infile.close();
    std::string serialized_engine;
    LoadBinaryFromFile(path, &serialized_engine);
    // Deserialize engine
    nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger_);
    TensorRTEngineAndContext engine_and_context;
    engine_and_context.engine =
        runtime->deserializeCudaEngine(&serialized_engine[0], serialized_engine.size(), nullptr);
    engine_and_context.context = engine_and_context.engine->createExecutionContext();
    // Load metadata
    std::string meta_path = cache_dir + "/" + key + ".meta";
    std::string serialized_meta;
    LoadBinaryFromFile(meta_path, &serialized_meta);
    std::istringstream is(serialized_meta);
    dmlc::JSONReader reader(&is);
    dmlc::JSONObjectReadHelper helper;
    helper.DeclareField("inputs", &engine_and_context.inputs);
    helper.DeclareField("outputs", &engine_and_context.outputs);
    helper.ReadAllFields(&reader);
    const int batch_size = 1;
    trt_engine_cache_[std::make_pair(symbol_name_, batch_size)] = engine_and_context;
    return true;
  }

  /*! \brief If TVM_TENSORRT_CACHE_DIR is set, will save the engine to that
   * directory so it can be loaded later.
   */
  void CacheEngineToDisk() {
    batch_size_ = data_entry_[input_var_eid_[0]]->shape[0];
    std::string cache_dir = dmlc::GetEnv("TVM_TENSORRT_CACHE_DIR", std::string(""));
    if (cache_dir.empty()) return;
    std::string key = GetSubgraphKey();
    std::string path = cache_dir + "/" + key + ".plan";
    DLOG(INFO) << "Caching TensorRT engine to " << path;
    // Serialize engine to disk
    nvinfer1::IHostMemory* serialized_engine =
        trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].engine->serialize();
    SaveBinaryToFile(path, std::string(static_cast<const char*>(serialized_engine->data()),
                                       serialized_engine->size()));
    serialized_engine->destroy();
    // Serialize metadata
    std::ostringstream os;
    dmlc::JSONWriter writer(&os);
    writer.BeginObject();
    writer.WriteObjectKeyValue("inputs",
                               trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].inputs);
    writer.WriteObjectKeyValue(
        "outputs", trt_engine_cache_[std::make_pair(symbol_name_, batch_size_)].outputs);
    writer.EndObject();
    std::string meta_path = cache_dir + "/" + key + ".meta";
    SaveBinaryToFile(meta_path, os.str());
  }

  std::string GetSubgraphKey() {
    // Using this key will only allow a single model per TVM_TENSORRT_CACHE_DIR directory. We could
    // instead use a hash of graph_json and all weights to allow many models in the same directory,
    // but the cost of computing the hash is high.
    return symbol_name_ + (dmlc::GetEnv("TVM_TENSORRT_USE_FP16", false) ? "_fp16" : "_fp32");
  }

  /*! \brief Get the batch size when in implicit_batch mode. */
  int GetBatchSize() {
    if (!use_implicit_batch_) return -1;
    for (size_t i = 0; i < input_nodes_.size(); ++i) {
      auto nid = input_nodes_[i];
      if (nodes_[nid].GetOpType() == "input") {
        // Get batch size from first input.
        return nodes_[nid].GetOpShape()[0][0];
      }
    }
    return -1;
  }

  /*! \brief Map of function name to TRT engine if built already. */
  std::unordered_map<std::pair<std::string, int>, TensorRTEngineAndContext, PairHash>
      trt_engine_cache_;

  /*! \brief TensorRT logger. */
  TensorRTLogger logger_;

  /*! \brief Batch size that the engine is optimized for. */
  int batch_size_;

#else
  void Run() override {
    LOG(FATAL) << "TensorRT runtime is not enabled. "
               << "Please build with USE_TENSORRT_RUNTIME.";
  }

  void BuildEngine() {
    LOG(WARNING) << "TensorRT runtime is not enabled. "
                 << "Please build with USE_TENSORRT_RUNTIME.";
  }

  bool GetCachedEnginesFromDisk() { return false; }

  void CacheEngineToDisk() {}
#endif

  bool use_implicit_batch_;

  size_t max_workspace_size_;
};

runtime::Module TensorRTRuntimeCreate(const String& symbol_name, const String& graph_json,
                                      const Array<String>& const_names) {
  auto n = make_object<TensorRTRuntime>(symbol_name, graph_json, const_names);
  return runtime::Module(n);
}

TVM_REGISTER_GLOBAL("runtime.tensorrt_runtime_create").set_body_typed(TensorRTRuntimeCreate);

TVM_REGISTER_GLOBAL("runtime.module.loadbinary_tensorrt")
    .set_body_typed(JSONRuntimeBase::LoadFromBinary<TensorRTRuntime>);

}  // namespace contrib
}  // namespace runtime
}  // namespace tvm
<|endoftext|>


<commit_before>/*********************************************************/
//SISTEMA DE ENSAYO DE CAJA Y CUBOS AUTOMATIZADO (ABBT)//
	    //Luis Ángel García Astudillo//
  //Grado en Ingeniería en Tecnologías Industriales//
         //Universidad Carlos III de Madrid//
/********************************************************/

#include "stdafx.h"
#include <strsafe.h>
#include "resource.h"
#include "ColorBasics.h"
#include <opencv2/opencv.hpp>

using namespace cv;

CColorBasics::CColorBasics() :

    m_fFreq(0),
    m_pKinectSensor(NULL),
    m_pColorFrameReader(NULL),
    m_pColorRGBX(NULL)
{
    LARGE_INTEGER qpf = {0};
    if (QueryPerformanceFrequency(&qpf)){
        m_fFreq = double(qpf.QuadPart);
    }

    // create heap storage for color pixel data in RGBX format
    m_pColorRGBX = new RGBQUAD[cColorWidth * cColorHeight];
}

CColorBasics::~CColorBasics(){

    SafeRelease(m_pColorFrameReader); // done with color frame reader

    if (m_pKinectSensor){ // close the Kinect Sensor

        m_pKinectSensor->Close();
    }

    SafeRelease(m_pKinectSensor);
}

void CColorBasics::update(Mat &m){

    if (!m_pColorFrameReader){
        return;
    }

    IColorFrame* pColorFrame = NULL;
    HRESULT hr = m_pColorFrameReader->AcquireLatestFrame(&pColorFrame);

    if (SUCCEEDED(hr)){

		imageCaptured = 1;
        INT64 nTime = 0;
        IFrameDescription* pFrameDescription = NULL;
        int nWidth = 0;
        int nHeight = 0;
        ColorImageFormat imageFormat = ColorImageFormat_None;
        UINT nBufferSize = 0;
        RGBQUAD *pBuffer = NULL;

        hr = pColorFrame->get_RelativeTime(&nTime);

        if (SUCCEEDED(hr)){
            hr = pColorFrame->get_FrameDescription(&pFrameDescription);
        }

        if (SUCCEEDED(hr)){
            hr = pFrameDescription->get_Width(&nWidth);
        }

        if (SUCCEEDED(hr)){
            hr = pFrameDescription->get_Height(&nHeight);
        }

        if (SUCCEEDED(hr)){
            hr = pColorFrame->get_RawColorImageFormat(&imageFormat);
        }

        if (SUCCEEDED(hr)){
            if (imageFormat == ColorImageFormat_Bgra){

                hr = pColorFrame->AccessRawUnderlyingBuffer(&nBufferSize, reinterpret_cast<BYTE**>(&m.data));
            }
            else if (m_pColorRGBX){

                pBuffer = m_pColorRGBX;
                nBufferSize = cColorWidth * cColorHeight * sizeof(RGBQUAD);
                hr = pColorFrame->CopyConvertedFrameDataToArray(nBufferSize, reinterpret_cast<BYTE*>(m.data), ColorImageFormat_Bgra);
            }
            else{
                hr = E_FAIL;
            }
        }

        SafeRelease(pFrameDescription);
    }
	else { imageCaptured = 0; }

	SafeRelease(pColorFrame);

}

HRESULT CColorBasics::initializeDefaultSensor(){

    HRESULT hr;
    hr = GetDefaultKinectSensor(&m_pKinectSensor);
    if (FAILED(hr)){
        return hr;
    }

    if (m_pKinectSensor){
        // Initialize the Kinect and get the color reader
        IColorFrameSource* pColorFrameSource = NULL;

        hr = m_pKinectSensor->Open();

        if (SUCCEEDED(hr)){
            hr = m_pKinectSensor->get_ColorFrameSource(&pColorFrameSource);
        }

        if (SUCCEEDED(hr)){
            hr = pColorFrameSource->OpenReader(&m_pColorFrameReader);
        }

        SafeRelease(pColorFrameSource);
    }
    return hr;
}
<commit_msg>Delete ColorBasics.cpp<commit_after><|endoftext|>


<commit_before>#include "window.h"

#include "atom.h"

#include <X11/Xlib.h>

namespace x11
{
  unsigned int window::input_only = InputOnly;
  unsigned int window::input_output = InputOutput;
  int window::copy_from_parent = CopyFromParent;
  int window::raise_lowest = RaiseLowest;
  int window::lower_highest = LowerHighest;
  int window::prop_mode_replace = PropModeReplace;
  int window::prop_mode_prepend = PropModePrepend;
  int window::prop_mode_append = PropModeAppend;
  int window::is_unmapped = IsUnmapped;
  int window::is_unviewable = IsUnviewable;
  int window::is_viewable = IsViewable;

  void window::create_window( display d, window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int win_class, void* visual, long unsigned int valuemask, void* attributes )
  {
    data = XCreateWindow( static_cast<Display*>( d.get() ), parent.data, x, y, width, height, border_width, depth, win_class, static_cast<Visual*>( visual ), valuemask, static_cast<XSetWindowAttributes*>( attributes ) );
  }

  void window::create_simple_window( display d, window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, long unsigned int border, long unsigned int background )
  {
    data = XCreateSimpleWindow( static_cast<Display*>( d.get() ), parent.data, x, y, width, height, border_width, border, background );
  }

  void window::destroy_window( display d )
  {
    XDestroyWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::destroy_subwindows( display d )
  {
    XDestroySubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::map_window( display d )
  {
    XMapWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::map_raised( display d )
  {
    XMapRaised( static_cast<Display*>( d.get() ), data );
  }

  void window::map_subwindows( display d )
  {
    XMapSubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::unmap_window( display d )
  {
    XUnmapWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::unmap_subwindows( display d )
  {
    XUnmapSubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::configure_window( display d, unsigned int value_mask, void* values )
  {
    XConfigureWindow( static_cast<Display*>( d.get() ), data, value_mask, static_cast<XWindowChanges*>( values ) );
  }

  void window::move_window( display d, int x, int y )
  {
    XMoveWindow( static_cast<Display*>( d.get() ), data, x, y );
  }

  void window::resize_window( display d, unsigned int width, unsigned int height )
  {
    XResizeWindow( static_cast<Display*>( d.get() ), data, width, height );
  }

  void window::move_resize_window( display d, int x, int y, unsigned int width, unsigned int height )
  {
    XMoveResizeWindow( static_cast<Display*>( d.get() ), data, x, y, width, height );
  }

  void window::set_window_border_width( display d, unsigned int width )
  {
    XSetWindowBorderWidth( static_cast<Display*>( d.get() ), data, width );
  }

  void window::raise_window( display d )
  {
    XRaiseWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::lower_window( display d )
  {
    XLowerWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::circulate_subwindows( display d, int direction )
  {
    XCirculateSubwindows( static_cast<Display*>( d.get() ), data, direction );
  }

  void window::circulate_subwindows_up( display d )
  {
    XCirculateSubwindowsUp( static_cast<Display*>( d.get() ), data );
  }

  void window::circulate_subwindows_down( display d )
  {
    XCirculateSubwindowsDown( static_cast<Display*>( d.get() ), data );
  }

  void window::restack_windows( display d, const std::vector< window >& windows )
  {
    XRestackWindows( static_cast<Display*>( d.get() ), ( Window* )&windows[0], windows.size() );
  }

  void window::change_window_attributes( display d, long unsigned int valuemask, void* attributes )
  {
    XChangeWindowAttributes( static_cast<Display*>( d.get() ), data, valuemask, static_cast<XSetWindowAttributes*>( attributes ) );
  }

  void window::set_window_background( display d, long unsigned int background_pixel )
  {
    XSetWindowBackground( static_cast<Display*>( d.get() ), data, background_pixel );
  }

  void window::set_window_background_pixmap( display d, long unsigned int pixmap )
  {
    XSetWindowBackgroundPixmap( static_cast<Display*>( d.get() ), data, pixmap );
  }

  void window::set_window_border( display d, long unsigned int border_pixel )
  {
    XSetWindowBorder( static_cast<Display*>( d.get() ), data, border_pixel );
  }

  void window::set_window_border_pixmap( display d, long unsigned int border_pixmap )
  {
    XSetWindowBorderPixmap( static_cast<Display*>( d.get() ), data, border_pixmap );
  }

  void window::set_window_colormap( display d, long unsigned int colormap )
  {
    XSetWindowColormap( static_cast<Display*>( d.get() ), data, colormap );
  }

  void window::define_cursor( display d, long unsigned int cursor )
  {
    XDefineCursor( static_cast<Display*>( d.get() ), data, cursor );
  }

  void window::undefine_cursor( display d )
  {
    XUndefineCursor( static_cast<Display*>( d.get() ), data );
  }

  bool window::query_tree( display d, window& root, window& parent, std::vector< window >& children )
  {
    Window r;
    Window p;
    Window* ch = 0;
    unsigned int numc = 0;
    int ret = XQueryTree( static_cast<Display*>( d.get() ), data, &r, &p, &ch, &numc );
    root = r;
    parent = p;

    for( int c = 0; c < numc; ++c )
      children.push_back( ch[c] );

    XFree( ch );
    return ret;
  }

  bool window::get_window_attributes( display d, window_attributes& attributes )
  {
    XWindowAttributes wa;
    bool ret = XGetWindowAttributes( static_cast<Display*>( d.get() ), data, &wa );

    if( ret )
    {
      attributes = window_attributes( wa.x, wa.y, wa.width, wa.height,
                                      wa.border_width, wa.depth, wa.visual, wa.root, wa.c_class, wa.bit_gravity, wa.win_gravity,
                                      wa.backing_store, wa.backing_planes, wa.backing_pixel, wa.save_under, wa.colormap,
                                      wa.map_installed, wa.map_state, wa.all_event_masks, wa.your_event_mask, wa.do_not_propagate_mask,
                                      wa.override_redirect, wa.screen );
    }

    return ret;
  }

  bool window::get_geometry( display d, long unsigned int drawable, window& root, int& x, int& y, unsigned int& width, unsigned int& height, unsigned int& border_width, unsigned int& depth )
  {
    Window roott;
    int xx, yy;
    unsigned int widtht, heightt, border_widtht, deptht;
    int ret = XGetGeometry( static_cast<Display*>( d.get() ), drawable, &roott, &xx, &yy, &widtht, &heightt, &border_widtht, &deptht );
    root = roott;
    x = xx;
    y = yy;
    width = width;
    height = heightt;
    border_width = border_widtht;
    depth = deptht;
    return ret;
  }

  bool window::translate_coordinates( display d, window src, window dst, int src_x, int src_y, int& dst_x, int& dst_y, window& child )
  {
    int dest_x, dest_y;
    Window childt;
    int ret = XTranslateCoordinates( static_cast<Display*>( d.get() ), src.data, dst.data, src_x, src_y, &dest_x, &dest_y, &childt );
    dst_x = dest_x;
    dst_y = dest_y;
    child = childt;
    return ret;
  }

  bool window::query_pointer( display d, window& root, window& child, int& root_x, int& root_y, int& win_x, int& win_y, unsigned int& mask )
  {
    Window roott, childrent;
    int root_xt, root_yt, win_xt, win_yt;
    unsigned int maskt;
    int ret = XQueryPointer( static_cast<Display*>( d.get() ), data, &roott, &childrent, &root_xt, &root_yt, &win_xt, &win_yt, &maskt );
    root = roott;
    child = childrent;
    root_x = root_xt;
    root_y = root_yt;
    win_x = win_xt;
    win_y = win_yt;
    mask = maskt;
    return ret;
  }

  template< class t, int length >
  bool get_window_property( display d, window w, unsigned long prop_length, atom property_name, Atom property_type, long prop_offset, std::vector<t>& property )
  {
    Atom actual_type;
    int actual_format;
    unsigned long nitems, bytes_left_to_read;
    unsigned char* propertyarray;
    int ret = XGetWindowProperty( static_cast<Display*>( d.get() ), w.get(), property_name.get(), prop_offset, prop_length, false, property_type, &actual_type, &actual_format, &nitems, &bytes_left_to_read, &propertyarray );

    if( ret != Success )
    {
      XFree( propertyarray );
      return false;
    }

    if( actual_type == None )
    {
      //property does not exist
      XFree( propertyarray );
      return false;
    }

    if( actual_format != length )
    {
      //format does not match the supplied array
      XFree( propertyarray );
      return false;
    }

    for( int c = 0; c < nitems; ++c )
    {
      property.push_back( ( ( t* )( propertyarray + 4 * prop_offset ) )[c] );
    }

    XFree( propertyarray );

    if( bytes_left_to_read > 0 )
    {
      //need to read some more
      return get_window_property<t, length>( d, w, bytes_left_to_read, property_name, actual_type, prop_offset, property );
    }

    return true;
  }

  bool window::get_window_property_char( display d, atom property_name, long int prop_offset, std::vector< char >& property )
  {
    return get_window_property<char, 8>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  bool window::get_window_property_short( display d, atom property_name, long int prop_offset, std::vector< short int >& property )
  {
    return get_window_property<short, 16>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  bool window::get_window_property_long( display d, atom property_name, long int prop_offset, std::vector< long int >& property )
  {
    return get_window_property<long, 32>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  template< class t, int length >
  void change_property_helper( display d, window w, atom property, atom type, int mode, const std::vector<t>& data )
  {
    XChangeProperty( static_cast<Display*>( d.get() ), w.get(), property.get(), type.get(), length, mode, ( unsigned char* )&data[0], data.size() );
  }

  void window::change_property_char( display d, atom property, atom type, int mode, const std::vector< char >& data )
  {
    change_property_helper<char, 8>( d, *this, property, type, mode, data );
  }

  void window::change_property_short( display d, atom property, atom type, int mode, const std::vector< short int >& data )
  {
    change_property_helper<short, 16>( d, *this, property, type, mode, data );
  }

  void window::change_property_long( display d, atom property, atom type, int mode, const std::vector< long int >& data )
  {
    change_property_helper<long, 32>( d, *this, property, type, mode, data );
  }

  void window::list_properties( display d, std::vector< atom >& atoms )
  {
    int num;
    Atom* atomst = XListProperties( static_cast<Display*>( d.get() ), data, &num );

    for( int c = 0; c < num; ++c )
      atoms.push_back( atomst[c] );

    XFree( atomst );
  }

  void window::rotate_window_properties( display d, const std::vector< atom >& atoms, int npositions )
  {
    XRotateWindowProperties( static_cast<Display*>( d.get() ), data, ( Atom* )&atoms[0], atoms.size(), npositions );
  }

  void window::delete_property( display d, atom property )
  {
    XDeleteProperty( static_cast<Display*>( d.get() ), data, property.get() );
  }

  window window::get_selection_owner( display d, atom selection )
  {
    return XGetSelectionOwner( static_cast<Display*>( d.get() ), selection.get() );
  }

  void window::convert_selection( display d, atom selection, atom target, atom property, long unsigned int time )
  {
    XConvertSelection( static_cast<Display*>( d.get() ), selection.get(), target.get(), property.get(), data, time );
  }

  void window::set_selection_owner( display d, atom selection, long unsigned int time )
  {
    XSetSelectionOwner( static_cast<Display*>( d.get() ), selection.get(), data, time );
  }

  template< int fmt >
  bool send_event( display d, unsigned long data, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    XEvent ev = {0};
    ev.xclient.type = ClientMessage;
    ev.xclient.window = data;
    ev.xclient.message_type = type.get();
    ev.xclient.format = fmt;
    ev.xclient.data.l[0] = data0;
    ev.xclient.data.l[1] = data1;
    ev.xclient.data.l[2] = data2;
    ev.xclient.data.l[3] = data3;

    XSendEvent( static_cast<Display*>( d.get() ), data, false, NoEventMask, &ev );
    d.sync();
  }

  bool window::send_event_char( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    send_event<8>( d, data, type, propagate, data0, data1, data2, data3 );
  }

  bool window::send_event_short( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    send_event<16>( d, data, type, propagate, data0, data1, data2, data3 );
  }

  bool window::send_event_long( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    send_event<32>( d, data, type, propagate, data0, data1, data2, data3 );
  }
}
<commit_msg>fixed return values<commit_after>#include "window.h"

#include "atom.h"

#include <X11/Xlib.h>

namespace x11
{
  unsigned int window::input_only = InputOnly;
  unsigned int window::input_output = InputOutput;
  int window::copy_from_parent = CopyFromParent;
  int window::raise_lowest = RaiseLowest;
  int window::lower_highest = LowerHighest;
  int window::prop_mode_replace = PropModeReplace;
  int window::prop_mode_prepend = PropModePrepend;
  int window::prop_mode_append = PropModeAppend;
  int window::is_unmapped = IsUnmapped;
  int window::is_unviewable = IsUnviewable;
  int window::is_viewable = IsViewable;

  void window::create_window( display d, window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int win_class, void* visual, long unsigned int valuemask, void* attributes )
  {
    data = XCreateWindow( static_cast<Display*>( d.get() ), parent.data, x, y, width, height, border_width, depth, win_class, static_cast<Visual*>( visual ), valuemask, static_cast<XSetWindowAttributes*>( attributes ) );
  }

  void window::create_simple_window( display d, window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, long unsigned int border, long unsigned int background )
  {
    data = XCreateSimpleWindow( static_cast<Display*>( d.get() ), parent.data, x, y, width, height, border_width, border, background );
  }

  void window::destroy_window( display d )
  {
    XDestroyWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::destroy_subwindows( display d )
  {
    XDestroySubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::map_window( display d )
  {
    XMapWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::map_raised( display d )
  {
    XMapRaised( static_cast<Display*>( d.get() ), data );
  }

  void window::map_subwindows( display d )
  {
    XMapSubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::unmap_window( display d )
  {
    XUnmapWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::unmap_subwindows( display d )
  {
    XUnmapSubwindows( static_cast<Display*>( d.get() ), data );
  }

  void window::configure_window( display d, unsigned int value_mask, void* values )
  {
    XConfigureWindow( static_cast<Display*>( d.get() ), data, value_mask, static_cast<XWindowChanges*>( values ) );
  }

  void window::move_window( display d, int x, int y )
  {
    XMoveWindow( static_cast<Display*>( d.get() ), data, x, y );
  }

  void window::resize_window( display d, unsigned int width, unsigned int height )
  {
    XResizeWindow( static_cast<Display*>( d.get() ), data, width, height );
  }

  void window::move_resize_window( display d, int x, int y, unsigned int width, unsigned int height )
  {
    XMoveResizeWindow( static_cast<Display*>( d.get() ), data, x, y, width, height );
  }

  void window::set_window_border_width( display d, unsigned int width )
  {
    XSetWindowBorderWidth( static_cast<Display*>( d.get() ), data, width );
  }

  void window::raise_window( display d )
  {
    XRaiseWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::lower_window( display d )
  {
    XLowerWindow( static_cast<Display*>( d.get() ), data );
  }

  void window::circulate_subwindows( display d, int direction )
  {
    XCirculateSubwindows( static_cast<Display*>( d.get() ), data, direction );
  }

  void window::circulate_subwindows_up( display d )
  {
    XCirculateSubwindowsUp( static_cast<Display*>( d.get() ), data );
  }

  void window::circulate_subwindows_down( display d )
  {
    XCirculateSubwindowsDown( static_cast<Display*>( d.get() ), data );
  }

  void window::restack_windows( display d, const std::vector< window >& windows )
  {
    XRestackWindows( static_cast<Display*>( d.get() ), ( Window* )&windows[0], windows.size() );
  }

  void window::change_window_attributes( display d, long unsigned int valuemask, void* attributes )
  {
    XChangeWindowAttributes( static_cast<Display*>( d.get() ), data, valuemask, static_cast<XSetWindowAttributes*>( attributes ) );
  }

  void window::set_window_background( display d, long unsigned int background_pixel )
  {
    XSetWindowBackground( static_cast<Display*>( d.get() ), data, background_pixel );
  }

  void window::set_window_background_pixmap( display d, long unsigned int pixmap )
  {
    XSetWindowBackgroundPixmap( static_cast<Display*>( d.get() ), data, pixmap );
  }

  void window::set_window_border( display d, long unsigned int border_pixel )
  {
    XSetWindowBorder( static_cast<Display*>( d.get() ), data, border_pixel );
  }

  void window::set_window_border_pixmap( display d, long unsigned int border_pixmap )
  {
    XSetWindowBorderPixmap( static_cast<Display*>( d.get() ), data, border_pixmap );
  }

  void window::set_window_colormap( display d, long unsigned int colormap )
  {
    XSetWindowColormap( static_cast<Display*>( d.get() ), data, colormap );
  }

  void window::define_cursor( display d, long unsigned int cursor )
  {
    XDefineCursor( static_cast<Display*>( d.get() ), data, cursor );
  }

  void window::undefine_cursor( display d )
  {
    XUndefineCursor( static_cast<Display*>( d.get() ), data );
  }

  bool window::query_tree( display d, window& root, window& parent, std::vector< window >& children )
  {
    Window r;
    Window p;
    Window* ch = 0;
    unsigned int numc = 0;
    int ret = XQueryTree( static_cast<Display*>( d.get() ), data, &r, &p, &ch, &numc );
    root = r;
    parent = p;

    for( int c = 0; c < numc; ++c )
      children.push_back( ch[c] );

    XFree( ch );
    return ret;
  }

  bool window::get_window_attributes( display d, window_attributes& attributes )
  {
    XWindowAttributes wa;
    bool ret = XGetWindowAttributes( static_cast<Display*>( d.get() ), data, &wa );

    if( ret )
    {
      attributes = window_attributes( wa.x, wa.y, wa.width, wa.height,
                                      wa.border_width, wa.depth, wa.visual, wa.root, wa.c_class, wa.bit_gravity, wa.win_gravity,
                                      wa.backing_store, wa.backing_planes, wa.backing_pixel, wa.save_under, wa.colormap,
                                      wa.map_installed, wa.map_state, wa.all_event_masks, wa.your_event_mask, wa.do_not_propagate_mask,
                                      wa.override_redirect, wa.screen );
    }

    return ret;
  }

  bool window::get_geometry( display d, long unsigned int drawable, window& root, int& x, int& y, unsigned int& width, unsigned int& height, unsigned int& border_width, unsigned int& depth )
  {
    Window roott;
    int xx, yy;
    unsigned int widtht, heightt, border_widtht, deptht;
    int ret = XGetGeometry( static_cast<Display*>( d.get() ), drawable, &roott, &xx, &yy, &widtht, &heightt, &border_widtht, &deptht );
    root = roott;
    x = xx;
    y = yy;
    width = width;
    height = heightt;
    border_width = border_widtht;
    depth = deptht;
    return ret;
  }

  bool window::translate_coordinates( display d, window src, window dst, int src_x, int src_y, int& dst_x, int& dst_y, window& child )
  {
    int dest_x, dest_y;
    Window childt;
    int ret = XTranslateCoordinates( static_cast<Display*>( d.get() ), src.data, dst.data, src_x, src_y, &dest_x, &dest_y, &childt );
    dst_x = dest_x;
    dst_y = dest_y;
    child = childt;
    return ret;
  }

  bool window::query_pointer( display d, window& root, window& child, int& root_x, int& root_y, int& win_x, int& win_y, unsigned int& mask )
  {
    Window roott, childrent;
    int root_xt, root_yt, win_xt, win_yt;
    unsigned int maskt;
    int ret = XQueryPointer( static_cast<Display*>( d.get() ), data, &roott, &childrent, &root_xt, &root_yt, &win_xt, &win_yt, &maskt );
    root = roott;
    child = childrent;
    root_x = root_xt;
    root_y = root_yt;
    win_x = win_xt;
    win_y = win_yt;
    mask = maskt;
    return ret;
  }

  template< class t, int length >
  bool get_window_property( display d, window w, unsigned long prop_length, atom property_name, Atom property_type, long prop_offset, std::vector<t>& property )
  {
    Atom actual_type;
    int actual_format;
    unsigned long nitems, bytes_left_to_read;
    unsigned char* propertyarray;
    int ret = XGetWindowProperty( static_cast<Display*>( d.get() ), w.get(), property_name.get(), prop_offset, prop_length, false, property_type, &actual_type, &actual_format, &nitems, &bytes_left_to_read, &propertyarray );

    if( ret != Success )
    {
      XFree( propertyarray );
      return false;
    }

    if( actual_type == None )
    {
      //property does not exist
      XFree( propertyarray );
      return false;
    }

    if( actual_format != length )
    {
      //format does not match the supplied array
      XFree( propertyarray );
      return false;
    }

    for( int c = 0; c < nitems; ++c )
    {
      property.push_back( ( ( t* )( propertyarray + 4 * prop_offset ) )[c] );
    }

    XFree( propertyarray );

    if( bytes_left_to_read > 0 )
    {
      //need to read some more
      return get_window_property<t, length>( d, w, bytes_left_to_read, property_name, actual_type, prop_offset, property );
    }

    return true;
  }

  bool window::get_window_property_char( display d, atom property_name, long int prop_offset, std::vector< char >& property )
  {
    return get_window_property<char, 8>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  bool window::get_window_property_short( display d, atom property_name, long int prop_offset, std::vector< short int >& property )
  {
    return get_window_property<short, 16>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  bool window::get_window_property_long( display d, atom property_name, long int prop_offset, std::vector< long int >& property )
  {
    return get_window_property<long, 32>( d, *this, 0, property_name, AnyPropertyType, prop_offset, property );
  }

  template< class t, int length >
  void change_property_helper( display d, window w, atom property, atom type, int mode, const std::vector<t>& data )
  {
    XChangeProperty( static_cast<Display*>( d.get() ), w.get(), property.get(), type.get(), length, mode, ( unsigned char* )&data[0], data.size() );
  }

  void window::change_property_char( display d, atom property, atom type, int mode, const std::vector< char >& data )
  {
    change_property_helper<char, 8>( d, *this, property, type, mode, data );
  }

  void window::change_property_short( display d, atom property, atom type, int mode, const std::vector< short int >& data )
  {
    change_property_helper<short, 16>( d, *this, property, type, mode, data );
  }

  void window::change_property_long( display d, atom property, atom type, int mode, const std::vector< long int >& data )
  {
    change_property_helper<long, 32>( d, *this, property, type, mode, data );
  }

  void window::list_properties( display d, std::vector< atom >& atoms )
  {
    int num;
    Atom* atomst = XListProperties( static_cast<Display*>( d.get() ), data, &num );

    for( int c = 0; c < num; ++c )
      atoms.push_back( atomst[c] );

    XFree( atomst );
  }

  void window::rotate_window_properties( display d, const std::vector< atom >& atoms, int npositions )
  {
    XRotateWindowProperties( static_cast<Display*>( d.get() ), data, ( Atom* )&atoms[0], atoms.size(), npositions );
  }

  void window::delete_property( display d, atom property )
  {
    XDeleteProperty( static_cast<Display*>( d.get() ), data, property.get() );
  }

  window window::get_selection_owner( display d, atom selection )
  {
    return XGetSelectionOwner( static_cast<Display*>( d.get() ), selection.get() );
  }

  void window::convert_selection( display d, atom selection, atom target, atom property, long unsigned int time )
  {
    XConvertSelection( static_cast<Display*>( d.get() ), selection.get(), target.get(), property.get(), data, time );
  }

  void window::set_selection_owner( display d, atom selection, long unsigned int time )
  {
    XSetSelectionOwner( static_cast<Display*>( d.get() ), selection.get(), data, time );
  }

  template< int fmt >
  bool send_event( display d, unsigned long data, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    XEvent ev = {0};
    ev.xclient.type = ClientMessage;
    ev.xclient.window = data;
    ev.xclient.message_type = type.get();
    ev.xclient.format = fmt;
    ev.xclient.data.l[0] = data0;
    ev.xclient.data.l[1] = data1;
    ev.xclient.data.l[2] = data2;
    ev.xclient.data.l[3] = data3;

    bool ret = XSendEvent( static_cast<Display*>( d.get() ), data, false, NoEventMask, &ev ) == Success;
    d.sync();

    return ret;
  }

  bool window::send_event_char( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    return send_event<8>( d, data, type, propagate, data0, data1, data2, data3 );
  }

  bool window::send_event_short( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    return send_event<16>( d, data, type, propagate, data0, data1, data2, data3 );
  }

  bool window::send_event_long( display d, atom type, bool propagate, long int data0, long int data1, long int data2, long int data3 )
  {
    return send_event<32>( d, data, type, propagate, data0, data1, data2, data3 );
  }
}
<|endoftext|>


<commit_before>#include "dns_communicator_factory.h"
#include "../../connector.h"
#include "../../../../../../../../usr/include/c++/6/chrono"
#include "../../../../../../../../usr/include/boost/system/error_code.hpp"

#include <chrono>

namespace network
{

dns_connector_factory::dns_connector_factory(boost::asio::io_service& io, std::chrono::milliseconds connector_timeout)
	: io{io}
	, conn_timeout{connector_timeout}
	, dead{std::make_shared<bool>(false)}
{}

dns_connector_factory::~dns_connector_factory()
{
	*dead = true;
}

void dns_connector_factory::get_connector(const std::string& address, uint16_t port, bool tls,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	if ( stopping ) return error_cb(1);

	dns_resolver(address, port, tls, std::move(connector_cb), std::move(error_cb));
}

void dns_connector_factory::dns_resolver(const std::string& address, uint16_t port, bool tls,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	std::shared_ptr<boost::asio::ip::tcp::resolver> r = std::make_shared<boost::asio::ip::tcp::resolver>(io);
	if(!port)
		port = tls ? 443 : 80;

	LOGTRACE("resolving ", address, "with port ", port);
	boost::asio::ip::tcp::resolver::query q( address,  std::to_string(port) );
	auto resolve_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	resolve_timer->expires_from_now(boost::posix_time::milliseconds(resolve_timeout));
	resolve_timer->async_wait([r, resolve_timer](const boost::system::error_code &ec)
	{
		if ( ! ec ) r->cancel();
	});
	auto begin = std::chrono::high_resolution_clock::now();
	r->async_resolve(q,
		[this, begin, r, tls, connector_cb = std::move(connector_cb), error_cb = std::move(error_cb), resolve_timer, dead=dead]
		(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator iterator)
		{
			if(*dead)
				return;
			resolve_timer->cancel();
			if(ec || iterator == boost::asio::ip::tcp::resolver::iterator())
			{
				LOGERROR(ec.message());
				return error_cb(3);
			}
			/** No error: go on connecting */
			LOGTRACE( "tls is: ", tls );
			if ( tls )
			{
				return endpoint_connect(std::move(iterator),
					std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>
						(io, ctx ),
							std::move(connector_cb), std::move(error_cb));
			}
			endpoint_connect(std::move(iterator),
					std::make_shared<boost::asio::ip::tcp::socket>
						(io),
							std::move(connector_cb), std::move(error_cb));
		});
}

void dns_connector_factory::endpoint_connect(boost::asio::ip::tcp::resolver::iterator it,
	std::shared_ptr<boost::asio::ip::tcp::socket> socket, connector_callback_t connector_cb, error_callback_t error_cb)
{

	if(it == boost::asio::ip::tcp::resolver::iterator() || stopping) //finished
		return error_cb(3);
	auto&& endpoint = *it;
	auto connect_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	connect_timer->expires_from_now(boost::posix_time::milliseconds(connect_timeout));
	connect_timer->async_wait([socket, connect_timer, error_cb](const boost::system::error_code &ec)
	{
		if(!ec)
		{
			socket->cancel();
			error_cb(3);
		}
	});
	++it;
	socket->async_connect(endpoint,
		[this, it = std::move(it), socket, connector_cb = std::move(connector_cb),
			error_cb = std::move(error_cb), connect_timer, dead=dead]
		(const boost::system::error_code &ec)
		{
			if(*dead)
				return;
			connect_timer->cancel();
			if ( ec)
			{
				if(ec != boost::system::errc::operation_canceled) {
						endpoint_connect(std::move(it), std::move(socket), std::move(connector_cb), std::move(error_cb));
				}
				return;
			}

			auto connector = std::make_shared<server::connector<server::tcp_socket>>(std::move(socket));
			connector->set_timeout(conn_timeout);
			connector_cb(std::move(connector), http::proto_version::HTTP11); // TODO: we are forcing http clear to http1.1
		});
}

http::proto_version dns_connector_factory::chose_protocol(std::shared_ptr<dns_connector_factory::ssl_socket_t> stream)
{
	const unsigned char* proto{nullptr};
	unsigned int len{0};
	const SSL *ssl_handle = stream->native_handle();

	//ALPN
	SSL_get0_alpn_selected(ssl_handle, &proto, &len);
	if( !len )
		//NPN
		SSL_get0_next_proto_negotiated(ssl_handle, &proto, &len);

	http::proto_version v = http::proto_version::HTTP10;
	if(len >= 2 && proto[0] == 'h' && proto[1] == '2')
		v = http::proto_version::HTTP20;
	else if(len == 8 && memcmp(proto, "http/1.1", 8) == 0)
		v = http::proto_version::HTTP11;

	return v;
}

void dns_connector_factory::endpoint_connect(boost::asio::ip::tcp::resolver::iterator it,
	std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> stream,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	if ( it == boost::asio::ip::tcp::resolver::iterator() || stopping ) //finished
		return error_cb(3);
	stream->set_verify_mode( boost::asio::ssl::verify_none );
	auto connect_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	connect_timer->expires_from_now(boost::posix_time::milliseconds(connect_timeout));
	connect_timer->async_wait([stream, connect_timer, error_cb](const boost::system::error_code &ec)
	{
		if ( !ec ) //stream->cancel();
		{
			boost::system::error_code sec;
			stream->shutdown( sec );
			stream->lowest_layer().cancel(sec);
			error_cb(3);
		}
	});
	boost::asio::async_connect( stream->lowest_layer(), it, [ this, begin, stream, connector_cb = std::move(connector_cb),
		error_cb = std::move(error_cb), connect_timer, dead = dead ]( const boost::system::error_code &ec,
			boost::asio::ip::tcp::resolver::iterator it )
	{

		if(*dead)
			return;

		if ( ec )
		{
			LOGERROR(ec.message());
			//++it ?
			if(ec != boost::system::errc::operation_canceled)
				endpoint_connect(std::move(it), std::move(stream), std::move(connector_cb), std::move(error_cb));
			return;
		}
		stream->async_handshake( boost::asio::ssl::stream_base::client,
			[ this, stream, connector_cb = std::move(connector_cb), error_cb = std::move(error_cb), connect_timer ]
				( const boost::system::error_code &ec )
				{
					connect_timer->cancel();
					if ( ec )
					{
						LOGERROR( ec.message() );
						return;
					}

					http::proto_version v = chose_protocol(stream);

					auto connector = std::make_shared<server::connector<server::ssl_socket>>(std::move(stream));
					connector->set_timeout(conn_timeout);
					connector_cb(std::move(connector), v);
				});
	});
}

namespace
{
static const std::string NGHTTP2_H2_ALPN = "\x2h2";
static const std::string NGHTTP2_H2_16_ALPN = "\x5h2-16";
static const std::string NGHTTP2_H2_14_ALPN = "\x5h2-14";
static const std::string HTTP1_1_ALPN = "\x8http/1.1";
static const std::string HTTP1_0_ALPN = "\x8http/1.0";

bool select_proto(const unsigned char **out, unsigned char *outlen,
				  const unsigned char *in, unsigned int inlen,
				  const std::string &key) {
  for (auto p = in, end = in + inlen; p + key.size() <= end; p += *p + 1) {
	if (std::equal(std::begin(key), std::end(key), p)) {
	  *out = p + 1;
	  *outlen = *p;
	  return true;
	}
  }
  return false;
}

bool select_h2(const unsigned char **out, unsigned char *outlen,
			   const unsigned char *in, unsigned int inlen)
{
  return select_proto(out, outlen, in, inlen, NGHTTP2_H2_ALPN) ||
		 select_proto(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN) ||
		  select_proto(out, outlen, in, inlen, NGHTTP2_H2_14_ALPN);
}

bool select_h1(const unsigned char **out, unsigned char *outlen,
			   const unsigned char *in, unsigned int inlen)
{
  return select_proto(out, outlen, in, inlen, HTTP1_1_ALPN) ||
		 select_proto(out, outlen, in, inlen, HTTP1_0_ALPN);
}

int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
								unsigned char *outlen, const unsigned char *in,
								unsigned int inlen, void *arg)
{
	if (!select_h2(const_cast<const unsigned char **>(out), outlen, in, inlen) &&
			!select_h1(const_cast<const unsigned char **>(out), outlen, in, inlen))
	{
		return SSL_TLSEXT_ERR_NOACK;
	}
	return SSL_TLSEXT_ERR_OK;
}

const std::vector<unsigned char>& get_default_alpn()
{
  static auto res = std::vector<unsigned char>(NGHTTP2_H2_ALPN.size() +
										NGHTTP2_H2_16_ALPN.size() +
										NGHTTP2_H2_14_ALPN.size() +
										HTTP1_1_ALPN.size() +
										HTTP1_0_ALPN.size());
  static bool initialized = false;
  if(!initialized)
  {
	  initialized = true;
	  auto p = std::begin(res);
	  p = std::copy_n(std::begin(NGHTTP2_H2_ALPN), NGHTTP2_H2_ALPN.size(), p);
	  p = std::copy_n(std::begin(NGHTTP2_H2_16_ALPN), NGHTTP2_H2_16_ALPN.size(), p);
	  p = std::copy_n(std::begin(NGHTTP2_H2_14_ALPN), NGHTTP2_H2_14_ALPN.size(), p);
	  p = std::copy_n(std::begin(HTTP1_1_ALPN), HTTP1_1_ALPN.size(), p);
	  p = std::copy_n(std::begin(HTTP1_0_ALPN), HTTP1_0_ALPN.size(), p);
  }

  return res;
}

} // unnamed namespace

boost::asio::ssl::context dns_connector_factory::init_ssl_ctx()
{
	boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
	// enable NPN for http2
	auto ctx_h = ctx.native_handle();
	SSL_CTX_set_next_proto_select_cb(ctx_h, client_select_next_proto_cb, nullptr);
	// enable ALPN for http2
	SSL_CTX_set_alpn_protos(ctx_h, get_default_alpn().data(), get_default_alpn().size());
	return ctx;
}

thread_local boost::asio::ssl::context dns_connector_factory::ctx{dns_connector_factory::init_ssl_ctx()};

}
<commit_msg>minor fix: removed undefined variable from lambda capture list<commit_after>#include "dns_communicator_factory.h"
#include "../../connector.h"
#include "../../../../../../../../usr/include/c++/6/chrono"
#include "../../../../../../../../usr/include/boost/system/error_code.hpp"

#include <chrono>

namespace network
{

dns_connector_factory::dns_connector_factory(boost::asio::io_service& io, std::chrono::milliseconds connector_timeout)
	: io{io}
	, conn_timeout{connector_timeout}
	, dead{std::make_shared<bool>(false)}
{}

dns_connector_factory::~dns_connector_factory()
{
	*dead = true;
}

void dns_connector_factory::get_connector(const std::string& address, uint16_t port, bool tls,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	if ( stopping ) return error_cb(1);

	dns_resolver(address, port, tls, std::move(connector_cb), std::move(error_cb));
}

void dns_connector_factory::dns_resolver(const std::string& address, uint16_t port, bool tls,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	std::shared_ptr<boost::asio::ip::tcp::resolver> r = std::make_shared<boost::asio::ip::tcp::resolver>(io);
	if(!port)
		port = tls ? 443 : 80;

	LOGTRACE("resolving ", address, "with port ", port);
	boost::asio::ip::tcp::resolver::query q( address,  std::to_string(port) );
	auto resolve_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	resolve_timer->expires_from_now(boost::posix_time::milliseconds(resolve_timeout));
	resolve_timer->async_wait([r, resolve_timer](const boost::system::error_code &ec)
	{
		if ( ! ec ) r->cancel();
	});
	auto begin = std::chrono::high_resolution_clock::now();
	r->async_resolve(q,
		[this, begin, r, tls, connector_cb = std::move(connector_cb), error_cb = std::move(error_cb), resolve_timer, dead=dead]
		(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator iterator)
		{
			if(*dead)
				return;
			resolve_timer->cancel();
			if(ec || iterator == boost::asio::ip::tcp::resolver::iterator())
			{
				LOGERROR(ec.message());
				return error_cb(3);
			}
			/** No error: go on connecting */
			LOGTRACE( "tls is: ", tls );
			if ( tls )
			{
				return endpoint_connect(std::move(iterator),
					std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>
						(io, ctx ),
							std::move(connector_cb), std::move(error_cb));
			}
			endpoint_connect(std::move(iterator),
					std::make_shared<boost::asio::ip::tcp::socket>
						(io),
							std::move(connector_cb), std::move(error_cb));
		});
}

void dns_connector_factory::endpoint_connect(boost::asio::ip::tcp::resolver::iterator it,
	std::shared_ptr<boost::asio::ip::tcp::socket> socket, connector_callback_t connector_cb, error_callback_t error_cb)
{

	if(it == boost::asio::ip::tcp::resolver::iterator() || stopping) //finished
		return error_cb(3);
	auto&& endpoint = *it;
	auto connect_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	connect_timer->expires_from_now(boost::posix_time::milliseconds(connect_timeout));
	connect_timer->async_wait([socket, connect_timer, error_cb](const boost::system::error_code &ec)
	{
		if(!ec)
		{
			socket->cancel();
			error_cb(3);
		}
	});
	++it;
	socket->async_connect(endpoint,
		[this, it = std::move(it), socket, connector_cb = std::move(connector_cb),
			error_cb = std::move(error_cb), connect_timer, dead=dead]
		(const boost::system::error_code &ec)
		{
			if(*dead)
				return;
			connect_timer->cancel();
			if ( ec)
			{
				if(ec != boost::system::errc::operation_canceled) {
						endpoint_connect(std::move(it), std::move(socket), std::move(connector_cb), std::move(error_cb));
				}
				return;
			}

			auto connector = std::make_shared<server::connector<server::tcp_socket>>(std::move(socket));
			connector->set_timeout(conn_timeout);
			connector_cb(std::move(connector), http::proto_version::HTTP11); // TODO: we are forcing http clear to http1.1
		});
}

http::proto_version dns_connector_factory::chose_protocol(std::shared_ptr<dns_connector_factory::ssl_socket_t> stream)
{
	const unsigned char* proto{nullptr};
	unsigned int len{0};
	const SSL *ssl_handle = stream->native_handle();

	//ALPN
	SSL_get0_alpn_selected(ssl_handle, &proto, &len);
	if( !len )
		//NPN
		SSL_get0_next_proto_negotiated(ssl_handle, &proto, &len);

	http::proto_version v = http::proto_version::HTTP10;
	if(len >= 2 && proto[0] == 'h' && proto[1] == '2')
		v = http::proto_version::HTTP20;
	else if(len == 8 && memcmp(proto, "http/1.1", 8) == 0)
		v = http::proto_version::HTTP11;

	return v;
}

void dns_connector_factory::endpoint_connect(boost::asio::ip::tcp::resolver::iterator it,
	std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> stream,
	connector_callback_t connector_cb, error_callback_t error_cb)
{
	if ( it == boost::asio::ip::tcp::resolver::iterator() || stopping ) //finished
		return error_cb(3);
	stream->set_verify_mode( boost::asio::ssl::verify_none );
	auto connect_timer =
		std::make_shared<boost::asio::deadline_timer>(io);
	connect_timer->expires_from_now(boost::posix_time::milliseconds(connect_timeout));
	connect_timer->async_wait([stream, connect_timer, error_cb](const boost::system::error_code &ec)
	{
		if ( !ec ) //stream->cancel();
		{
			boost::system::error_code sec;
			stream->shutdown( sec );
			stream->lowest_layer().cancel(sec);
			error_cb(3);
		}
	});
	boost::asio::async_connect( stream->lowest_layer(), it, [ this, stream, connector_cb = std::move(connector_cb),
		error_cb = std::move(error_cb), connect_timer, dead = dead ]( const boost::system::error_code &ec,
			boost::asio::ip::tcp::resolver::iterator it )
	{

		if(*dead)
			return;

		if ( ec )
		{
			LOGERROR(ec.message());
			//++it ?
			if(ec != boost::system::errc::operation_canceled)
				endpoint_connect(std::move(it), std::move(stream), std::move(connector_cb), std::move(error_cb));
			return;
		}
		stream->async_handshake( boost::asio::ssl::stream_base::client,
			[ this, stream, connector_cb = std::move(connector_cb), error_cb = std::move(error_cb), connect_timer ]
				( const boost::system::error_code &ec )
				{
					connect_timer->cancel();
					if ( ec )
					{
						LOGERROR( ec.message() );
						return;
					}

					http::proto_version v = chose_protocol(stream);

					auto connector = std::make_shared<server::connector<server::ssl_socket>>(std::move(stream));
					connector->set_timeout(conn_timeout);
					connector_cb(std::move(connector), v);
				});
	});
}

namespace
{
static const std::string NGHTTP2_H2_ALPN = "\x2h2";
static const std::string NGHTTP2_H2_16_ALPN = "\x5h2-16";
static const std::string NGHTTP2_H2_14_ALPN = "\x5h2-14";
static const std::string HTTP1_1_ALPN = "\x8http/1.1";
static const std::string HTTP1_0_ALPN = "\x8http/1.0";

bool select_proto(const unsigned char **out, unsigned char *outlen,
				  const unsigned char *in, unsigned int inlen,
				  const std::string &key) {
  for (auto p = in, end = in + inlen; p + key.size() <= end; p += *p + 1) {
	if (std::equal(std::begin(key), std::end(key), p)) {
	  *out = p + 1;
	  *outlen = *p;
	  return true;
	}
  }
  return false;
}

bool select_h2(const unsigned char **out, unsigned char *outlen,
			   const unsigned char *in, unsigned int inlen)
{
  return select_proto(out, outlen, in, inlen, NGHTTP2_H2_ALPN) ||
		 select_proto(out, outlen, in, inlen, NGHTTP2_H2_16_ALPN) ||
		  select_proto(out, outlen, in, inlen, NGHTTP2_H2_14_ALPN);
}

bool select_h1(const unsigned char **out, unsigned char *outlen,
			   const unsigned char *in, unsigned int inlen)
{
  return select_proto(out, outlen, in, inlen, HTTP1_1_ALPN) ||
		 select_proto(out, outlen, in, inlen, HTTP1_0_ALPN);
}

int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
								unsigned char *outlen, const unsigned char *in,
								unsigned int inlen, void *arg)
{
	if (!select_h2(const_cast<const unsigned char **>(out), outlen, in, inlen) &&
			!select_h1(const_cast<const unsigned char **>(out), outlen, in, inlen))
	{
		return SSL_TLSEXT_ERR_NOACK;
	}
	return SSL_TLSEXT_ERR_OK;
}

const std::vector<unsigned char>& get_default_alpn()
{
  static auto res = std::vector<unsigned char>(NGHTTP2_H2_ALPN.size() +
										NGHTTP2_H2_16_ALPN.size() +
										NGHTTP2_H2_14_ALPN.size() +
										HTTP1_1_ALPN.size() +
										HTTP1_0_ALPN.size());
  static bool initialized = false;
  if(!initialized)
  {
	  initialized = true;
	  auto p = std::begin(res);
	  p = std::copy_n(std::begin(NGHTTP2_H2_ALPN), NGHTTP2_H2_ALPN.size(), p);
	  p = std::copy_n(std::begin(NGHTTP2_H2_16_ALPN), NGHTTP2_H2_16_ALPN.size(), p);
	  p = std::copy_n(std::begin(NGHTTP2_H2_14_ALPN), NGHTTP2_H2_14_ALPN.size(), p);
	  p = std::copy_n(std::begin(HTTP1_1_ALPN), HTTP1_1_ALPN.size(), p);
	  p = std::copy_n(std::begin(HTTP1_0_ALPN), HTTP1_0_ALPN.size(), p);
  }

  return res;
}

} // unnamed namespace

boost::asio::ssl::context dns_connector_factory::init_ssl_ctx()
{
	boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
	// enable NPN for http2
	auto ctx_h = ctx.native_handle();
	SSL_CTX_set_next_proto_select_cb(ctx_h, client_select_next_proto_cb, nullptr);
	// enable ALPN for http2
	SSL_CTX_set_alpn_protos(ctx_h, get_default_alpn().data(), get_default_alpn().size());
	return ctx;
}

thread_local boost::asio::ssl::context dns_connector_factory::ctx{dns_connector_factory::init_ssl_ctx()};

}
<|endoftext|>


<commit_before>/**
 * @file
 */
#include "libbirch/Copier.hpp"

#include "libbirch/Any.hpp"

libbirch::Any* libbirch::Copier::visitObject(Any* o) {
  auto value = m.get(o);
  if (!value) {
    value = o->copy_();
    value->accept_(*this);
  }
  return value;
}
<commit_msg>Fixed bug in Copier from last commit.<commit_after>/**
 * @file
 */
#include "libbirch/Copier.hpp"

#include "libbirch/Any.hpp"

libbirch::Any* libbirch::Copier::visitObject(Any* o) {
  auto& value = m.get(o);
  if (value) {
    return value;
  } else {
    value = o->copy_();

    /* copy the value into a non-reference, as the reference may be
     * invalidated if m is resized during the call to accept_() below */
    Any* result = value;
    result->accept_(*this);
    return result;
  }
}
<|endoftext|>