Commits

Ruslan Osmanov committed 49fb02c Merge

Merge branch 'develop'

Comments (0)

Files changed (41)

     NO_DEFAULT_PATH)
 ...
 
+
+
 FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient_r
     PATHS
     /usr/lib/mysql
     NO_DEFAULT_PATH)
+
+OR rather
+
+FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient_r
+    PATHS
+    /usr/lib64/mysql
+    NO_DEFAULT_PATH)
+
+for 64-bit arch. See https://github.com/facebook/hhvm/issues/1531
 ```
 
+
 Building with debug support:
 ```
 ./configure -DCMAKE_BUILD_TYPE=Debug
+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/Event.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+#define SET_FD(__what, __fd, __fdvar, __ret)                       \
+  do {                                                             \
+    if ((__what) & EV_SIGNAL) {                                    \
+      (__fd) = static_cast<evutil_socket_t>((__fdvar).toInt64());  \
+      if (!check_signum((__fd))) {                                 \
+        raise_warning("invalid signal passed");                    \
+        return __ret;                                              \
+      }                                                            \
+    } else if ((__what) & EV_TIMEOUT) {                            \
+      fd = -1;                                                     \
+    } else {                                                       \
+      (__fd) = Event::varToFd((__fdvar));                          \
+      if ((__fd) < 0) {                                            \
+        raise_warning("invalid socket or file descriptor passed"); \
+        return __ret;                                              \
+      }                                                            \
+    }                                                              \
+  } while (0)
+
+#define CHECK_PENDING(e, __ret)                    \
+  do {                                             \
+    if ((e)->isPending()) {                        \
+      raise_warning("can't modify pending event"); \
+      return __ret;                                \
+    }                                              \
+  } while (0)
+
+
+
+ALWAYS_INLINE
+static bool check_signum(evutil_socket_t fd) {
+  return (fd >= 0 && fd < NSIG);
+}
+
+static void event_callback(evutil_socket_t fd, short what, void* arg) {
+  assert(arg);
+  Event* rc = static_cast<Event*>(arg);
+  assert(!rc->isInvalid());
+  rc->callback(fd, what);
+}
+
+static void timer_callback(evutil_socket_t fd, short what, void* arg) {
+  assert(arg);
+  Event* rc = static_cast<Event*>(arg);
+  assert(!rc->isInvalid());
+  rc->callback();
+}
+
+static void signal_callback(evutil_socket_t signum, short what, void* arg) {
+  assert(arg);
+  Event* rc = static_cast<Event*>(arg);
+  assert(!rc->isInvalid());
+  rc->callback(signum);
+}
+
+evutil_socket_t Event::varToFd(const Variant& var) {
+  auto type = var.getType();
+
+  switch (type) {
+    case KindOfResource:
+      try {
+        Socket* sock = var.toResource().getTyped<Socket>();
+        if (!sock) {
+          break;
+        }
+        if (!sock->valid()) {
+          break;
+        }
+
+        return static_cast<evutil_socket_t>(sock->fd());
+      } catch (const InvalidObjectTypeException& e) {
+        raise_warning("%s", e.what());
+      }
+      break;
+    case KindOfInt64:
+      return static_cast<evutil_socket_t>(var.toInt64());
+    default:
+      return -1;
+  }
+
+  return -1;
+}
+
+
+Event::Event()
+: m_ptr(nullptr), m_cb(null_variant), m_cbArg(null_variant) {}
+
+
+Event::Event(struct event_base* base, evutil_socket_t fd, short what, const Variant& cb, const Variant& arg)
+: m_cb(cb), m_cbArg(arg) {
+  assert(base);
+
+  if (what & EV_SIGNAL) {
+    m_ptr = ::evsignal_new(base, fd, signal_callback, static_cast<void*>(this));
+  } else if (what & EV_TIMEOUT) {
+    m_ptr = ::evtimer_new(base, timer_callback, static_cast<void*>(this));
+  } else {
+    m_ptr = ::event_new(base, fd, what, event_callback, static_cast<void*>(this));
+  }
+
+  if (!m_ptr) {
+    raise_error("event_new failed");
+    return;
+  }
+}
+
+void Event::free() {
+  if (m_ptr) {
+    // No need in ::event_del(m_ptr) since
+    // ::event_free makes event non-pending internally
+    ::event_free(m_ptr);
+    m_ptr = nullptr;
+  }
+}
+
+
+Event::~Event() {
+  free();
+}
+
+
+void Event::sweep() {
+  free();
+}
+
+Event* Event::get(Object obj) {
+  return getInternalResource<Event>(obj, s_Event);
+}
+
+Object Event::wrap() {
+  return newInstance(s_Event.get());
+}
+
+bool Event::isPending() {
+  return m_ptr
+    ? ::event_pending(m_ptr, EV_READ | EV_WRITE | EV_SIGNAL | EV_TIMEOUT, NULL)
+    : false;
+}
+
+void Event::callback(evutil_socket_t fd, short what) const {
+  if (MemoryManager::sweeping()) return;
+  vm_call_user_func(m_cb, make_packed_array(fd, what, m_cbArg));
+}
+
+void Event::callback() const {
+  if (MemoryManager::sweeping()) return;
+  vm_call_user_func(m_cb, make_packed_array(m_cbArg));
+}
+
+void Event::callback(evutil_socket_t fd) const {
+  if (MemoryManager::sweeping()) return;
+  vm_call_user_func(m_cb, make_packed_array(fd, m_cbArg));
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// Event PHP class
+
+static void HHVM_METHOD(Event, __constructor, const Object& baseObj, const Variant& fdvar, int64_t what, const Variant& cb, const Variant& arg/* = null_variant */) {
+  evutil_socket_t fd;
+
+  HPHP_EVENT_BASE_GET(base, baseObj, /* void */);
+  assert(base);
+
+  SET_FD(what, fd, fdvar, /* void */);
+
+  HPHP_EVENT_CHECK_CALLABLE(cb, /* void */);
+
+  auto rc = NEWOBJ(Event)(base->getPtr(), fd, what, cb, arg);
+  this_->o_set(s__rc, Resource(rc), s_Event.get());
+}
+
+static bool HHVM_METHOD(Event, add, double timeout = -1.0) {
+  HPHP_EVENT_GET(event, this_, false);
+
+  if (timeout == -1.0) {
+    return (::event_add(event->getPtr(), NULL) == 0);
+  }
+
+  struct timeval tv;
+  HPHP_EVENT_TIMEVAL_SET(tv, timeout);
+
+  return (::event_add(event->getPtr(), &tv) == 0);
+}
+
+static bool HHVM_METHOD(Event, del) {
+  HPHP_EVENT_GET(event, this_, false);
+  return (::event_del(event->getPtr()) == 0);
+}
+
+static void HHVM_METHOD(Event, free) {
+  HPHP_EVENT_GET(event, this_, /* void */);
+  event->free();
+}
+
+static Array HHVM_STATIC_METHOD(Event, getSupportedMethods) {
+  const char **methods = ::event_get_supported_methods();
+  Array a;
+
+  for (int i = 0; methods[i] != NULL; ++i) {
+    a.add(i, methods[i]);
+  }
+
+  return a;
+}
+
+static bool HHVM_METHOD(Event, pending, int64_t flags) {
+  HPHP_EVENT_GET(event, this_, false);
+
+  return (::event_pending(event->getPtr(), flags, NULL));
+}
+
+static bool HHVM_METHOD(Event, set, const Object& baseObj, const Variant& fdvar,
+    int64_t what /*= -1*/,
+    const Variant& cb /*= null_variant*/,
+    const Variant& arg /*= null_variant*/) {
+  evutil_socket_t fd;
+
+  SET_FD(what, fd, fdvar, false);
+
+  HPHP_EVENT_CHECK_CALLABLE(cb, false);
+  HPHP_EVENT_GET(event, this_, false);
+
+  if (event->isPending()) {
+    raise_warning("can't modify pending event");
+    return false;
+  }
+
+  HPHP_EVENT_BASE_GET(base, baseObj, false);
+  // XXX check if a signum bound to different event bases
+
+  event->set(cb, arg);
+
+  struct event_base* basePtr = base->getPtr();
+  ::event_get_assignment(event->getPtr(), &basePtr,
+      (fd >= 0 ? NULL : &fd),
+      reinterpret_cast<short*>(what == -1 ? &what : NULL),
+      NULL /* ignore old callback */ ,
+      NULL /* ignore old callback argument */);
+
+  return (::event_assign(event->getPtr(), base->getPtr(),
+        fd, what, event_callback, static_cast<void*>(event)) == 0);
+}
+
+static bool HHVM_METHOD(Event, setPriority, int64_t priority) {
+  HPHP_EVENT_GET(event, this_, false);
+  return (::event_priority_set(event->getPtr(), priority) == 0);
+}
+
+static bool HHVM_METHOD(Event, setTimer, const Object& baseObj,
+    const Variant& cb, const Variant& arg/* = null_variant*/) {
+
+  HPHP_EVENT_GET(event, this_, false);
+  CHECK_PENDING(event, false);
+  HPHP_EVENT_CHECK_CALLABLE(cb, false);
+  HPHP_EVENT_BASE_GET(base, baseObj, false);
+
+  event->set(cb, arg);
+
+  return (::evtimer_assign(event->getPtr(), base->getPtr(),
+        timer_callback, static_cast<void*>(event)) == 0);
+}
+
+static Object HHVM_STATIC_METHOD(Event, signal,
+    const Object& baseObj, int64_t signum, const Variant& cb, const Variant& arg /* = null_variant */) {
+  HPHP_EVENT_BASE_GET(base, baseObj, null_object);
+  HPHP_EVENT_CHECK_CALLABLE(cb, null_object);
+
+  auto rc = NEWOBJ(Event)(base->getPtr(),
+      static_cast<evutil_socket_t>(signum),
+      EV_SIGNAL | EV_PERSIST, cb, arg);
+  return rc->wrap();
+}
+
+static Object HHVM_STATIC_METHOD(Event, timer,
+    const Object& baseObj, const Variant& cb, const Variant& arg /* = null_variant */) {
+  HPHP_EVENT_BASE_GET(base, baseObj, null_object);
+  HPHP_EVENT_CHECK_CALLABLE(cb, null_object);
+
+  auto rc = NEWOBJ(Event)(base->getPtr(), -1, EV_TIMEOUT | EV_PERSIST, cb, arg);
+  return rc->wrap();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+#define REG_INT_CONST(v) \
+  Native::registerClassConstant<KindOfInt64>(s_Event.get(), \
+      makeStaticString(#v), EV_ ## v)
+
+#define REG_NAMED_INT_CONST(v, val) \
+  Native::registerClassConstant<KindOfInt64>(s_Event.get(), \
+      makeStaticString(#v), (val))
+
+void EventExtension::_initEventClass() {
+  REG_INT_CONST(ET);
+  REG_INT_CONST(PERSIST);
+  REG_INT_CONST(READ);
+  REG_INT_CONST(WRITE);
+  REG_INT_CONST(SIGNAL);
+  REG_INT_CONST(TIMEOUT);
+  REG_NAMED_INT_CONST(ALL_TYPES, EV_TIMEOUT | EV_READ | EV_WRITE | EV_SIGNAL | EV_PERSIST | EV_ET);
+
+  HHVM_ME(Event, __constructor);
+  HHVM_ME(Event, add);
+  HHVM_ME(Event, del);
+  HHVM_ME(Event, free);
+  HHVM_STATIC_ME(Event, getSupportedMethods);
+  HHVM_ME(Event, pending);
+  HHVM_ME(Event, set);
+  HHVM_ME(Event, setPriority);
+  HHVM_ME(Event, setTimer);
+  HHVM_STATIC_ME(Event, signal);
+  HHVM_STATIC_ME(Event, timer);
+}
+
+#undef REG_INT_CONST
+#undef REG_NAMED_INT_CONST
+
+#undef SET_FD
+
+} // namespace HPHP
+
+// vim: et ts=2 sts=2 sw=2
+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef incl_HPHP_CLASSES_EVENT_H
+#define incl_HPHP_CLASSES_EVENT_H
+
+#include "ext_event.h"
+#include "hphp/runtime/ext/ext_function.h"
+#include "api/EventBase.h"
+
+#define HPHP_EVENT_SET_FD(__fd, __fdvar, __ret)                \
+do {                                                           \
+  (__fd) = Event::varToFd((__fdvar));                          \
+  if ((__fd) < 0) {                                            \
+    raise_warning("invalid socket or file descriptor passed"); \
+    return __ret;                                              \
+  }                                                            \
+} while (0)
+
+namespace HPHP {
+
+class Event: public EventResourceData {
+  DECLARE_RESOURCE_ALLOCATION(Event);
+  CLASSNAME_IS("Event");
+  const String& o_getClassNameHook() const override { return classnameof(); }
+
+  private:
+    struct event* m_ptr = nullptr;
+    Variant m_cb;
+    Variant m_cbArg;
+
+  public:
+    Event();
+    explicit Event(struct event_base* base, evutil_socket_t fd, short what, const Variant& cb, const Variant& arg);
+    virtual ~Event();
+
+    Object wrap();
+    static Event* get(Object obj);
+    bool isValid() const { return m_ptr; }
+
+    static evutil_socket_t varToFd(const Variant& var);
+    inline struct event* getPtr() const { return m_ptr; }
+    inline void free();
+    inline bool isPending();
+    inline void set(const Variant& cb, const Variant& arg) {
+      m_cb = cb;
+      m_cbArg = arg;
+    }
+    inline void callback(evutil_socket_t fd, short what) const;
+    inline void callback() const;
+    inline void callback(evutil_socket_t fd) const;
+};
+
+} // namespace HPHP
+
+#endif // incl_HPHP_CLASSES_EVENT_H
+
+// vim: et ts=2 sts=2 sw=2

api/EventBase.cpp

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/EventBase.h"
+#include "src/EventRequestData.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+IMPLEMENT_REQUEST_LOCAL(EventRequestData, EventBase::m_tlsRequestData);
+
+
+void EventBase::_initRequestData() {
+  // Trigger request init handler to setup/configure Libevent and OpenSSL.
+  // ```
+  // Before using any of the functions in the library, you must call
+  // event_init() or event_base_new() to perform one-time initialization of the
+  // libevent library.
+  // ```
+  //    See <http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/>.
+  //
+  // Thus, no Event API could be run until an EventBase object is instantiated.
+  // So we can be sure that Libevent and OpenSSL are initialized.
+  m_tlsRequestData.get();
+}
+
+
+EventBase::EventBase() {
+  _initRequestData();
+
+  m_ptr = ::event_base_new();
+  if (!m_ptr) {
+    raise_error("event_base_new failed");
+  }
+}
+
+
+EventBase::EventBase(struct event_config* cfg) {
+  _initRequestData();
+
+  assert(cfg);
+  m_ptr = ::event_base_new_with_config(cfg);
+  if (!m_ptr) {
+    raise_error("event_base_new_with_config failed");
+  }
+}
+
+
+void EventBase::_free() {
+  if (m_ptr) {
+    ::event_base_free(m_ptr);
+    m_ptr = nullptr;
+  }
+}
+
+
+void EventBase::sweep()
+{
+  _free();
+}
+
+
+EventBase::~EventBase() {
+  _free();
+}
+
+EventBase* EventBase::get(Object obj) {
+  return getInternalResource<EventBase>(obj, s_EventBase);
+}
+
+/////////////////////////////////////////////////////////////////////////
+// EventBase PHP class
+
+static void HHVM_METHOD(EventBase, __construct, const Variant& cfg /* = null_variant */) {
+  if (cfg.isNull()) {
+    auto rc = NEWOBJ(EventBase)();
+    this_->o_set(s__rc, Resource(rc), s_EventBase.get());
+  } else {
+    HPHP_EVENT_CONFIG_GET(rc_cfg, cfg.toObject(), /* void */);
+    auto rc = NEWOBJ(EventBase)(rc_cfg->getPtr());
+    this_->o_set(s__rc, Resource(rc), s_EventBase.get());
+  }
+}
+
+static bool HHVM_METHOD(EventBase, dispatch) {
+  JIT::VMRegAnchor _;
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_base_dispatch(rc->getPtr()) != -1);
+}
+
+static bool HHVM_METHOD(EventBase, exitLoop, double timeout = -1.0) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+
+  if (timeout == -1.0) {
+    return (::event_base_loopexit(rc->getPtr(), NULL) == 0);
+  }
+
+  struct timeval tv;
+  HPHP_EVENT_TIMEVAL_SET(tv, timeout);
+  return (::event_base_loopexit(rc->getPtr(), &tv) == 0);
+}
+
+static int64_t HHVM_METHOD(EventBase, getFeatures) {
+  HPHP_EVENT_BASE_GET(rc, this_, 0);
+  return (::event_base_get_features(rc->getPtr()));
+}
+
+static String HHVM_METHOD(EventBase, getMethod) {
+  HPHP_EVENT_BASE_GET(rc, this_, null_string);
+  return String(::event_base_get_method(rc->getPtr()));
+}
+
+static double HHVM_METHOD(EventBase, getTimeOfDayCached) {
+  struct timeval tv;
+
+  HPHP_EVENT_BASE_GET(rc, this_, 0.0);
+  return (::event_base_gettimeofday_cached(rc->getPtr(), &tv)
+      ? 0.0 : HPHP_EVENT_TIMEVAL_TO_DOUBLE(tv));
+}
+
+static bool HHVM_METHOD(EventBase, gotExit) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_base_got_exit(rc->getPtr()));
+}
+
+static bool HHVM_METHOD(EventBase, gotStop) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_base_got_break(rc->getPtr()));
+}
+
+static bool HHVM_METHOD(EventBase, loop, int64_t flags = -1) {
+  JIT::VMRegAnchor _;
+
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+
+  if (flags == -1) {
+    if (::event_base_dispatch(rc->getPtr()) == -1) {
+      return false;
+    }
+  } else if (::event_base_loop(rc->getPtr(), flags) == -1) {
+    return false;
+  }
+  return true;
+}
+
+static bool HHVM_METHOD(EventBase, priorityInit, int64_t priorities) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_base_priority_init(rc->getPtr(), priorities) == 0);
+}
+
+static bool HHVM_METHOD(EventBase, reInit) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_reinit(rc->getPtr()) == 0);
+}
+
+static bool HHVM_METHOD(EventBase, stop) {
+  HPHP_EVENT_BASE_GET(rc, this_, false);
+  return (::event_base_loopbreak(rc->getPtr()) == 0);
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+
+#define REG_INT_CONST(v, vorg) \
+  Native::registerClassConstant<KindOfInt64>(s_EventBase.get(), \
+      makeStaticString(#v), (vorg))
+
+void EventExtension::_initEventBaseClass() {
+  REG_INT_CONST(LOOP_ONCE, EVLOOP_ONCE);
+  REG_INT_CONST(LOOP_NONBLOCK, EVLOOP_NONBLOCK);
+
+  // Runtime flags of event base usually passed to event_config_set_flag
+  REG_INT_CONST(NOLOCK, EVENT_BASE_FLAG_NOLOCK);
+  REG_INT_CONST(STARTUP_IOCP, EVENT_BASE_FLAG_STARTUP_IOCP);
+  REG_INT_CONST(NO_CACHE_TIME, EVENT_BASE_FLAG_NO_CACHE_TIME);
+  REG_INT_CONST(EPOLL_USE_CHANGELIST, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
+#ifdef EVENT_BASE_FLAG_IGNORE_ENV
+  REG_INT_CONST(IGNORE_ENV, IGNORE_ENV);
+#endif
+#ifdef EVENT_BASE_FLAG_PRECISE_TIMER
+  REG_INT_CONST(PRECISE_TIMER, PRECISE_TIMER);
+#endif
+
+  HHVM_ME(EventBase, __construct);
+  HHVM_ME(EventBase, dispatch);
+  HHVM_ME(EventBase, exitLoop);
+  HHVM_ME(EventBase, getFeatures);
+  HHVM_ME(EventBase, getMethod);
+  HHVM_ME(EventBase, getTimeOfDayCached);
+  HHVM_ME(EventBase, gotExit);
+  HHVM_ME(EventBase, gotStop);
+  HHVM_ME(EventBase, loop);
+  HHVM_ME(EventBase, priorityInit);
+  HHVM_ME(EventBase, reInit);
+  HHVM_ME(EventBase, stop);
+}
+
+#undef REG_INT_CONST
+
+} // namespace HPHP
+
+// vim: et ts=2 sts=2 sw=2
+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef incl_HPHP_CLASSES_EVENT_BASE_H
+#define incl_HPHP_CLASSES_EVENT_BASE_H
+
+#include "ext_event.h"
+#include "api/EventConfig.h"
+#include "src/EventRequestData.h"
+
+namespace HPHP {
+
+class EventBase: public EventResourceData {
+  DECLARE_RESOURCE_ALLOCATION(EventBase);
+  CLASSNAME_IS("EventBase");
+  const String& o_getClassNameHook() const override { return classnameof(); }
+
+  protected:
+    struct event_base* m_ptr = nullptr;
+    // RequestLocal implements some operators `->` and `*`,
+    // which call RequestLocal::get() method. The `get()` method, in turn, (lazily) calls
+    // `requestInit()` and registers `requestShutdown()`.
+    // So the first time we access the request-local variable, we implicitly trigger
+    // `requestInit()`.
+    inline void _initRequestData();
+    inline void _free();
+
+  public:
+    EventBase();
+    EventBase(struct event_config* cfg);
+    virtual ~EventBase();
+
+    DECLARE_STATIC_REQUEST_LOCAL(EventRequestData, m_tlsRequestData);
+
+    static EventBase* get(Object obj);
+
+    bool isValid() const { return m_ptr; }
+    inline struct event_base* getPtr() const { return m_ptr; }
+};
+
+} // namespace HPHP
+
+#endif // incl_HPHP_CLASSES_EVENT_BASE_H
+
+// vim: et ts=2 sts=2 sw=2

api/EventBuffer.cpp

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/EventBuffer.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+#define VAR_FALSE Variant(false)
+
+
+EventBuffer::EventBuffer():
+  m_ptr(::evbuffer_new()),
+  m_owned(false)
+{}
+
+EventBuffer::EventBuffer(struct evbuffer* ptr):
+  m_ptr(ptr), m_owned(true) {}
+
+
+void EventBuffer::free() {
+  if (m_ptr && m_owned == false) {
+    ::evbuffer_free(m_ptr);
+    m_ptr = nullptr;
+  }
+}
+
+
+void EventBuffer::sweep() {
+  free();
+}
+
+
+EventBuffer::~EventBuffer() {
+  free();
+}
+
+
+EventBuffer* EventBuffer::get(Object obj) {
+  return getInternalResource<EventBuffer>(obj, s_EventBuffer);
+}
+
+Object EventBuffer::wrap() {
+  return newInstance(s_EventBuffer.get());
+}
+
+bool EventBuffer::setPos(struct evbuffer_ptr* ptr, const int64_t pos) {
+  if (pos < 0) {
+    return false;
+  }
+
+  if (::evbuffer_ptr_set(m_ptr, ptr, pos, ::EVBUFFER_PTR_SET) != -1) {
+    return true;
+  }
+
+  raise_warning("Failed to set position to %ld", pos);
+  return false;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// EventBuffer PHP class
+
+static void HHVM_METHOD(EventBuffer, __construct) {
+  auto rc = NEWOBJ(EventBuffer)();
+  this_->o_set(s__rc, Resource(rc), s_EventBuffer.get());
+}
+
+static bool HHVM_METHOD(EventBuffer, add, const String& s) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_add(buf->getPtr(), s.data(), s.length()) == 0);
+}
+
+static bool HHVM_METHOD(EventBuffer, addBuffer, const Object& srcObj) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  HPHP_EVENT_BUFFER_GET(src, srcObj, false);
+  return (::evbuffer_add_buffer(buf->getPtr(), src->getPtr()) == 0);
+}
+
+static int64_t HHVM_METHOD(EventBuffer, getLength) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, 0);
+  return ::evbuffer_get_length(buf->getPtr());
+}
+
+static int64_t HHVM_METHOD(EventBuffer, getContiguousSpace) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, 0);
+  return ::evbuffer_get_contiguous_space(buf->getPtr());
+}
+
+static int64_t HHVM_METHOD(EventBuffer, appendFrom, const Object& srcObj, int64_t len) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, 0);
+  HPHP_EVENT_BUFFER_GET(src, srcObj, 0);
+  return ::evbuffer_remove_buffer(src->getPtr(), buf->getPtr(), static_cast<size_t>(len));
+}
+
+static int64_t HHVM_METHOD(EventBuffer, copyout, VRefParam sref, int64_t max_bytes) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, 0);
+
+  char* data = new char[max_bytes + 1];
+  int64_t ret = ::evbuffer_copyout(buf->getPtr(), data, max_bytes);
+
+  if (ret > 0) {
+    sref = String(data, ret, CopyString);
+  } else {
+    sref = String();
+  }
+
+  delete data;
+
+  return ret;
+}
+
+static bool HHVM_METHOD(EventBuffer, drain, int64_t len) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_drain(buf->getPtr(), len) == 0);
+}
+
+static void HHVM_METHOD(EventBuffer, enableLocking) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, /* void */);
+  ::evbuffer_enable_locking(buf->getPtr(), NULL);
+}
+
+static bool HHVM_METHOD(EventBuffer, expand, int64_t len) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_expand(buf->getPtr(), (size_t) len) == 0);
+}
+
+static bool HHVM_METHOD(EventBuffer, freeze, bool at_front) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_freeze(buf->getPtr(), at_front) == 0);
+}
+
+static void HHVM_METHOD(EventBuffer, lock) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, /* void */);
+  ::evbuffer_lock(buf->getPtr());
+}
+
+static bool HHVM_METHOD(EventBuffer, prepend, const String& data) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_prepend(buf->getPtr(), data.data(), data.length()) == 0);
+}
+
+static bool HHVM_METHOD(EventBuffer, prependBuffer, const Object& srcObj) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  HPHP_EVENT_BUFFER_GET(src, srcObj, false);
+  return (::evbuffer_prepend_buffer(buf->getPtr(), src->getPtr()) == 0);
+}
+
+static Variant HHVM_METHOD(EventBuffer, pullup, int64_t size) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, null_variant);
+
+  unsigned char* mem = ::evbuffer_pullup(buf->getPtr(), size);
+  if (mem == NULL) {
+    return null_variant;
+  }
+
+  int64_t len = (int64_t) ::evbuffer_get_length(buf->getPtr());
+  if (size >=0 && size < len) {
+    len = size;
+  }
+
+  return Variant(String(reinterpret_cast<const char*>(mem), len, CopyString));
+}
+
+
+static Variant HHVM_METHOD(EventBuffer, read, int64_t max_bytes) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+
+  if (max_bytes <= 0) {
+    return VAR_FALSE;
+  }
+
+  char* data = (char *) malloc(sizeof(char) * max_bytes + 1);
+  auto num = ::evbuffer_remove(buf->getPtr(), data, max_bytes);
+
+  if (num > 0) {
+    return String(data, num, AttachString);
+  }
+  return VAR_FALSE;
+}
+
+static Variant HHVM_METHOD(EventBuffer, readFrom, const Variant& fdvar, int64_t howmuch) {
+  evutil_socket_t fd;
+
+  HPHP_EVENT_BUFFER_GET(buf, this_, null_string);
+  HPHP_EVENT_SET_FD(fd, fdvar, null_string);
+
+  int64_t ret = ::evbuffer_read(buf->getPtr(), fd, howmuch);
+  if (ret != -1) {
+    return ret;
+  }
+  return VAR_FALSE;
+}
+
+static Variant HHVM_METHOD(EventBuffer, readLine, int64_t eol_style) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, VAR_FALSE);
+
+  size_t len;
+  char* res = ::evbuffer_readln(buf->getPtr(), &len, static_cast<evbuffer_eol_style>(eol_style));
+  return res ? String(res, len, AttachString) : false;
+}
+
+static Variant HHVM_METHOD(EventBuffer, search, const String& what, int64_t start = -1, int64_t end = -1) {
+  struct evbuffer_ptr ptr_start, ptr_end, ptr_res;
+
+  HPHP_EVENT_BUFFER_GET(buf, this_, VAR_FALSE);
+
+  if (start != -1 && buf->setPos(&ptr_start, start) == false) {
+    start = -1;
+  }
+  if (end != -1 && (end > ::evbuffer_get_length(buf->getPtr()) ||
+        buf->setPos(&ptr_end, end) == false)) {
+    end = -1;
+  }
+
+  if (end != -1) {
+    ptr_res = ::evbuffer_search_range(buf->getPtr(), what.c_str(), static_cast<size_t>(what.length()),
+        (start != -1 ? &ptr_start : NULL), &ptr_end);
+  } else {
+    ptr_res = ::evbuffer_search(buf->getPtr(), what.c_str(), static_cast<size_t>(what.length()),
+        (start != -1 ? &ptr_start : NULL));
+  }
+
+  if (ptr_res.pos != -1) {
+    return ptr_res.pos;
+  }
+  return VAR_FALSE;
+}
+
+static Variant HHVM_METHOD(EventBuffer, searchEol, int64_t start = -1, int64_t eol_style = ::EVBUFFER_EOL_ANY) {
+  struct evbuffer_ptr ptr_start, ptr_res;
+
+  HPHP_EVENT_BUFFER_GET(buf, this_, VAR_FALSE);
+
+  if (start != -1 && buf->setPos(&ptr_start, start) == false) {
+    start = -1;
+  }
+
+  ptr_res = ::evbuffer_search_eol(buf->getPtr(),
+      (start != -1 ? &ptr_start : NULL),
+      NULL,
+      static_cast<evbuffer_eol_style>(eol_style));
+
+  if (ptr_res.pos != -1) {
+    return ptr_res.pos;
+  }
+  return VAR_FALSE;
+}
+
+static Variant HHVM_METHOD(EventBuffer, substr, int64_t start, int64_t length = -1) {
+  struct evbuffer_ptr    ptr;
+  struct evbuffer_iovec* pv;
+  int                    n_chunks;
+  long                   n_read   = 0;
+  int                    i;
+
+  HPHP_EVENT_BUFFER_GET(buf, this_, VAR_FALSE);
+
+  if (buf->setPos(&ptr, start) == false) {
+    return VAR_FALSE;
+  }
+
+  // Determine how many chunks we need
+  n_chunks = ::evbuffer_peek(buf->getPtr(), length, &ptr, NULL, 0);
+  // Allocate space for the chunks
+  pv = (struct evbuffer_iovec *) malloc(sizeof(struct evbuffer_iovec) * n_chunks);
+  // Fill up pv
+  n_chunks = ::evbuffer_peek(buf->getPtr(), length, &ptr, pv, n_chunks);
+
+  // Determine the size of the result string
+  for (i = 0; i < n_chunks; ++i) {
+    size_t len = pv[i].iov_len;
+
+    if (n_read + len > length) {
+      len = length - n_read;
+    }
+
+    n_read += len;
+  }
+
+  String s = String(n_read + 1, ReserveString);
+  char* ret = s.bufferSlice().ptr;
+
+  for (n_read = 0, i = 0; i < n_chunks; ++i) {
+    size_t len = pv[i].iov_len;
+
+    if (n_read + len > length) {
+      len = length - n_read;
+    }
+
+    ::memcpy(ret + n_read, pv[i].iov_base, len);
+
+    n_read += len;
+  }
+
+  ::free(pv);
+
+  ret[n_read] = '\0';
+  s.setSize(n_read);
+
+  return s;
+}
+
+static bool HHVM_METHOD(EventBuffer, unfreeze, bool at_front) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, false);
+  return (::evbuffer_unfreeze(buf->getPtr(), at_front) == 0);
+}
+
+static void HHVM_METHOD(EventBuffer, unlock) {
+  HPHP_EVENT_BUFFER_GET(buf, this_, /* void */);
+  ::evbuffer_unlock(buf->getPtr());
+}
+
+static Variant HHVM_METHOD(EventBuffer, write, const Variant& fdvar, int64_t howmuch = -1) {
+  int64_t res;
+  evutil_socket_t fd;
+
+  HPHP_EVENT_BUFFER_GET(buf, this_, VAR_FALSE);
+  HPHP_EVENT_SET_FD(fd, fdvar, VAR_FALSE);
+
+  res = howmuch < 0
+    ? ::evbuffer_write(buf->getPtr(), fd)
+    : ::evbuffer_write_atmost(buf->getPtr(), fd, howmuch);
+
+  if (res == -1) {
+    return VAR_FALSE;
+  }
+  return res;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+
+#define REG_INT_CONST(v) \
+  Native::registerClassConstant<KindOfInt64>(s_EventBuffer.get(), \
+      makeStaticString(#v), EVBUFFER_ ## v)
+
+void EventExtension::_initEventBufferClass() {
+  REG_INT_CONST(EOL_ANY);
+  REG_INT_CONST(EOL_CRLF);
+  REG_INT_CONST(EOL_CRLF_STRICT);
+  REG_INT_CONST(EOL_LF);
+#if LIBEVENT_VERSION_NUMBER >= 0x02010100
+  REG_INT_CONST(EOL_NUL);
+#endif
+  REG_INT_CONST(PTR_SET);
+  REG_INT_CONST(PTR_ADD);
+
+  HHVM_ME(EventBuffer, __construct);
+  HHVM_ME(EventBuffer, add);
+  HHVM_ME(EventBuffer, addBuffer);
+  HHVM_ME(EventBuffer, getLength);
+  HHVM_ME(EventBuffer, getContiguousSpace);
+  HHVM_ME(EventBuffer, appendFrom);
+  HHVM_ME(EventBuffer, copyout);
+  HHVM_ME(EventBuffer, drain);
+  HHVM_ME(EventBuffer, enableLocking);
+  HHVM_ME(EventBuffer, expand);
+  HHVM_ME(EventBuffer, freeze);
+  HHVM_ME(EventBuffer, lock);
+  HHVM_ME(EventBuffer, prepend);
+  HHVM_ME(EventBuffer, prependBuffer);
+  HHVM_ME(EventBuffer, pullup);
+  HHVM_ME(EventBuffer, read);
+  HHVM_ME(EventBuffer, readFrom);
+  HHVM_ME(EventBuffer, readLine);
+  HHVM_ME(EventBuffer, search);
+  HHVM_ME(EventBuffer, searchEol);
+  HHVM_ME(EventBuffer, substr);
+  HHVM_ME(EventBuffer, unfreeze);
+  HHVM_ME(EventBuffer, unlock);
+  HHVM_ME(EventBuffer, write);
+}
+
+#undef REG_INT_CONST
+
+#undef VAR_FALSE
+
+} // namespace HPHP
+
+// vim: et ts=2 sts=2 sw=2

api/EventBuffer.h

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef incl_HPHP_CLASSES_EVENT_BUFFER_H
+#define incl_HPHP_CLASSES_EVENT_BUFFER_H
+
+#include "ext_event.h"
+#include "api/Event.h"
+
+namespace HPHP {
+
+class EventBuffer: public EventResourceData {
+  DECLARE_RESOURCE_ALLOCATION(EventBuffer);
+  CLASSNAME_IS("EventBuffer");
+  const String& o_getClassNameHook() const override { return classnameof(); }
+
+
+  private:
+    struct evbuffer* m_ptr = nullptr;
+    // Whether m_ptr is allocated outside
+    bool m_owned;
+
+  public:
+    EventBuffer();
+    explicit EventBuffer(struct evbuffer* ptr);
+    virtual ~EventBuffer();
+
+    Object wrap();
+    static EventBuffer* get(Object obj);
+    bool isValid() const { return m_ptr; }
+    inline struct evbuffer* getPtr() const { return m_ptr; }
+    bool setPos(struct evbuffer_ptr* ptr, const long pos);
+    inline void free();
+};
+
+} // namespace HPHP
+
+#endif // incl_HPHP_CLASSES_EVENT_BUFFER_H
+
+// vim: et ts=2 sts=2 sw=2

api/EventBufferEvent.cpp

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/EventBufferEvent.h"
+#include "src/EventRequestData.h"
+#include "api/EventBase.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+#define VAR_FALSE Variant(false)
+
+#define HPHP_EVENT_OPENSSL_REQUIRED_ERROR(__f, __ret)   \
+do {                                                    \
+  raise_error(#__f " requires OpenSSL support. "        \
+      "Rebuild event extension with OpenSSL support."); \
+  return __ret;                                         \
+} while (0)
+
+
+#if 0
+IMPLEMENT_OBJECT_ALLOCATION(EventBufferEvent);
+#endif
+
+
+
+static void bevent_read_cb(struct bufferevent* bevent, void* ptr) {
+  assert(ptr);
+  EventBufferEvent* rc = static_cast<EventBufferEvent*>(ptr);
+  assert(!rc->isInvalid());
+  rc->readCallback();
+}
+
+static void bevent_write_cb(struct bufferevent* bevent, void* ptr) {
+  assert(ptr);
+  EventBufferEvent* rc = static_cast<EventBufferEvent*>(ptr);
+  assert(!rc->isInvalid());
+  rc->writeCallback();
+}
+
+static void bevent_event_cb(struct bufferevent* bevent, short events, void* ptr) {
+  assert(ptr);
+  EventBufferEvent* rc = static_cast<EventBufferEvent*>(ptr);
+  assert(!rc->isInvalid());
+  rc->eventCallback(events);
+}
+
+
+void EventBufferEvent::readCallback() const {
+  assert(m_ptr);
+  if (!m_readCb.isNull()) {
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_lock(m_ptr);
+#endif
+
+    vm_call_user_func(m_readCb, make_packed_array(m_cbArg));
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_unlock(m_ptr);
+#endif
+  }
+}
+
+void EventBufferEvent::writeCallback() const {
+  assert(m_ptr);
+  if (!m_writeCb.isNull()) {
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_lock(m_ptr);
+#endif
+
+    vm_call_user_func(m_writeCb, make_packed_array(m_cbArg));
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_unlock(m_ptr);
+#endif
+  }
+}
+
+void EventBufferEvent::eventCallback(int64_t events) const {
+  assert(m_ptr);
+  if (!m_eventCb.isNull()) {
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_lock(m_ptr);
+#endif
+
+    vm_call_user_func(m_eventCb, make_packed_array(events, m_cbArg));
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    ::bufferevent_unlock(m_ptr);
+#endif
+  }
+}
+
+EventBufferEvent::EventBufferEvent():
+  m_ptr(nullptr),
+  m_readCb(null_variant),
+  m_writeCb(null_variant),
+  m_eventCb(null_variant),
+  m_cbArg(null_variant)
+{}
+
+EventBufferEvent::EventBufferEvent(const Object& baseObj, const Variant& socketVar, int64_t options,
+    const Variant& readCbVar, const Variant& writeCbVar, const Variant& eventCbVar, const Variant& arg):
+  m_ptr(nullptr),
+  m_readCb(readCbVar),
+  m_writeCb(writeCbVar),
+  m_eventCb(eventCbVar),
+  m_cbArg(arg)
+{
+    HPHP_EVENT_BASE_GET(base, baseObj, /* void */);
+
+    evutil_socket_t      fd;
+    bufferevent_data_cb  readCb;
+    bufferevent_data_cb  writeCb;
+    bufferevent_event_cb eventCb;
+
+    if (!socketVar.isNull()) {
+      HPHP_EVENT_SET_FD(fd, socketVar, /* void */);
+      // Make sure that the socket is in non-blocking mode(libevent's tip)
+      ::evutil_make_socket_nonblocking(fd);
+    } else {
+      // User decided to assign fd later,
+      // e.g. by means of bufferevent_socket_connect()
+      // which allocates new socket stream in this case.
+      fd = -1;
+      // User has no access to the file descriptor created
+      // internally (bufferevent_getfd is not exposed to userspace at the
+      // moment). Therefore, we have to make it close-on-free.
+      options |= ::BEV_OPT_CLOSE_ON_FREE;
+    }
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+    options |= ::BEV_OPT_THREADSAFE;
+#endif
+    m_ptr = ::bufferevent_socket_new(base->getPtr(), fd, options);
+    if (m_ptr == NULL) {
+      raise_error("Failed to allocate bufferevent for socket");
+      return;
+    }
+
+    readCb  = f_is_callable(readCbVar)  ? bevent_read_cb  : NULL;
+    writeCb = f_is_callable(writeCbVar) ? bevent_write_cb : NULL;
+    eventCb = f_is_callable(eventCbVar) ? bevent_event_cb : NULL;
+
+    if (readCb || writeCb || eventCb || !arg.isNull()) {
+      ::bufferevent_setcb(m_ptr, readCb, writeCb, eventCb, static_cast<void*>(this));
+    }
+}
+
+#ifndef HPHP_DISABLE_EVENT_OPENSSL
+EventBufferEvent::EventBufferEvent(struct event_base* base,
+    struct bufferevent* bevent, SSL_CTX* ctx,
+    int64_t state, int64_t options):
+  m_ptr(nullptr),
+  m_readCb(null_variant),
+  m_writeCb(null_variant),
+  m_eventCb(null_variant),
+  m_cbArg(null_variant)
+{
+  assert(ctx);
+  auto ssl = ::SSL_new(ctx);
+  if (!ssl) {
+    raise_warning("Failed to create SSL handle");
+    return;
+  }
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+  options |= ::BEV_OPT_THREADSAFE;
+#endif
+  m_ptr = ::bufferevent_openssl_filter_new(base, bevent, ssl, static_cast<bufferevent_ssl_state>(state), options);
+
+  if (m_ptr == NULL) {
+    raise_warning("Failed to allocate bufferevent filter");
+    return;
+  }
+}
+
+EventBufferEvent::EventBufferEvent(struct event_base* base,
+    evutil_socket_t fd, SSL_CTX* ctx,
+    int64_t state, int64_t options):
+  m_ptr(nullptr),
+  m_readCb(null_variant),
+  m_writeCb(null_variant),
+  m_eventCb(null_variant),
+  m_cbArg(null_variant)
+{
+  assert(ctx);
+  auto ssl = ::SSL_new(ctx);
+  if (!ssl) {
+    raise_warning("Failed to create SSL handle");
+    return;
+  }
+
+  if (fd < 0) {
+    raise_warning("Invalid file descriptor");
+    return;
+  }
+
+  // Attach ectx to ssl for callbacks
+  EventBase::m_tlsRequestData->setSslData(ssl, (void *) ctx);
+
+#ifndef HPHP_DISABLE_EVENT_PTHREADS
+  options |= ::BEV_OPT_THREADSAFE;
+#endif
+  m_ptr = ::bufferevent_openssl_socket_new(base, fd, ssl, static_cast<bufferevent_ssl_state>(state), options);
+  if (m_ptr == NULL) {
+    raise_warning("Failed to allocate bufferevent socket");
+    return;
+  }
+}
+#endif // HPHP_DISABLE_EVENT_OPENSSL
+
+
+void EventBufferEvent::free() {
+  if (m_ptr) {
+    ::bufferevent_free(m_ptr);
+    m_ptr = nullptr;
+  }
+}
+
+
+void EventBufferEvent::sweep() {
+  free();
+}
+
+EventBufferEvent::~EventBufferEvent() {
+  free();
+}
+
+
+EventBufferEvent* EventBufferEvent::get(Object obj) {
+  return getInternalResource<EventBufferEvent>(obj, s_EventBufferEvent);
+}
+
+Object EventBufferEvent::wrap() {
+  return newInstance(s_EventBufferEvent.get());
+}
+
+Object EventBufferEvent::getInputBuffer() {
+  if (m_ptr) {
+    return (new EventBuffer(::bufferevent_get_input(m_ptr)))->wrap();
+  }
+  return null_object;
+}
+
+Object EventBufferEvent::getOutputBuffer() {
+  if (m_ptr) {
+    return (new EventBuffer(::bufferevent_get_output(m_ptr)))->wrap();
+  }
+  return null_object;
+}
+
+/////////////////////////////////////////////////////////////////////////
+// EventBufferEvent PHP class
+
+static Variant HHVM_METHOD(EventBufferEvent, _getProperty, int64_t key) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, null_variant);
+
+  switch (key) {
+    case 1: // fd
+      {
+        evutil_socket_t fd = ::bufferevent_getfd(bevent->getPtr());
+        return fd == -1 ? null_variant : Variant(fd);
+      }
+    case 2: // input
+      return bevent->getInputBuffer();
+    case 3: // output
+      return bevent->getOutputBuffer();
+    default:
+      return null_variant;
+  }
+}
+
+static void HHVM_METHOD(EventBufferEvent, __constructArray, const Array& args) {
+  auto rc = NEWOBJ(EventBufferEvent)(
+      args[0].asCObjRef(), // base
+      args[1],            // socket
+      args[2].toInt64(),  // options
+      args[3],            // readcb
+      args[4],            // writecb
+      args[5],            // writecb
+      args[6]);           // arg
+  this_->o_set(s__rc, Resource(rc), s_EventBufferEvent.get());
+}
+
+static bool HHVM_METHOD(EventBufferEvent, connectHost, const Variant& dnsBaseVar, const String& hostname,
+    int64_t port, int64_t family = AF_UNSPEC) {
+#if LIBEVENT_VERSION_NUMBER < 0x02000300
+  raise_error("Minimum Libevent version required: 2.0.3-alpha");
+  return false;
+#else
+
+  if (family & ~(AF_INET | AF_INET6 | AF_UNSPEC)) {
+    raise_warning("Invalid address family specified");
+    return false;
+  }
+
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+
+  // bufferevent_socket_connect() allocates a socket stream internally, if we
+  // the file descriptor is not provided before e.g. with
+  // bufferevent_socket_new()
+
+#ifndef HPHP_DISABLE_EVENT_EXTRA
+  EventDnsBase* dnsBase;
+
+  if (dnsBaseVar.isNull()) {
+    dnsBase = nullptr;
+  } else {
+    dnsBase = EventDnsBase::get(dnsBaseVar.toObject());
+    if (!dnsBase) {
+      raise_warning("EventDnsBase object is not constructed");
+      return false;
+    }
+  }
+
+  if (::bufferevent_socket_connect_hostname(bevent->getPtr(),
+        (dnsBase ? dnsBase->getPtr() : NULL),
+        family, hostname.c_str(), port)) {
+#ifdef HPHP_EVENT_DEBUG
+    raise_warning("%s", ::evutil_gai_strerror(
+          ::bufferevent_socket_get_dns_error(bevent->getPtr())));
+#endif
+    return false;
+  }
+
+#else //  HPHP_DISABLE_EVENT_EXTRA
+
+  if (::bufferevent_socket_connect_hostname(bevent->getPtr(),
+        NULL, family, hostname.c_str(), port)) {
+#ifdef PHP_EVENT_DEBUG
+    raise_warning("%s", ::evutil_gai_strerror(
+          ::bufferevent_socket_get_dns_error(bevent->getPtr())));
+#endif
+    return false;
+  }
+
+#endif  //  HPHP_DISABLE_EVENT_EXTRA
+
+  return true;
+#endif //  LIBEVENT_VERSION_NUMBER < 0x02000300
+}
+
+static bool HHVM_METHOD(EventBufferEvent, enable, int64_t events) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  return (::bufferevent_enable(bevent->getPtr(), events) == 0);
+}
+
+static bool HHVM_METHOD(EventBufferEvent, disable, int64_t events) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  return (::bufferevent_disable(bevent->getPtr(), events) == 0);
+}
+
+static void HHVM_METHOD(EventBufferEvent, free) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, /* void */);
+  //delete bevent;
+  bevent->free();
+}
+
+static String HHVM_METHOD(EventBufferEvent, getDnsErrorString) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, null_string);
+
+  auto err = ::bufferevent_socket_get_dns_error(bevent->getPtr());
+  return err == 0 ? null_string : String(evutil_gai_strerror(err));
+}
+
+static int64_t HHVM_METHOD(EventBufferEvent, getEnabled) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, 0);
+  return ::bufferevent_get_enabled(bevent->getPtr());
+}
+
+static Object HHVM_METHOD(EventBufferEvent, getInput) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, 0);
+  return bevent->getInputBuffer();
+}
+
+static Object HHVM_METHOD(EventBufferEvent, getOutput) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, 0);
+  return bevent->getOutputBuffer();
+}
+
+static Variant HHVM_METHOD(EventBufferEvent, read, int64_t size) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, 0);
+
+  char* data = (char *) malloc(size * sizeof(char) + 1);
+  auto num = ::bufferevent_read(bevent->getPtr(), data, size);
+
+  if (num > 0) {
+    return String(data, num, AttachString);
+  }
+  return VAR_FALSE;
+}
+
+static bool HHVM_METHOD(EventBufferEvent, readBuffer, const Object& bufVar) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  HPHP_EVENT_BUFFER_GET(buf, bufVar, false);
+  return (::bufferevent_read_buffer(bevent->getPtr(), buf->getPtr()) == 0);
+}
+
+static void HHVM_METHOD(EventBufferEvent, setCallbacks,
+    const Variant& readCbVar, const Variant& writeCbVar, const Variant& eventCbVar, const Variant& arg /*= null_variant*/) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, /* void */);
+
+  bevent->setCallbacks(readCbVar, writeCbVar, eventCbVar, arg);
+
+  bufferevent_data_cb  readCb;
+  bufferevent_data_cb  writeCb;
+  bufferevent_event_cb eventCb;
+
+  readCb  = f_is_callable(readCbVar)  ? bevent_read_cb  : NULL;
+  writeCb = f_is_callable(writeCbVar) ? bevent_write_cb : NULL;
+  eventCb = f_is_callable(eventCbVar) ? bevent_event_cb : NULL;
+
+  ::bufferevent_setcb(bevent->getPtr(), readCb, writeCb, eventCb, static_cast<void*>(bevent));
+}
+
+static bool HHVM_METHOD(EventBufferEvent, setPriority, int64_t priority) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  return (::bufferevent_priority_set(bevent->getPtr(), priority) == 0);
+}
+
+static bool HHVM_METHOD(EventBufferEvent, setTimeouts,
+    double read_timeout, double write_timeout) {
+  struct timeval tv_read, tv_write;
+
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  HPHP_EVENT_TIMEVAL_SET(tv_read, read_timeout);
+  HPHP_EVENT_TIMEVAL_SET(tv_write, write_timeout);
+
+  return (::bufferevent_set_timeouts(bevent->getPtr(), &tv_read, &tv_write) == 0);
+}
+
+static void HHVM_METHOD(EventBufferEvent, setWatermark,
+    int64_t events, int64_t lowmark, int64_t highmark) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, /* void */);
+  bufferevent_setwatermark(bevent->getPtr(), events,
+      static_cast<size_t>(lowmark), static_cast<size_t>(highmark));
+}
+
+static Variant HHVM_METHOD(EventBufferEvent, sslError) {
+#ifdef HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_OPENSSL_REQUIRED_ERROR(EventBufferEvent::sslError, null_variant);
+#else //  HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_BEVENT_GET(bevent, this_, VAR_FALSE);
+
+  char buf[512];
+  auto e = ::bufferevent_get_openssl_error(bevent->getPtr());
+  if (e) {
+    return String(ERR_error_string(e, buf));
+  }
+  return VAR_FALSE;
+#endif // HPHP_DISABLE_EVENT_OPENSSL
+}
+
+static Object HHVM_STATIC_METHOD(EventBufferEvent, sslFilter, const Object& baseObj,
+    const Object& underlyingObj, const Object& ctxObj, int64_t state, int64_t options = 0) {
+#ifdef HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_OPENSSL_REQUIRED_ERROR(EventBufferEvent::sslFilter, null_object);
+#else //  HPHP_DISABLE_EVENT_OPENSSL
+  if (!EventBufferEvent::isValidSslState(state)) {
+    raise_warning("Invalid state specified");
+    return null_object;
+  }
+
+  HPHP_EVENT_BASE_GET(base, baseObj, null_object);
+  HPHP_EVENT_BEVENT_GET(bevUnderlying, underlyingObj, null_object);
+  HPHP_EVENT_SSLCONTEXT_GET(ctx, ctxObj, null_object);
+
+  auto rc = NEWOBJ(EventBufferEvent)(base->getPtr(), bevUnderlying->getPtr(),
+      ctx->getPtr(), state, options);
+  return rc->wrap();
+#endif // HPHP_DISABLE_EVENT_OPENSSL
+}
+
+static void HHVM_METHOD(EventBufferEvent, sslRenegotiate) {
+#ifdef HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_OPENSSL_REQUIRED_ERROR(EventBufferEvent::sslRenegotiate, /* void */);
+#else // HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_BEVENT_GET(bevent, this_, /* void */);
+  ::bufferevent_ssl_renegotiate(bevent->getPtr());
+#endif // HPHP_DISABLE_EVENT_OPENSSL
+}
+
+static Object HHVM_STATIC_METHOD(EventBufferEvent, sslSocket, const Object& baseObj, const Variant& socketVar,
+    const Object& ctxObj, int64_t state, int options = 0) {
+#ifdef HPHP_DISABLE_EVENT_OPENSSL
+  HPHP_EVENT_OPENSSL_REQUIRED_ERROR(EventBufferEvent::sslSocket, null_object);
+#else // HPHP_DISABLE_EVENT_OPENSSL
+  evutil_socket_t fd;
+
+  if (!EventBufferEvent::isValidSslState(state)) {
+    raise_warning("Invalid state specified");
+    return null_object;
+  }
+
+  if (socketVar.isNull()) {
+    // User decided to set fd later via connect or connectHost etc.
+    fd = -1;
+  } else {
+    fd = Event::varToFd(socketVar);
+    if (fd < 0) {
+      return null_object;
+    }
+    // Make sure that the socket is in non-blocking mode(libevent's tip)
+    //evutil_make_socket_nonblocking(fd);
+  }
+
+  HPHP_EVENT_BASE_GET(base, baseObj, null_object);
+  HPHP_EVENT_SSLCONTEXT_GET(ctx, ctxObj, null_object);
+
+  auto rc = NEWOBJ(EventBufferEvent)(base->getPtr(), fd, ctx->getPtr(), state, options);
+  return rc->wrap();
+#endif // HPHP_DISABLE_EVENT_OPENSSL
+}
+
+static bool HHVM_METHOD(EventBufferEvent, write, const String& data) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  return (::bufferevent_write(bevent->getPtr(), data.data(), data.length()) == 0);
+}
+
+static bool HHVM_METHOD(EventBufferEvent, writeBuffer, const Object& bufObj) {
+  HPHP_EVENT_BEVENT_GET(bevent, this_, false);
+  HPHP_EVENT_BUFFER_GET(buf, bufObj, false);
+  return (::bufferevent_write_buffer(bevent->getPtr(), buf->getPtr()) == 0);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+#define REG_NAMED_INT_CONST(v, n) \
+  Native::registerClassConstant<KindOfInt64>(s_EventBufferEvent.get(), \
+      makeStaticString(#v), n)
+
+#define REG_INT_EVENT_CONST(v) \
+  REG_NAMED_INT_CONST(v, BEV_EVENT_ ## v)
+
+#define REG_INT_OPT_CONST(v) \
+  REG_NAMED_INT_CONST(OPT_ ## v, BEV_OPT_ ## v)
+
+void EventExtension::_initEventBufferEventClass() {
+  HHVM_ME(EventBufferEvent, _getProperty);
+  HHVM_ME(EventBufferEvent, __constructArray);
+  HHVM_ME(EventBufferEvent, connectHost);
+  HHVM_ME(EventBufferEvent, enable);
+  HHVM_ME(EventBufferEvent, disable);
+  HHVM_ME(EventBufferEvent, free);
+  HHVM_ME(EventBufferEvent, getDnsErrorString);
+  HHVM_ME(EventBufferEvent, getEnabled);
+  HHVM_ME(EventBufferEvent, getInput);
+  HHVM_ME(EventBufferEvent, getOutput);
+  HHVM_ME(EventBufferEvent, read);
+  HHVM_ME(EventBufferEvent, readBuffer);
+  HHVM_ME(EventBufferEvent, setCallbacks);
+  HHVM_ME(EventBufferEvent, setPriority);
+  HHVM_ME(EventBufferEvent, setTimeouts);
+  HHVM_ME(EventBufferEvent, setWatermark);
+  HHVM_ME(EventBufferEvent, sslError);
+  HHVM_STATIC_ME(EventBufferEvent, sslFilter);
+  HHVM_ME(EventBufferEvent, sslRenegotiate);
+  HHVM_STATIC_ME(EventBufferEvent, sslSocket);
+  HHVM_ME(EventBufferEvent, write);
+  HHVM_ME(EventBufferEvent, writeBuffer);
+
+  REG_INT_EVENT_CONST(READING);
+  REG_INT_EVENT_CONST(WRITING);
+  REG_NAMED_INT_CONST(EOF, BEV_EVENT_EOF);
+  REG_INT_EVENT_CONST(ERROR);
+  REG_INT_EVENT_CONST(TIMEOUT);
+  REG_INT_EVENT_CONST(CONNECTED);
+
+  REG_INT_OPT_CONST(CLOSE_ON_FREE);
+  REG_INT_OPT_CONST(THREADSAFE);
+  REG_INT_OPT_CONST(DEFER_CALLBACKS);
+#if LIBEVENT_VERSION_NUMBER >= 0x02000500
+  REG_INT_OPT_CONST(UNLOCK_CALLBACKS);
+#endif
+
+#ifndef HPHP_DISABLE_EVENT_OPENSSL
+  REG_NAMED_INT_CONST(SSL_OPEN,       BUFFEREVENT_SSL_OPEN);
+  REG_NAMED_INT_CONST(SSL_CONNECTING, BUFFEREVENT_SSL_CONNECTING);
+  REG_NAMED_INT_CONST(SSL_ACCEPTING,  BUFFEREVENT_SSL_ACCEPTING);
+#endif
+}
+
+#undef REG_NAMED_INT_CONST
+#undef REG_INT_EVENT_CONST
+#undef REG_INT_OPT_CONST
+
+#undef VAR_FALSE
+
+} // namespace HPHP
+
+// vim: et ts=2 sts=2 sw=2

api/EventBufferEvent.h

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef incl_HPHP_CLASSES_EVENT_BUFFER_EVENT_H
+#define incl_HPHP_CLASSES_EVENT_BUFFER_EVENT_H
+
+#include "ext_event.h"
+#include "api/Event.h"
+#include "api/EventBuffer.h"
+#include "api/EventDnsBase.h"
+#include "api/EventSslContext.h"
+
+namespace HPHP {
+
+#if LIBEVENT_VERSION_NUMBER < 0x02000200
+// These types introduced in libevent 2.0.2-alpha
+typedef void (*bufferevent_data_cb)(struct bufferevent* bev, void* ctx);
+typedef void (*bufferevent_event_cb)(struct bufferevent* bev, short events, void* ctx);
+#endif
+
+class EventBufferEvent: public EventResourceData {
+  DECLARE_RESOURCE_ALLOCATION(EventBufferEvent);
+  CLASSNAME_IS("EventBufferEvent");
+  const String& o_getClassNameHook() const override { return classnameof(); }
+
+  private:
+    struct bufferevent* m_ptr = nullptr;
+    Variant m_readCb;
+    Variant m_writeCb;
+    Variant m_eventCb;
+    Variant m_cbArg;
+
+  public:
+    EventBufferEvent();
+    explicit EventBufferEvent(const Object& baseObj, const Variant& socketvar, int64_t options,
+        const Variant& readCbVar, const Variant& writeCbVar, const Variant& eventCbVar, const Variant& arg);
+    explicit EventBufferEvent(struct event_base* base, struct bufferevent* bevent,
+        SSL_CTX* ctx, int64_t state, int64_t options);
+    explicit EventBufferEvent(struct event_base* base, evutil_socket_t fd,
+        SSL_CTX* ctx, int64_t state, int64_t options);
+    virtual ~EventBufferEvent();
+    inline void free();
+
+    Object getInputBuffer();
+    Object getOutputBuffer();
+    Object wrap();
+    static EventBufferEvent* get(Object obj);
+    bool isValid() const { return m_ptr; }
+    inline struct bufferevent* getPtr() const { return m_ptr; }
+
+    void readCallback() const;
+    void writeCallback() const;
+    void eventCallback(int64_t events) const;
+
+    inline void setCallbacks(const Variant& rcb, const Variant& wcb, const Variant& ecb, const Variant& arg) {
+      m_readCb  = rcb;
+      m_writeCb = wcb;
+      m_eventCb = ecb;
+      m_cbArg   = arg;
+    }
+
+    inline static bool isValidSslState(int64_t state) {
+      return (state == ::BUFFEREVENT_SSL_OPEN
+          || state == ::BUFFEREVENT_SSL_CONNECTING
+          || state == ::BUFFEREVENT_SSL_ACCEPTING);
+    }
+};
+
+} // namespace HPHP
+
+#endif // incl_HPHP_CLASSES_EVENT_BUFFER_EVENT_H
+
+// vim: et ts=2 sts=2 sw=2

api/EventConfig.cpp

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/EventConfig.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+void EventConfig::free() {
+  if (m_ptr) {
+    ::event_config_free(m_ptr);
+    m_ptr = nullptr;
+  }
+}
+
+
+void EventConfig::sweep() {
+  free();
+}
+
+
+EventConfig::EventConfig() {
+  m_ptr = ::event_config_new();
+  if (!m_ptr) {
+    raise_error("event_config_new failed");
+  }
+}
+
+
+EventConfig::~EventConfig() {
+  free();
+}
+
+
+EventConfig* EventConfig::get(Object obj) {
+  return getInternalResource<EventConfig>(obj, s_EventConfig);
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// EventConfig PHP class
+
+static void HHVM_METHOD(EventConfig, __construct) {
+  auto rc = NEWOBJ(EventConfig)();
+  this_->o_set(s__rc, Resource(rc), s_EventConfig.get());
+}
+
+static bool HHVM_METHOD(EventConfig, avoidMethod, const String& method) {
+  HPHP_EVENT_CONFIG_GET(rc, this_, false);
+  return (::event_config_avoid_method(rc->getPtr(), method.c_str()) == 0);
+}
+
+static bool HHVM_METHOD(EventConfig, requireFeatures, int64_t features) {
+  HPHP_EVENT_CONFIG_GET(rc, this_, false);
+  return (::event_config_require_features(rc->getPtr(), features) == 0);
+}
+
+static void HHVM_METHOD(EventConfig, setMaxDispatchInterval,
+    int64_t max_interval, int64_t max_callbacks, int64_t min_priority) {
+#if LIBEVENT_VERSION_NUMBER >= 0x02010000
+  HPHP_EVENT_CONFIG_GET(rc, this_, /* void */);
+
+  if (max_interval > 0) {
+    struct timeval tv;
+    HPHP_EVENT_TIMEVAL_SET(tv, max_interval);
+    ::event_config_set_max_dispatch_interval(rc->getPtr(), &tv, max_callbacks, min_priority);
+  } else {
+    ::event_config_set_max_dispatch_interval(rc->getPtr(), NULL, max_callbacks, min_priority);
+  }
+#endif // LIBEVENT_VERSION_NUMBER >= 0x02010000
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+#define REG_INT_CONST(v) \
+  Native::registerClassConstant<KindOfInt64>(s_EventConfig.get(), \
+      makeStaticString(#v), EV_ ## v)
+
+void EventExtension::_initEventConfigClass() {
+  REG_INT_CONST(FEATURE_ET);
+  REG_INT_CONST(FEATURE_O1);
+  REG_INT_CONST(FEATURE_FDS);
+
+  HHVM_ME(EventConfig, __construct);
+  HHVM_ME(EventConfig, avoidMethod);
+  HHVM_ME(EventConfig, requireFeatures);
+  HHVM_ME(EventConfig, setMaxDispatchInterval);
+}
+
+#undef REG_INT_CONST
+
+} // namespace HPHP
+
+// vim: et ts=2 sts=2 sw=2

api/EventConfig.h

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef incl_HPHP_CLASSES_EVENT_CONFIG_H
+#define incl_HPHP_CLASSES_EVENT_CONFIG_H
+
+#include "ext_event.h"
+
+namespace HPHP {
+
+class EventConfig: public EventResourceData {
+  DECLARE_RESOURCE_ALLOCATION(EventConfig);
+  CLASSNAME_IS("EventConfig");
+  const String& o_getClassNameHook() const override { return classnameof(); }
+
+  private:
+    struct event_config* m_ptr = nullptr;
+
+  public:
+    EventConfig();
+    virtual ~EventConfig();
+
+    static EventConfig* get(Object obj);
+
+    bool isValid() const { return m_ptr; }
+    inline struct event_config* getPtr() const { return m_ptr; }
+    inline void free();
+};
+
+} // namespace HPHP
+
+#endif // incl_HPHP_CLASSES_EVENT_CONFIG_H
+
+// vim: et ts=2 sts=2 sw=2

api/EventDnsBase.cpp

+/*
+   +----------------------------------------------------------------------+
+   | HipHop for PHP                                                       |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com)     |
+   | Copyright (c) 1997-2014 The PHP Group                                |
+   | Author: Ruslan Osmanov <osmanov@php.net>                             |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+*/
+
+#include "api/EventDnsBase.h"
+
+namespace HPHP {
+
+/////////////////////////////////////////////////////////////////////////
+// Internal
+
+void EventDnsBase::free() {
+  if (m_ptr) {
+    // Setting fail_requests to 1 makes all in-flight requests get
+    // their callbacks invoked with a canceled error code before it
+    // frees the base
+    ::evdns_base_free(m_ptr, 1);
+    m_ptr = nullptr;
+  }
+}
+
+
+void EventDnsBase::sweep() {
+  free();
+}
+
+EventDnsBase::EventDnsBase()
+: m_ptr(nullptr) {}
+
+
+EventDnsBase::EventDnsBase(struct event_base* base, bool initialize)
+: m_ptr(::evdns_base_new(base, initialize)) {}
+
+
+EventDnsBase::~EventDnsBase() {
+  free();
+}
+
+
+EventDnsBase* EventDnsBase::get(Object obj) {
+  return getInternalResource<EventDnsBase>(obj, s_EventDnsBase);
+}
+
+
+Object EventDnsBase::wrap() {
+  return newInstance(s_EventDnsBase.get());
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// EventDnsBase PHP class
+
+static void HHVM_METHOD(EventDnsBase, __construct, const Object& baseObj, bool initialize) {
+  HPHP_EVENT_BASE_GET(base, baseObj, /* void */);
+  assert(base);
+
+  auto rc = NEWOBJ(EventDnsBase)(base->getPtr(), initialize);
+  this_->o_set(s__rc, Resource(rc), s_EventDnsBase.get());
+}
+
+static bool HHVM_METHOD(EventDnsBase, addNameserverIp, const String& ip) {
+  HPHP_EVENT_DNSBASE_GET(dnsBase, this_, false);
+  return (::evdns_base_nameserver_ip_add(dnsBase->getPtr(), ip.c_str()) == 0);
+}