<commit_before>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "LoadImageModule.hpp"
#include "../framework/types/Matrix.hpp"

using namespace std;
using namespace uipf;

/*

*/
void LoadImageModule::run( DataManager& data) const
{
	 using namespace cv;

	  Mat image;
	  std::string strFilename = data.getParam<std::string>("filename","not found");
	  // check whether to load the image in grayscale mode, defaults to color
	  if (data.getParam<std::string>("mode","color").compare("grayscale") == 0)
	  {
	    image = imread (strFilename.c_str (), CV_LOAD_IMAGE_GRAYSCALE);	// Read the file
	  }
	  else
	  {
	    image = imread (strFilename.c_str (), CV_LOAD_IMAGE_COLOR);	// Read the file
	  }

	  if (!image.data)// Check for invalid input
	  {
	    throw new ErrorException(string("Could not open or find the image: ") + strFilename);
	  }

	  data.setOutputData("image",new Matrix(image));

}

MetaData LoadImageModule::getMetaData() const
{
	map<string, DataDescription> output = {
		{"image", DataDescription(MATRIX, "the loaded image.") }
	};
	map<string, ParamDescription> params = {
		{"filename", ParamDescription("file name of the file to load from.") },
		{"mode", ParamDescription("can be either 'color' or 'grayscale' for whether to load the image in color or grayscale mode. Defaults to 'color'.",true) },
	};

	return MetaData(
		"Load an image from a file.",
		map<string, DataDescription>(), // no inputs
		output,
		params
	);
}

<commit_msg>issue #86<commit_after>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "LoadImageModule.hpp"
#include "../framework/types/Matrix.hpp"

using namespace std;
using namespace uipf;

/*

*/
void LoadImageModule::run( DataManager& data) const
{
	 using namespace cv;

	  Mat image;
	  std::string strFilename = data.getParam<std::string>("filename","not found");
	  // check whether to load the image in grayscale mode, defaults to color
	  if (data.getParam<std::string>("mode","color").compare("grayscale") == 0)
	  {
	    image = imread (strFilename.c_str (), CV_LOAD_IMAGE_GRAYSCALE);	// Read the file
	  }
	  else
	  {
	    image = imread (strFilename.c_str (), CV_LOAD_IMAGE_COLOR);	// Read the file
	  }

	  if (!image.data)// Check for invalid input
	  {
	    throw ErrorException(string("Could not open or find the image: ") + strFilename);
	  }

	  data.setOutputData("image",new Matrix(image));

}

MetaData LoadImageModule::getMetaData() const
{
	map<string, DataDescription> output = {
		{"image", DataDescription(MATRIX, "the loaded image.") }
	};
	map<string, ParamDescription> params = {
		{"filename", ParamDescription("file name of the file to load from.") },
		{"mode", ParamDescription("can be either 'color' or 'grayscale' for whether to load the image in color or grayscale mode. Defaults to 'color'.",true) },
	};

	return MetaData(
		"Load an image from a file.",
		map<string, DataDescription>(), // no inputs
		output,
		params
	);
}

<|endoftext|>


<commit_before>#include <Python.h>
#include <iostream>
#include "binarytree.h"
#include <vector>

typedef struct {
    PyObject_HEAD
    binarytree::BinaryTree<PyObject*> btree;
} BinaryTree_obj;

static void BinaryTree_dealloc(BinaryTree_obj *self) {
    self->btree.~BinaryTree();
}

bool BinaryTree_intCMP(PyObject *left, PyObject *right) {
    int l = PyInt_AsLong(left);
    int r = PyInt_AsLong(right);
    return l < r;
}

static PyObject* BinaryTree_init(BinaryTree_obj *self, PyObject *args, PyObject *kwds) {
    binarytree::BinaryTree<PyObject*> tmp(BinaryTree_intCMP);
    (self->btree) = tmp;
    return 0;
}

PyObject* BinaryTree_ToString(PyObject *self) {
    return PyString_FromString("BinaryTree");
}

static PyObject* BinaryTree_add(BinaryTree_obj *self, PyObject *args) {
    PyObject* obj;
    if (!PyArg_ParseTuple(args, "O", &obj)) {
	return NULL;
    }
    self->btree.Add(obj);
    Py_RETURN_NONE;
}

static PyObject* BinaryTree_walk(BinaryTree_obj *self) {
    auto sortedItems = self->btree.Walk();
    PyObject *list = PyList_New(0);
    for (auto el : sortedItems) {
	if (PyList_Append(list, el) == -1) {
	    return NULL;
	}
    }
    return list;
}

static PyMethodDef  BinaryTree_methods[] = {
    {"add", (PyCFunction) BinaryTree_add, METH_VARARGS, "Add an element to the BinaryTree"},
    {"walk", (PyCFunction) BinaryTree_walk, METH_NOARGS, "Walk the tree and return a list"},
    {NULL}  /* Sentinel */
};

static PyTypeObject BinaryTreeType = {
    PyObject_HEAD_INIT(NULL)
    0,                                    /* ob_size is not used anymore, docs don't explain *what* it is */
    "binarytree.BinaryTree",              /* tp_name, string for object */
    sizeof(BinaryTree_obj),               /* tp_basicsize, how much space to alloc */
    0,                                    /* tp_itemsize */
    (destructor) BinaryTree_dealloc,      /* tp_dealloc */
    0,                                    /* tp_print */
    0,                                    /* tp_getattr */
    0,                                    /* tp_setattr */
    0,                                    /* tp_compare */
    0,                                    /* tp_repr */
    0,                                    /* tp_as_number */
    0,                                    /* tp_as_sequence */
    0,                                    /* tp_as_mapping */
    0,                                    /* tp_hash */
    0,                                    /* tp_call */
    BinaryTree_ToString,                  /* tp_str */
    0,                                    /* tp_getattro */
    0,                                    /* tp_setattro */
    0,                                    /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,                   /* tp_flags */
    "BinaryTree object",                  /* class docstring */
    0,		                          /* tp_traverse */
    0,		                          /* tp_clear */
    0,		                          /* tp_richcompare */
    0,		                          /* tp_weaklistoffset */
    0,		                          /* tp_iter */
    0,		                          /* tp_iternext */
    BinaryTree_methods,                   /* tp_methods */
    0,                                    /* tp_members */
    0,                                    /* tp_getset */
    0,                                    /* tp_base */
    0,                                    /* tp_dict */
    0,                                    /* tp_descr_get */
    0,                                    /* tp_descr_set */
    0,                                    /* tp_dictoffset */
    (initproc) BinaryTree_init,           /* tp_init */
    0,                                    /* tp_alloc */
    0,                                    /* tp_new */
};

static PyMethodDef binarytree_funcs[] = {
    // no free functions yet.
    {NULL}
};

PyMODINIT_FUNC initbinarytree(void) {
    BinaryTreeType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&BinaryTreeType) < 0)
	return;

    PyObject* m;
    m = Py_InitModule3("binarytree", binarytree_funcs, "Binary Tree wrapper module over a C++11 lib.");
    Py_INCREF(&BinaryTreeType);

    PyModule_AddObject(m, "BinaryTree", (PyObject *) &BinaryTreeType);
}
<commit_msg>Whitespace changes<commit_after>#include <Python.h>
#include <iostream>
#include "binarytree.h"
#include <vector>

typedef struct {
    PyObject_HEAD
    binarytree::BinaryTree<PyObject*> btree;
} BinaryTree_obj;

static void BinaryTree_dealloc(BinaryTree_obj *self) {
    self->btree.~BinaryTree();
}

bool BinaryTree_intCMP(PyObject *left, PyObject *right) {
    int l = PyInt_AsLong(left);
    int r = PyInt_AsLong(right);
    return l < r;
}

static PyObject* BinaryTree_init(BinaryTree_obj *self, PyObject *args, PyObject *kwds) {
    binarytree::BinaryTree<PyObject*> tmp(BinaryTree_intCMP);
    (self->btree) = tmp;
    return 0;
}

PyObject* BinaryTree_ToString(PyObject *self) {
    return PyString_FromString("BinaryTree");
}

static PyObject* BinaryTree_add(BinaryTree_obj *self, PyObject *args) {
    PyObject* obj;
    if (!PyArg_ParseTuple(args, "O", &obj)) {
	return NULL;
    }
    self->btree.Add(obj);
    Py_RETURN_NONE;
}

static PyObject* BinaryTree_walk(BinaryTree_obj *self) {
    auto sortedItems = self->btree.Walk();
    PyObject *list = PyList_New(0);
    for (auto el : sortedItems) {
	if (PyList_Append(list, el) == -1) {
	    return NULL;
	}
    }
    return list;
}

static PyMethodDef BinaryTree_methods[] = {
    {"add", (PyCFunction) BinaryTree_add, METH_VARARGS, "Add an element to the BinaryTree"},
    {"walk", (PyCFunction) BinaryTree_walk, METH_NOARGS, "Walk the tree and return a list"},
    {NULL} /* Sentinel */
};

static PyTypeObject BinaryTreeType = {
    PyObject_HEAD_INIT(NULL)
    0,                                 /* ob_size is not used anymore, docs don't explain *what* it is */
    "binarytree.BinaryTree",           /* tp_name, string for object */
    sizeof(BinaryTree_obj),            /* tp_basicsize, how much space to alloc */
    0,                                 /* tp_itemsize */
    (destructor) BinaryTree_dealloc,   /* tp_dealloc */
    0,                                 /* tp_print */
    0,                                 /* tp_getattr */
    0,                                 /* tp_setattr */
    0,                                 /* tp_compare */
    0,                                 /* tp_repr */
    0,                                 /* tp_as_number */
    0,                                 /* tp_as_sequence */
    0,                                 /* tp_as_mapping */
    0,                                 /* tp_hash */
    0,                                 /* tp_call */
    BinaryTree_ToString,               /* tp_str */
    0,                                 /* tp_getattro */
    0,                                 /* tp_setattro */
    0,                                 /* tp_as_buffer  */
    Py_TPFLAGS_DEFAULT,                /* tp_flags  */
    "BinaryTree  object",              /* tp_doc */
    0,		                       /* tp_traverse  */
    0,		                       /* tp_clear  */
    0,		                       /* tp_richcompare  */
    0,		                       /* tp_weaklistoffset  */
    0,		                       /* tp_iter  */
    0,		                       /* tp_iternext  */
    BinaryTree_methods,                /* tp_methods  */
    0,                                 /* tp_members  */
    0,                                 /* tp_getset  */
    0,                                 /* tp_base  */
    0,                                 /* tp_dict  */
    0,                                 /* tp_descr_get  */
    0,                                 /* tp_descr_set  */
    0,                                 /* tp_dictoffset  */
    (initproc)  BinaryTree_init,       /* tp_init  */
    0,                                 /* tp_alloc  */
    0,                                 /* tp_new  */
};

static PyMethodDef binarytree_funcs[] = {
    // no free functions yet.
    {NULL}
};

PyMODINIT_FUNC initbinarytree(void) {
    BinaryTreeType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&BinaryTreeType) < 0)
	return;

    PyObject* m;
    m = Py_InitModule3("binarytree", binarytree_funcs, "Binary Tree wrapper module over a C++11 lib.");
    Py_INCREF(&BinaryTreeType);
    PyModule_AddObject(m, "BinaryTree", (PyObject *) &BinaryTreeType);
}
<|endoftext|>


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

#include "net/base/tcp_client_socket.h"

#include "base/string_util.h"
#include "base/trace_event.h"
#include "net/base/net_errors.h"
#include "net/base/winsock_init.h"

namespace net {

//-----------------------------------------------------------------------------

static int MapWinsockError(DWORD err) {
  // There are numerous Winsock error codes, but these are the ones we thus far
  // find interesting.
  switch (err) {
    case WSAENETDOWN:
      return ERR_INTERNET_DISCONNECTED;
    case WSAETIMEDOUT:
      return ERR_TIMED_OUT;
    case WSAECONNRESET:
    case WSAENETRESET:  // Related to keep-alive
      return ERR_CONNECTION_RESET;
    case WSAECONNABORTED:
      return ERR_CONNECTION_ABORTED;
    case WSAECONNREFUSED:
      return ERR_CONNECTION_REFUSED;
    case WSAEDISCON:
      // Returned by WSARecv or WSARecvFrom for message-oriented sockets (where
      // a return value of zero means a zero-byte message) to indicate graceful
      // connection shutdown.  We should not ever see this error code for TCP
      // sockets, which are byte stream oriented.
      NOTREACHED();
      return ERR_CONNECTION_CLOSED;
    case WSAEHOSTUNREACH:
    case WSAENETUNREACH:
      return ERR_ADDRESS_UNREACHABLE;
    case WSAEADDRNOTAVAIL:
      return ERR_ADDRESS_INVALID;
    case WSA_IO_INCOMPLETE:
      return ERR_UNEXPECTED;
    case ERROR_SUCCESS:
      return OK;
    default:
      return ERR_FAILED;
  }
}

//-----------------------------------------------------------------------------

TCPClientSocket::TCPClientSocket(const AddressList& addresses)
    : socket_(INVALID_SOCKET),
      addresses_(addresses),
      current_ai_(addresses_.head()),
      wait_state_(NOT_WAITING) {
  memset(&overlapped_, 0, sizeof(overlapped_));
  EnsureWinsockInit();
}

TCPClientSocket::~TCPClientSocket() {
  Disconnect();
}

int TCPClientSocket::Connect(CompletionCallback* callback) {
  // If already connected, then just return OK.
  if (socket_ != INVALID_SOCKET)
    return OK;

  TRACE_EVENT_BEGIN("socket.connect", this, "");
  const struct addrinfo* ai = current_ai_;
  DCHECK(ai);

  int rv = CreateSocket(ai);
  if (rv != OK)
    return rv;

  overlapped_.hEvent = WSACreateEvent();
  // WSAEventSelect sets the socket to non-blocking mode as a side effect.
  // Our connect() and recv() calls require that the socket be non-blocking.
  WSAEventSelect(socket_, overlapped_.hEvent, FD_CONNECT);

  if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
    TRACE_EVENT_END("socket.connect", this, "");
    // Connected without waiting!
    return OK;
  }

  DWORD err = WSAGetLastError();
  if (err != WSAEWOULDBLOCK) {
    LOG(ERROR) << "connect failed: " << err;
    return MapWinsockError(err);
  }

  watcher_.StartWatching(overlapped_.hEvent, this);
  wait_state_ = WAITING_CONNECT;
  callback_ = callback;
  return ERR_IO_PENDING;
}

int TCPClientSocket::ReconnectIgnoringLastError(CompletionCallback* callback) {
  // No ignorable errors!
  return ERR_FAILED;
}

void TCPClientSocket::Disconnect() {
  if (socket_ == INVALID_SOCKET)
    return;

  TRACE_EVENT_INSTANT("socket.disconnect", this, "");

  // Make sure the message loop is not watching this object anymore.
  watcher_.StopWatching();

  // In most socket implementations, closing a socket results in a graceful
  // connection shutdown, but in Winsock we have to call shutdown explicitly.
  // See the MSDN page "Graceful Shutdown, Linger Options, and Socket Closure"
  // at http://msdn.microsoft.com/en-us/library/ms738547.aspx
  shutdown(socket_, SD_SEND);

  // This cancels any pending IO.
  closesocket(socket_);
  socket_ = INVALID_SOCKET;

  WSACloseEvent(overlapped_.hEvent);
  memset(&overlapped_, 0, sizeof(overlapped_));

  // Reset for next time.
  current_ai_ = addresses_.head();
}

bool TCPClientSocket::IsConnected() const {
  if (socket_ == INVALID_SOCKET || wait_state_ == WAITING_CONNECT)
    return false;

  // Check if connection is alive.
  char c;
  int rv = recv(socket_, &c, 1, MSG_PEEK);
  if (rv == 0)
    return false;
  if (rv == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
    return false;

  return true;
}

int TCPClientSocket::Read(char* buf,
                          int buf_len,
                          CompletionCallback* callback) {
  DCHECK(socket_ != INVALID_SOCKET);
  DCHECK(wait_state_ == NOT_WAITING);
  DCHECK(!callback_);

  buffer_.len = buf_len;
  buffer_.buf = buf;

  // TODO(wtc): Remove the CHECKs after enough testing.
  CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT);
  DWORD num, flags = 0;
  int rv = WSARecv(socket_, &buffer_, 1, &num, &flags, &overlapped_, NULL);
  if (rv == 0) {
    CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_OBJECT_0);
    BOOL ok = WSAResetEvent(overlapped_.hEvent);
    CHECK(ok);
    return static_cast<int>(num);
  }
  int err = WSAGetLastError();
  if (err == WSA_IO_PENDING) {
    watcher_.StartWatching(overlapped_.hEvent, this);
    wait_state_ = WAITING_READ;
    callback_ = callback;
    return ERR_IO_PENDING;
  }
  return MapWinsockError(err);
}

int TCPClientSocket::Write(const char* buf,
                           int buf_len,
                           CompletionCallback* callback) {
  DCHECK(socket_ != INVALID_SOCKET);
  DCHECK(wait_state_ == NOT_WAITING);
  DCHECK(!callback_);

  buffer_.len = buf_len;
  buffer_.buf = const_cast<char*>(buf);

  // TODO(wtc): Remove the CHECKs after enough testing.
  CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT);
  DWORD num;
  int rv = WSASend(socket_, &buffer_, 1, &num, 0, &overlapped_, NULL);
  if (rv == 0) {
    CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_OBJECT_0);
    BOOL ok = WSAResetEvent(overlapped_.hEvent);
    CHECK(ok);
    return static_cast<int>(num);
  }
  int err = WSAGetLastError();
  if (err == WSA_IO_PENDING) {
    watcher_.StartWatching(overlapped_.hEvent, this);
    wait_state_ = WAITING_WRITE;
    callback_ = callback;
    return ERR_IO_PENDING;
  }
  return MapWinsockError(err);
}

int TCPClientSocket::CreateSocket(const struct addrinfo* ai) {
  socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0,
                      WSA_FLAG_OVERLAPPED);
  if (socket_ == INVALID_SOCKET) {
    DWORD err = WSAGetLastError();
    LOG(ERROR) << "WSASocket failed: " << err;
    return MapWinsockError(err);
  }
  return OK;
}

void TCPClientSocket::DoCallback(int rv) {
  DCHECK(rv != ERR_IO_PENDING);
  DCHECK(callback_);

  // since Run may result in Read being called, clear callback_ up front.
  CompletionCallback* c = callback_;
  callback_ = NULL;
  c->Run(rv);
}

void TCPClientSocket::DidCompleteConnect() {
  int result;

  TRACE_EVENT_END("socket.connect", this, "");
  wait_state_ = NOT_WAITING;

  WSANETWORKEVENTS events;
  int rv = WSAEnumNetworkEvents(socket_, overlapped_.hEvent, &events);
  if (rv == SOCKET_ERROR) {
    NOTREACHED();
    result = MapWinsockError(WSAGetLastError());
  } else if (events.lNetworkEvents & FD_CONNECT) {
    wait_state_ = NOT_WAITING;
    DWORD error_code = static_cast<DWORD>(events.iErrorCode[FD_CONNECT_BIT]);
    if (current_ai_->ai_next && (
        error_code == WSAEADDRNOTAVAIL ||
        error_code == WSAEAFNOSUPPORT ||
        error_code == WSAECONNREFUSED ||
        error_code == WSAENETUNREACH ||
        error_code == WSAEHOSTUNREACH ||
        error_code == WSAETIMEDOUT)) {
      // Try using the next address.
      const struct addrinfo* next = current_ai_->ai_next;
      Disconnect();
      current_ai_ = next;
      result = Connect(callback_);
    } else {
      result = MapWinsockError(error_code);
    }
  } else {
    NOTREACHED();
    result = ERR_FAILED;
  }

  if (result != ERR_IO_PENDING)
    DoCallback(result);
}

void TCPClientSocket::DidCompleteIO() {
  DWORD num_bytes, flags;
  BOOL ok = WSAGetOverlappedResult(
      socket_, &overlapped_, &num_bytes, FALSE, &flags);
  WSAResetEvent(overlapped_.hEvent);
  if (wait_state_ == WAITING_READ) {
    TRACE_EVENT_INSTANT("socket.read", this,
                        StringPrintf("%d bytes", num_bytes));
  } else {
    TRACE_EVENT_INSTANT("socket.write", this,
                        StringPrintf("%d bytes", num_bytes));
  }
  wait_state_ = NOT_WAITING;
  DoCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError()));
}

void TCPClientSocket::OnObjectSignaled(HANDLE object) {
  DCHECK(object == overlapped_.hEvent);

  switch (wait_state_) {
    case WAITING_CONNECT:
      DidCompleteConnect();
      break;
    case WAITING_READ:
    case WAITING_WRITE:
      DidCompleteIO();
      break;
    default:
      NOTREACHED();
      break;
  }
}

}  // namespace net

<commit_msg>Remove all but one place in this file where we return ERR_FAILED.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/tcp_client_socket.h"

#include "base/string_util.h"
#include "base/trace_event.h"
#include "net/base/net_errors.h"
#include "net/base/winsock_init.h"

namespace net {

//-----------------------------------------------------------------------------

static int MapWinsockError(DWORD err) {
  // There are numerous Winsock error codes, but these are the ones we thus far
  // find interesting.
  switch (err) {
    case WSAENETDOWN:
      return ERR_INTERNET_DISCONNECTED;
    case WSAETIMEDOUT:
      return ERR_TIMED_OUT;
    case WSAECONNRESET:
    case WSAENETRESET:  // Related to keep-alive
      return ERR_CONNECTION_RESET;
    case WSAECONNABORTED:
      return ERR_CONNECTION_ABORTED;
    case WSAECONNREFUSED:
      return ERR_CONNECTION_REFUSED;
    case WSAEDISCON:
      // Returned by WSARecv or WSARecvFrom for message-oriented sockets (where
      // a return value of zero means a zero-byte message) to indicate graceful
      // connection shutdown.  We should not ever see this error code for TCP
      // sockets, which are byte stream oriented.
      NOTREACHED();
      return ERR_CONNECTION_CLOSED;
    case WSAEHOSTUNREACH:
    case WSAENETUNREACH:
      return ERR_ADDRESS_UNREACHABLE;
    case WSAEADDRNOTAVAIL:
      return ERR_ADDRESS_INVALID;
    case WSA_IO_INCOMPLETE:
      return ERR_UNEXPECTED;
    case ERROR_SUCCESS:
      return OK;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

//-----------------------------------------------------------------------------

TCPClientSocket::TCPClientSocket(const AddressList& addresses)
    : socket_(INVALID_SOCKET),
      addresses_(addresses),
      current_ai_(addresses_.head()),
      wait_state_(NOT_WAITING) {
  memset(&overlapped_, 0, sizeof(overlapped_));
  EnsureWinsockInit();
}

TCPClientSocket::~TCPClientSocket() {
  Disconnect();
}

int TCPClientSocket::Connect(CompletionCallback* callback) {
  // If already connected, then just return OK.
  if (socket_ != INVALID_SOCKET)
    return OK;

  TRACE_EVENT_BEGIN("socket.connect", this, "");
  const struct addrinfo* ai = current_ai_;
  DCHECK(ai);

  int rv = CreateSocket(ai);
  if (rv != OK)
    return rv;

  overlapped_.hEvent = WSACreateEvent();
  // WSAEventSelect sets the socket to non-blocking mode as a side effect.
  // Our connect() and recv() calls require that the socket be non-blocking.
  WSAEventSelect(socket_, overlapped_.hEvent, FD_CONNECT);

  if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
    TRACE_EVENT_END("socket.connect", this, "");
    // Connected without waiting!
    return OK;
  }

  DWORD err = WSAGetLastError();
  if (err != WSAEWOULDBLOCK) {
    LOG(ERROR) << "connect failed: " << err;
    return MapWinsockError(err);
  }

  watcher_.StartWatching(overlapped_.hEvent, this);
  wait_state_ = WAITING_CONNECT;
  callback_ = callback;
  return ERR_IO_PENDING;
}

int TCPClientSocket::ReconnectIgnoringLastError(CompletionCallback* callback) {
  // No ignorable errors!
  return ERR_UNEXPECTED;
}

void TCPClientSocket::Disconnect() {
  if (socket_ == INVALID_SOCKET)
    return;

  TRACE_EVENT_INSTANT("socket.disconnect", this, "");

  // Make sure the message loop is not watching this object anymore.
  watcher_.StopWatching();

  // In most socket implementations, closing a socket results in a graceful
  // connection shutdown, but in Winsock we have to call shutdown explicitly.
  // See the MSDN page "Graceful Shutdown, Linger Options, and Socket Closure"
  // at http://msdn.microsoft.com/en-us/library/ms738547.aspx
  shutdown(socket_, SD_SEND);

  // This cancels any pending IO.
  closesocket(socket_);
  socket_ = INVALID_SOCKET;

  WSACloseEvent(overlapped_.hEvent);
  memset(&overlapped_, 0, sizeof(overlapped_));

  // Reset for next time.
  current_ai_ = addresses_.head();
}

bool TCPClientSocket::IsConnected() const {
  if (socket_ == INVALID_SOCKET || wait_state_ == WAITING_CONNECT)
    return false;

  // Check if connection is alive.
  char c;
  int rv = recv(socket_, &c, 1, MSG_PEEK);
  if (rv == 0)
    return false;
  if (rv == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
    return false;

  return true;
}

int TCPClientSocket::Read(char* buf,
                          int buf_len,
                          CompletionCallback* callback) {
  DCHECK(socket_ != INVALID_SOCKET);
  DCHECK(wait_state_ == NOT_WAITING);
  DCHECK(!callback_);

  buffer_.len = buf_len;
  buffer_.buf = buf;

  // TODO(wtc): Remove the CHECKs after enough testing.
  CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT);
  DWORD num, flags = 0;
  int rv = WSARecv(socket_, &buffer_, 1, &num, &flags, &overlapped_, NULL);
  if (rv == 0) {
    CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_OBJECT_0);
    BOOL ok = WSAResetEvent(overlapped_.hEvent);
    CHECK(ok);
    return static_cast<int>(num);
  }
  int err = WSAGetLastError();
  if (err == WSA_IO_PENDING) {
    watcher_.StartWatching(overlapped_.hEvent, this);
    wait_state_ = WAITING_READ;
    callback_ = callback;
    return ERR_IO_PENDING;
  }
  return MapWinsockError(err);
}

int TCPClientSocket::Write(const char* buf,
                           int buf_len,
                           CompletionCallback* callback) {
  DCHECK(socket_ != INVALID_SOCKET);
  DCHECK(wait_state_ == NOT_WAITING);
  DCHECK(!callback_);

  buffer_.len = buf_len;
  buffer_.buf = const_cast<char*>(buf);

  // TODO(wtc): Remove the CHECKs after enough testing.
  CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT);
  DWORD num;
  int rv = WSASend(socket_, &buffer_, 1, &num, 0, &overlapped_, NULL);
  if (rv == 0) {
    CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_OBJECT_0);
    BOOL ok = WSAResetEvent(overlapped_.hEvent);
    CHECK(ok);
    return static_cast<int>(num);
  }
  int err = WSAGetLastError();
  if (err == WSA_IO_PENDING) {
    watcher_.StartWatching(overlapped_.hEvent, this);
    wait_state_ = WAITING_WRITE;
    callback_ = callback;
    return ERR_IO_PENDING;
  }
  return MapWinsockError(err);
}

int TCPClientSocket::CreateSocket(const struct addrinfo* ai) {
  socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0,
                      WSA_FLAG_OVERLAPPED);
  if (socket_ == INVALID_SOCKET) {
    DWORD err = WSAGetLastError();
    LOG(ERROR) << "WSASocket failed: " << err;
    return MapWinsockError(err);
  }
  return OK;
}

void TCPClientSocket::DoCallback(int rv) {
  DCHECK(rv != ERR_IO_PENDING);
  DCHECK(callback_);

  // since Run may result in Read being called, clear callback_ up front.
  CompletionCallback* c = callback_;
  callback_ = NULL;
  c->Run(rv);
}

void TCPClientSocket::DidCompleteConnect() {
  int result;

  TRACE_EVENT_END("socket.connect", this, "");
  wait_state_ = NOT_WAITING;

  WSANETWORKEVENTS events;
  int rv = WSAEnumNetworkEvents(socket_, overlapped_.hEvent, &events);
  if (rv == SOCKET_ERROR) {
    NOTREACHED();
    result = MapWinsockError(WSAGetLastError());
  } else if (events.lNetworkEvents & FD_CONNECT) {
    wait_state_ = NOT_WAITING;
    DWORD error_code = static_cast<DWORD>(events.iErrorCode[FD_CONNECT_BIT]);
    if (current_ai_->ai_next && (
        error_code == WSAEADDRNOTAVAIL ||
        error_code == WSAEAFNOSUPPORT ||
        error_code == WSAECONNREFUSED ||
        error_code == WSAENETUNREACH ||
        error_code == WSAEHOSTUNREACH ||
        error_code == WSAETIMEDOUT)) {
      // Try using the next address.
      const struct addrinfo* next = current_ai_->ai_next;
      Disconnect();
      current_ai_ = next;
      result = Connect(callback_);
    } else {
      result = MapWinsockError(error_code);
    }
  } else {
    NOTREACHED();
    result = ERR_UNEXPECTED;
  }

  if (result != ERR_IO_PENDING)
    DoCallback(result);
}

void TCPClientSocket::DidCompleteIO() {
  DWORD num_bytes, flags;
  BOOL ok = WSAGetOverlappedResult(
      socket_, &overlapped_, &num_bytes, FALSE, &flags);
  WSAResetEvent(overlapped_.hEvent);
  if (wait_state_ == WAITING_READ) {
    TRACE_EVENT_INSTANT("socket.read", this,
                        StringPrintf("%d bytes", num_bytes));
  } else {
    TRACE_EVENT_INSTANT("socket.write", this,
                        StringPrintf("%d bytes", num_bytes));
  }
  wait_state_ = NOT_WAITING;
  DoCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError()));
}

void TCPClientSocket::OnObjectSignaled(HANDLE object) {
  DCHECK(object == overlapped_.hEvent);

  switch (wait_state_) {
    case WAITING_CONNECT:
      DidCompleteConnect();
      break;
    case WAITING_READ:
    case WAITING_WRITE:
      DidCompleteIO();
      break;
    default:
      NOTREACHED();
      break;
  }
}

}  // namespace net

<|endoftext|>


<commit_before>// @(#)root/krb5auth:$Id$
// Author: Maarten Ballintijn   27/10/2003

#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>

#include "TKSocket.h"
#include "TSocket.h"
#include "TError.h"

extern "C" {
// missing from "krb5.h"
extern int krb5_net_read(/*IN*/ krb5_context context, int fd,
                         /*OUT*/ char *buf,/*IN*/ int len);

extern int krb5_net_write(/*IN*/ krb5_context context, int fd,
                          const char *buf, int len);
}

#ifdef __APPLE__
#define SOCKET int
#define SOCKET_ERRNO errno
#define SOCKET_EINTR EINTR
#define SOCKET_READ(a,b,c) read(a,b,c)
#define SOCKET_WRITE(a,b,c) write(a,b,c)
/*
 * lib/krb5/os/net_read.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_read() reads from the file descriptor "fd" to the buffer
 * "buf", until either 1) "len" bytes have been read or 2) cannot
 * read anymore from "fd".  It returns the number of bytes read
 * or a read() error.  (The calling interface is identical to
 * read(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_read(krb5_context /*context*/, int fd, register char *buf, register int len)
{
   int cc, len2 = 0;

   do {
      cc = SOCKET_READ((SOCKET)fd, buf, len);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
	      errno = SOCKET_ERRNO;

         return(cc);          /* errno is already set */
      } else if (cc == 0) {
         return(len2);
      } else {
         buf += cc;
         len2 += cc;
         len -= cc;
      }
   } while (len > 0);
   return(len2);
}
/*
 * lib/krb5/os/net_write.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_write() writes "len" bytes from "buf" to the file
 * descriptor "fd".  It returns the number of bytes written or
 * a write() error.  (The calling interface is identical to
 * write(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_write(krb5_context /*context*/, int fd, register const char *buf, int len)
{
   int cc;
   register int wrlen = len;
   do {
      cc = SOCKET_WRITE((SOCKET)fd, buf, wrlen);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
         errno = SOCKET_ERRNO;

         return(cc);
      } else {
         buf += cc;
         wrlen -= cc;
      }
   } while (wrlen > 0);
   return(len);
}
#endif

ClassImp(TKSocket)

krb5_context TKSocket::fgContext = 0;
krb5_ccache TKSocket::fgCCDef = 0;
krb5_principal TKSocket::fgClient = 0;

//______________________________________________________________________________
TKSocket::TKSocket(TSocket *s)
   : fSocket(s), fServer(0), fAuthContext(0)
{
   // Constructor

}

//______________________________________________________________________________
TKSocket::~TKSocket()
{
   // Destructor

   krb5_free_principal(fgContext, fServer);
   krb5_auth_con_free(fgContext, fAuthContext);
   delete fSocket;
}

//______________________________________________________________________________
TKSocket *TKSocket::Connect(const char *server, Int_t port)
{
   // Connect to 'server' on 'port'

   Int_t rc;

   if (fgContext == 0) {
      rc = krb5_init_context(&fgContext);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while initializing krb5 (%d), %s",
                 rc, error_message(rc));
         return 0;
      }

      rc = krb5_cc_default(fgContext, &fgCCDef);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting default credential cache (%d), %s",
                 rc, error_message(rc));
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }

      rc = krb5_cc_get_principal(fgContext, fgCCDef, &fgClient);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting client principal from %s (%d), %s",
                 krb5_cc_get_name(fgContext,fgCCDef), rc, error_message(rc));
         krb5_cc_close(fgContext,fgCCDef); fgCCDef = 0;
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }
   }

   TSocket  *s = new TSocket(server, port);

   if (!s->IsValid()) {
      ::SysError("TKSocket::Connect","Cannot connect to %s:%d", server, port);
      delete s;
      return 0;
   }

   TKSocket *ks = new TKSocket(s);

   rc = krb5_sname_to_principal(fgContext, server, "host", KRB5_NT_SRV_HST, &ks->fServer);
   if (rc != 0) {
      ::Error("TKSocket::Connect","while getting server principal (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   krb5_data cksum_data;
   cksum_data.data = StrDup(server);
   cksum_data.length = strlen(server);

   krb5_error *err_ret;
   krb5_ap_rep_enc_part *rep_ret;

   int sock = ks->fSocket->GetDescriptor();
   rc = krb5_sendauth(fgContext, &ks->fAuthContext, (krb5_pointer) &sock,
                      (char *)"KRB5_TCP_Python_v1.0", fgClient, ks->fServer,
                      AP_OPTS_MUTUAL_REQUIRED,
                      &cksum_data,
                      0,           /* no creds, use ccache instead */
                      fgCCDef, &err_ret, &rep_ret, 0);

   delete [] cksum_data.data;

   if (rc != 0) {
      ::Error("TKSocket::Connect","while sendauth (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   return ks;
}

//______________________________________________________________________________
Int_t TKSocket::BlockRead(char *&buf, EEncoding &type)
{
   // Read block on information from server. The result is stored in buf.
   // The number of read bytes is returned; -1 is returned in case of error.

   Int_t rc;
   Desc_t desc;
   Int_t fd = fSocket->GetDescriptor();

   rc = krb5_net_read(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading descriptor (%d), %s",
               rc, error_message(rc));
      return -1;
   }

   type = static_cast<EEncoding>(ntohs(desc.fType));

   krb5_data enc;
   enc.length = ntohs(desc.fLength);
   enc.data = new char[enc.length+1];

   rc = krb5_net_read(fgContext, fd, enc.data, enc.length);
   enc.data[enc.length] = 0;

   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading data (%d), %s",
               rc, error_message(rc));
      delete [] enc.data;
      return -1;
   }

   krb5_data out;
   switch (type) {
   case kNone:
      buf = enc.data;
      rc = enc.length;
      break;
   case kSafe:
      rc = krb5_rd_safe(fgContext, fAuthContext, &enc, &out, 0);
      break;
   case kPriv:
      rc = krb5_rd_priv(fgContext, fAuthContext, &enc, &out, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   if (type != kNone) {
      // copy data to buffer that is new'ed
      buf = new char[out.length+1];
      memcpy(buf, out.data, out.length);
      buf[out.length] = 0;
      free(out.data);
      delete [] enc.data;
      rc = out.length;
   }

   return rc;
}

//______________________________________________________________________________
Int_t TKSocket::BlockWrite(const char *buf, Int_t length, EEncoding type)
{
   // Block-send 'length' bytes to server from 'buf'.

   Desc_t desc;
   krb5_data in;
   krb5_data enc;
   Int_t rc;
   in.data = const_cast<char*>(buf);
   in.length = length;

   switch (type) {
   case kNone:
      enc.data = in.data;
      enc.length = in.length;
      break;
   case kSafe:
      rc = krb5_mk_safe(fgContext, fAuthContext, &in, &enc, 0);
      break;
   case kPriv:
      rc = krb5_mk_priv(fgContext, fAuthContext, &in, &enc, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   desc.fLength = htons(enc.length);
   desc.fType = htons(type);

   Int_t fd = fSocket->GetDescriptor();
   rc = krb5_net_write(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc <= 0) {
      Error("BlockWrite","writing descriptor (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   rc = krb5_net_write(fgContext, fd, (char *)enc.data, enc.length);
   if (rc <= 0) {
      Error("BlockWrite","writing data (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   if (type != kNone) free(enc.data);

   return rc;
}
<commit_msg>add unistd.h include needed for read()/write() and gcc 4.7. Fixes issue 94702.<commit_after>// @(#)root/krb5auth:$Id$
// Author: Maarten Ballintijn   27/10/2003

#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#ifndef WIN32
#   include <unistd.h>
#endif

#include "TKSocket.h"
#include "TSocket.h"
#include "TError.h"

extern "C" {
// missing from "krb5.h"
extern int krb5_net_read(/*IN*/ krb5_context context, int fd,
                         /*OUT*/ char *buf,/*IN*/ int len);

extern int krb5_net_write(/*IN*/ krb5_context context, int fd,
                          const char *buf, int len);
}

#ifdef __APPLE__
#define SOCKET int
#define SOCKET_ERRNO errno
#define SOCKET_EINTR EINTR
#define SOCKET_READ(a,b,c) read(a,b,c)
#define SOCKET_WRITE(a,b,c) write(a,b,c)
/*
 * lib/krb5/os/net_read.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_read() reads from the file descriptor "fd" to the buffer
 * "buf", until either 1) "len" bytes have been read or 2) cannot
 * read anymore from "fd".  It returns the number of bytes read
 * or a read() error.  (The calling interface is identical to
 * read(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_read(krb5_context /*context*/, int fd, register char *buf, register int len)
{
   int cc, len2 = 0;

   do {
      cc = SOCKET_READ((SOCKET)fd, buf, len);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
	      errno = SOCKET_ERRNO;

         return(cc);          /* errno is already set */
      } else if (cc == 0) {
         return(len2);
      } else {
         buf += cc;
         len2 += cc;
         len -= cc;
      }
   } while (len > 0);
   return(len2);
}
/*
 * lib/krb5/os/net_write.c
 *
 * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 */

/*
 * krb5_net_write() writes "len" bytes from "buf" to the file
 * descriptor "fd".  It returns the number of bytes written or
 * a write() error.  (The calling interface is identical to
 * write(2).)
 *
 * XXX must not use non-blocking I/O
 */

int krb5_net_write(krb5_context /*context*/, int fd, register const char *buf, int len)
{
   int cc;
   register int wrlen = len;
   do {
      cc = SOCKET_WRITE((SOCKET)fd, buf, wrlen);
      if (cc < 0) {
         if (SOCKET_ERRNO == SOCKET_EINTR)
            continue;

         /* XXX this interface sucks! */
         errno = SOCKET_ERRNO;

         return(cc);
      } else {
         buf += cc;
         wrlen -= cc;
      }
   } while (wrlen > 0);
   return(len);
}
#endif

ClassImp(TKSocket)

krb5_context TKSocket::fgContext = 0;
krb5_ccache TKSocket::fgCCDef = 0;
krb5_principal TKSocket::fgClient = 0;

//______________________________________________________________________________
TKSocket::TKSocket(TSocket *s)
   : fSocket(s), fServer(0), fAuthContext(0)
{
   // Constructor

}

//______________________________________________________________________________
TKSocket::~TKSocket()
{
   // Destructor

   krb5_free_principal(fgContext, fServer);
   krb5_auth_con_free(fgContext, fAuthContext);
   delete fSocket;
}

//______________________________________________________________________________
TKSocket *TKSocket::Connect(const char *server, Int_t port)
{
   // Connect to 'server' on 'port'

   Int_t rc;

   if (fgContext == 0) {
      rc = krb5_init_context(&fgContext);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while initializing krb5 (%d), %s",
                 rc, error_message(rc));
         return 0;
      }

      rc = krb5_cc_default(fgContext, &fgCCDef);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting default credential cache (%d), %s",
                 rc, error_message(rc));
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }

      rc = krb5_cc_get_principal(fgContext, fgCCDef, &fgClient);
      if (rc != 0) {
         ::Error("TKSocket::Connect","while getting client principal from %s (%d), %s",
                 krb5_cc_get_name(fgContext,fgCCDef), rc, error_message(rc));
         krb5_cc_close(fgContext,fgCCDef); fgCCDef = 0;
         krb5_free_context(fgContext); fgContext = 0;
         return 0;
      }
   }

   TSocket  *s = new TSocket(server, port);

   if (!s->IsValid()) {
      ::SysError("TKSocket::Connect","Cannot connect to %s:%d", server, port);
      delete s;
      return 0;
   }

   TKSocket *ks = new TKSocket(s);

   rc = krb5_sname_to_principal(fgContext, server, "host", KRB5_NT_SRV_HST, &ks->fServer);
   if (rc != 0) {
      ::Error("TKSocket::Connect","while getting server principal (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   krb5_data cksum_data;
   cksum_data.data = StrDup(server);
   cksum_data.length = strlen(server);

   krb5_error *err_ret;
   krb5_ap_rep_enc_part *rep_ret;

   int sock = ks->fSocket->GetDescriptor();
   rc = krb5_sendauth(fgContext, &ks->fAuthContext, (krb5_pointer) &sock,
                      (char *)"KRB5_TCP_Python_v1.0", fgClient, ks->fServer,
                      AP_OPTS_MUTUAL_REQUIRED,
                      &cksum_data,
                      0,           /* no creds, use ccache instead */
                      fgCCDef, &err_ret, &rep_ret, 0);

   delete [] cksum_data.data;

   if (rc != 0) {
      ::Error("TKSocket::Connect","while sendauth (%d), %s",
              rc, error_message(rc));
      delete ks;
      return 0;
   }

   return ks;
}

//______________________________________________________________________________
Int_t TKSocket::BlockRead(char *&buf, EEncoding &type)
{
   // Read block on information from server. The result is stored in buf.
   // The number of read bytes is returned; -1 is returned in case of error.

   Int_t rc;
   Desc_t desc;
   Int_t fd = fSocket->GetDescriptor();

   rc = krb5_net_read(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading descriptor (%d), %s",
               rc, error_message(rc));
      return -1;
   }

   type = static_cast<EEncoding>(ntohs(desc.fType));

   krb5_data enc;
   enc.length = ntohs(desc.fLength);
   enc.data = new char[enc.length+1];

   rc = krb5_net_read(fgContext, fd, enc.data, enc.length);
   enc.data[enc.length] = 0;

   if (rc == 0) errno = ECONNABORTED;

   if (rc <= 0) {
      SysError("BlockRead","reading data (%d), %s",
               rc, error_message(rc));
      delete [] enc.data;
      return -1;
   }

   krb5_data out;
   switch (type) {
   case kNone:
      buf = enc.data;
      rc = enc.length;
      break;
   case kSafe:
      rc = krb5_rd_safe(fgContext, fAuthContext, &enc, &out, 0);
      break;
   case kPriv:
      rc = krb5_rd_priv(fgContext, fAuthContext, &enc, &out, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   if (type != kNone) {
      // copy data to buffer that is new'ed
      buf = new char[out.length+1];
      memcpy(buf, out.data, out.length);
      buf[out.length] = 0;
      free(out.data);
      delete [] enc.data;
      rc = out.length;
   }

   return rc;
}

//______________________________________________________________________________
Int_t TKSocket::BlockWrite(const char *buf, Int_t length, EEncoding type)
{
   // Block-send 'length' bytes to server from 'buf'.

   Desc_t desc;
   krb5_data in;
   krb5_data enc;
   Int_t rc;
   in.data = const_cast<char*>(buf);
   in.length = length;

   switch (type) {
   case kNone:
      enc.data = in.data;
      enc.length = in.length;
      break;
   case kSafe:
      rc = krb5_mk_safe(fgContext, fAuthContext, &in, &enc, 0);
      break;
   case kPriv:
      rc = krb5_mk_priv(fgContext, fAuthContext, &in, &enc, 0);
      break;
   default:
      Error("BlockWrite","unknown encoding type (%d)", type);
      return -1;
   }

   desc.fLength = htons(enc.length);
   desc.fType = htons(type);

   Int_t fd = fSocket->GetDescriptor();
   rc = krb5_net_write(fgContext, fd, (char *)&desc, sizeof(desc));
   if (rc <= 0) {
      Error("BlockWrite","writing descriptor (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   rc = krb5_net_write(fgContext, fd, (char *)enc.data, enc.length);
   if (rc <= 0) {
      Error("BlockWrite","writing data (%d), %s",
            rc, error_message(rc));
      return -1;
   }

   if (type != kNone) free(enc.data);

   return rc;
}
<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#include <cmath>
#include "Effects.hpp"
#include "Audio.hpp"
#include "scene/Actor.hpp"
#include "math/MathUtils.hpp"
#include "smbPitchShift.hpp"

namespace ouzel
{
    namespace audio
    {
        class DelayProcessor final: public mixer::Processor
        {
        public:
            DelayProcessor(float initDelay):
                delay(initDelay)
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                uint32_t delayFrames = static_cast<uint32_t>(delay * sampleRate);
                uint32_t bufferFrames = frames + delayFrames;

                buffer.resize(bufferFrames * channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    float* bufferChannel = &buffer[channel * bufferFrames];
                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame + delayFrames] += outputChannel[frame];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = bufferChannel[frame];

                    // erase frames from beginning
                    for (uint32_t frame = 0; frame < bufferFrames - frames; ++frame)
                        bufferChannel[frame] = bufferChannel[frame + frames];

                    for (uint32_t frame = bufferFrames - frames; frame < bufferFrames; ++frame)
                        bufferChannel[frame] = 0.0F;
                }
            }

        private:
            float delay = 0.0F;
            std::vector<float> buffer;
        };

        Delay::Delay(Audio& initAudio, float initDelay):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new DelayProcessor(initDelay)))),
            delay(initDelay)
        {
        }

        Delay::~Delay()
        {
        }

        void Delay::setDelay(float newDelay)
        {
            delay = newDelay;
        }

        class GainProcessor final: public mixer::Processor
        {
        public:
            GainProcessor(float initGain = 0.0F):
                gain(initGain),
                gainFactor(pow(10.0F, initGain / 20.0F))
            {
            }

            void process(uint32_t, uint16_t, uint32_t,
                         std::vector<float>& samples) override
            {
                for (float& sample : samples)
                    sample *= gainFactor;
            }

            void setGain(float newGain)
            {
                gain = newGain;
                gainFactor = pow(10.0F, gain / 20.0F);
            }

        private:
            float gain = 0.0F;
            float gainFactor = 1.0F;
        };

        Gain::Gain(Audio& initAudio, float initGain):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new GainProcessor(initGain)))),
            gain(initGain)
        {
        }

        Gain::~Gain()
        {
        }

        void Gain::setGain(float newGain)
        {
            gain = newGain;

            audio.updateProcessor(processorId, [newGain](mixer::Object* node) {
                GainProcessor* gainProcessor = static_cast<GainProcessor*>(node);
                gainProcessor->setGain(newGain);
            });
        }

        class PannerProcessor final: public mixer::Processor
        {
        public:
            PannerProcessor()
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
            }

            void setPosition(const Vector3F& newPosition)
            {
                position = newPosition;
            }

            void setRolloffFactor(float newRolloffFactor)
            {
                rolloffFactor = newRolloffFactor;
            }

            void setMinDistance(float newMinDistance)
            {
                minDistance = newMinDistance;
            }

            void setMaxDistance(float newMaxDistance)
            {
                maxDistance = newMaxDistance;
            }

        private:
            Vector3F position;
            float rolloffFactor = 1.0F;
            float minDistance = 1.0F;
            float maxDistance = FLT_MAX;
        };

        Panner::Panner(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new PannerProcessor()))),
            scene::Component(scene::Component::SOUND)
        {
        }

        Panner::~Panner()
        {
        }

        void Panner::setPosition(const Vector3F& newPosition)
        {
            position = newPosition;

            audio.updateProcessor(processorId, [newPosition](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setPosition(newPosition);
            });
        }

        void Panner::setRolloffFactor(float newRolloffFactor)
        {
            rolloffFactor = newRolloffFactor;

            audio.updateProcessor(processorId, [newRolloffFactor](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setRolloffFactor(newRolloffFactor);
            });
        }

        void Panner::setMinDistance(float newMinDistance)
        {
            minDistance = newMinDistance;

            audio.updateProcessor(processorId, [newMinDistance](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setMinDistance(newMinDistance);
            });
        }

        void Panner::setMaxDistance(float newMaxDistance)
        {
            maxDistance = newMaxDistance;

            audio.updateProcessor(processorId, [newMaxDistance](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setMaxDistance(newMaxDistance);
            });
        }

        void Panner::updateTransform()
        {
            setPosition(actor->getWorldPosition());
        }

        static constexpr float MIN_PITCH = 0.5F;
        static constexpr float MAX_PITCH = 2.0F;

        class PitchProcessor final: public mixer::Processor
        {
        public:
            PitchProcessor(float initPitch):
                pitch(clamp(initPitch, MIN_PITCH, MAX_PITCH))
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                channelSamples.resize(frames);
                pitchShift.resize(channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    pitchShift[channel].process(pitch, frames, 1024, 4, static_cast<float>(sampleRate),
                                                samples.data() + channel * frames,
                                                channelSamples.data());

                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = channelSamples[frame];
                }
            }

            void setPitch(float newPitch)
            {
                pitch = clamp(newPitch, MIN_PITCH, MAX_PITCH);
            }

        private:
            float pitch = 1.0f;
            std::vector<float> channelSamples;
            std::vector<smb::PitchShift> pitchShift;
        };

        Pitch::Pitch(Audio& initAudio, float initPitch):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new PitchProcessor(initPitch)))),
            pitch(initPitch)
        {
        }

        Pitch::~Pitch()
        {
        }

        void Pitch::setPitch(float newPitch)
        {
            pitch = newPitch;

            audio.updateProcessor(processorId, [newPitch](mixer::Object* node) {
                PitchProcessor* pitchProcessor = static_cast<PitchProcessor*>(node);
                pitchProcessor->setPitch(newPitch);
            });
        }

        class ReverbProcessor final: public mixer::Processor
        {
        public:
            ReverbProcessor(float initDelay, float initDecay):
                delay(initDelay), decay(initDecay)
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                uint32_t delayFrames = static_cast<uint32_t>(delay * sampleRate);
                uint32_t bufferFrames = frames + delayFrames;

                buffer.resize(bufferFrames * channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    float* bufferChannel = &buffer[channel * bufferFrames];
                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame] += outputChannel[frame];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame + delayFrames] += bufferChannel[frame] * decay;

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = bufferChannel[frame];

                    // erase frames from beginning
                    for (uint32_t frame = 0; frame < bufferFrames - frames; ++frame)
                        bufferChannel[frame] = bufferChannel[frame + frames];

                    for (uint32_t frame = bufferFrames - frames; frame < bufferFrames; ++frame)
                        bufferChannel[frame] = 0.0F;
                }
            }

        private:
            float delay = 0.1F;
            float decay = 0.5F;
            std::vector<float> buffer;
        };

        Reverb::Reverb(Audio& initAudio, float initDelay, float initDecay):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new ReverbProcessor(initDelay, initDecay)))),
            delay(initDelay),
            decay(initDecay)
        {
        }

        Reverb::~Reverb()
        {
        }

        LowPass::LowPass(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>()))
        {
        }

        LowPass::~LowPass()
        {
        }

        HighPass::HighPass(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>()))
        {
        }

        HighPass::~HighPass()
        {
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Implement the delay setter for the Delay effect<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#include <cmath>
#include "Effects.hpp"
#include "Audio.hpp"
#include "scene/Actor.hpp"
#include "math/MathUtils.hpp"
#include "smbPitchShift.hpp"

namespace ouzel
{
    namespace audio
    {
        class DelayProcessor final: public mixer::Processor
        {
        public:
            DelayProcessor(float initDelay):
                delay(initDelay)
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                uint32_t delayFrames = static_cast<uint32_t>(delay * sampleRate);
                uint32_t bufferFrames = frames + delayFrames;

                buffer.resize(bufferFrames * channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    float* bufferChannel = &buffer[channel * bufferFrames];
                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame + delayFrames] += outputChannel[frame];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = bufferChannel[frame];

                    // erase frames from beginning
                    for (uint32_t frame = 0; frame < bufferFrames - frames; ++frame)
                        bufferChannel[frame] = bufferChannel[frame + frames];

                    for (uint32_t frame = bufferFrames - frames; frame < bufferFrames; ++frame)
                        bufferChannel[frame] = 0.0F;
                }
            }

            void setDelay(float newDelay)
            {
                delay = newDelay;
            }

        private:
            float delay = 0.0F;
            std::vector<float> buffer;
        };

        Delay::Delay(Audio& initAudio, float initDelay):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new DelayProcessor(initDelay)))),
            delay(initDelay)
        {
        }

        Delay::~Delay()
        {
        }

        void Delay::setDelay(float newDelay)
        {
            delay = newDelay;

            audio.updateProcessor(processorId, [newDelay](mixer::Object* node) {
                DelayProcessor* delayProcessor = static_cast<DelayProcessor*>(node);
                delayProcessor->setDelay(newDelay);
            });
        }

        class GainProcessor final: public mixer::Processor
        {
        public:
            GainProcessor(float initGain = 0.0F):
                gain(initGain),
                gainFactor(pow(10.0F, initGain / 20.0F))
            {
            }

            void process(uint32_t, uint16_t, uint32_t,
                         std::vector<float>& samples) override
            {
                for (float& sample : samples)
                    sample *= gainFactor;
            }

            void setGain(float newGain)
            {
                gain = newGain;
                gainFactor = pow(10.0F, gain / 20.0F);
            }

        private:
            float gain = 0.0F;
            float gainFactor = 1.0F;
        };

        Gain::Gain(Audio& initAudio, float initGain):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new GainProcessor(initGain)))),
            gain(initGain)
        {
        }

        Gain::~Gain()
        {
        }

        void Gain::setGain(float newGain)
        {
            gain = newGain;

            audio.updateProcessor(processorId, [newGain](mixer::Object* node) {
                GainProcessor* gainProcessor = static_cast<GainProcessor*>(node);
                gainProcessor->setGain(newGain);
            });
        }

        class PannerProcessor final: public mixer::Processor
        {
        public:
            PannerProcessor()
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
            }

            void setPosition(const Vector3F& newPosition)
            {
                position = newPosition;
            }

            void setRolloffFactor(float newRolloffFactor)
            {
                rolloffFactor = newRolloffFactor;
            }

            void setMinDistance(float newMinDistance)
            {
                minDistance = newMinDistance;
            }

            void setMaxDistance(float newMaxDistance)
            {
                maxDistance = newMaxDistance;
            }

        private:
            Vector3F position;
            float rolloffFactor = 1.0F;
            float minDistance = 1.0F;
            float maxDistance = FLT_MAX;
        };

        Panner::Panner(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new PannerProcessor()))),
            scene::Component(scene::Component::SOUND)
        {
        }

        Panner::~Panner()
        {
        }

        void Panner::setPosition(const Vector3F& newPosition)
        {
            position = newPosition;

            audio.updateProcessor(processorId, [newPosition](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setPosition(newPosition);
            });
        }

        void Panner::setRolloffFactor(float newRolloffFactor)
        {
            rolloffFactor = newRolloffFactor;

            audio.updateProcessor(processorId, [newRolloffFactor](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setRolloffFactor(newRolloffFactor);
            });
        }

        void Panner::setMinDistance(float newMinDistance)
        {
            minDistance = newMinDistance;

            audio.updateProcessor(processorId, [newMinDistance](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setMinDistance(newMinDistance);
            });
        }

        void Panner::setMaxDistance(float newMaxDistance)
        {
            maxDistance = newMaxDistance;

            audio.updateProcessor(processorId, [newMaxDistance](mixer::Object* node) {
                PannerProcessor* pannerProcessor = static_cast<PannerProcessor*>(node);
                pannerProcessor->setMaxDistance(newMaxDistance);
            });
        }

        void Panner::updateTransform()
        {
            setPosition(actor->getWorldPosition());
        }

        static constexpr float MIN_PITCH = 0.5F;
        static constexpr float MAX_PITCH = 2.0F;

        class PitchProcessor final: public mixer::Processor
        {
        public:
            PitchProcessor(float initPitch):
                pitch(clamp(initPitch, MIN_PITCH, MAX_PITCH))
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                channelSamples.resize(frames);
                pitchShift.resize(channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    pitchShift[channel].process(pitch, frames, 1024, 4, static_cast<float>(sampleRate),
                                                samples.data() + channel * frames,
                                                channelSamples.data());

                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = channelSamples[frame];
                }
            }

            void setPitch(float newPitch)
            {
                pitch = clamp(newPitch, MIN_PITCH, MAX_PITCH);
            }

        private:
            float pitch = 1.0f;
            std::vector<float> channelSamples;
            std::vector<smb::PitchShift> pitchShift;
        };

        Pitch::Pitch(Audio& initAudio, float initPitch):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new PitchProcessor(initPitch)))),
            pitch(initPitch)
        {
        }

        Pitch::~Pitch()
        {
        }

        void Pitch::setPitch(float newPitch)
        {
            pitch = newPitch;

            audio.updateProcessor(processorId, [newPitch](mixer::Object* node) {
                PitchProcessor* pitchProcessor = static_cast<PitchProcessor*>(node);
                pitchProcessor->setPitch(newPitch);
            });
        }

        class ReverbProcessor final: public mixer::Processor
        {
        public:
            ReverbProcessor(float initDelay, float initDecay):
                delay(initDelay), decay(initDecay)
            {
            }

            void process(uint32_t frames, uint16_t channels, uint32_t sampleRate,
                         std::vector<float>& samples) override
            {
                uint32_t delayFrames = static_cast<uint32_t>(delay * sampleRate);
                uint32_t bufferFrames = frames + delayFrames;

                buffer.resize(bufferFrames * channels);

                for (uint16_t channel = 0; channel < channels; ++channel)
                {
                    float* bufferChannel = &buffer[channel * bufferFrames];
                    float* outputChannel = &samples[channel * frames];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame] += outputChannel[frame];

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        bufferChannel[frame + delayFrames] += bufferChannel[frame] * decay;

                    for (uint32_t frame = 0; frame < frames; ++frame)
                        outputChannel[frame] = bufferChannel[frame];

                    // erase frames from beginning
                    for (uint32_t frame = 0; frame < bufferFrames - frames; ++frame)
                        bufferChannel[frame] = bufferChannel[frame + frames];

                    for (uint32_t frame = bufferFrames - frames; frame < bufferFrames; ++frame)
                        bufferChannel[frame] = 0.0F;
                }
            }

        private:
            float delay = 0.1F;
            float decay = 0.5F;
            std::vector<float> buffer;
        };

        Reverb::Reverb(Audio& initAudio, float initDelay, float initDecay):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>(new ReverbProcessor(initDelay, initDecay)))),
            delay(initDelay),
            decay(initDecay)
        {
        }

        Reverb::~Reverb()
        {
        }

        LowPass::LowPass(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>()))
        {
        }

        LowPass::~LowPass()
        {
        }

        HighPass::HighPass(Audio& initAudio):
            Effect(initAudio,
                   initAudio.initProcessor(std::unique_ptr<mixer::Processor>()))
        {
        }

        HighPass::~HighPass()
        {
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>