<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xml:id="eventlistener.construct" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
 <refnamediv>
  <refname>EventListener::__construct</refname>
  <refpurpose>Creates new connection listener associated with an event base</refpurpose>
 </refnamediv>
 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier>
   <methodname>EventListener::__construct</methodname>
   <methodparam>
    <type>EventBase</type>
    <parameter>base</parameter>
   </methodparam>
   <methodparam>
    <type>callable</type>
    <parameter>cb</parameter>
   </methodparam>
   <methodparam>
    <type>mixed</type>
    <parameter>data</parameter>
   </methodparam>
   <methodparam>
    <type>int</type>
    <parameter>flags</parameter>
   </methodparam>
   <methodparam>
    <type>int</type>
    <parameter>backlog</parameter>
   </methodparam>
   <methodparam>
    <type>mixed</type>
    <parameter>target</parameter>
   </methodparam>
  </methodsynopsis>
  <para>
   Creates new connection listener associated with an event base.
  </para>
 </refsect1>
 <refsect1 role="parameters">
  &reftitle.parameters;
  <variablelist>
   <varlistentry>
    <term>
     <parameter>base</parameter>
    </term>
    <listitem>
     <para>
      Associated event base.
     </para>
    </listitem>
   </varlistentry>
   <varlistentry>
    <term>
     <parameter>cb</parameter>
    </term>
    <listitem>
     <para>
      A
      <type>callable</type>
      that will be invoked when new connection received.
     </para>
    </listitem>
   </varlistentry>
   <varlistentry>
    <term>
     <parameter>data</parameter>
    </term>
    <listitem>
     <para>
      Custom user data attached to
      <parameter>cb</parameter>
      .
     </para>
    </listitem>
   </varlistentry>
   <varlistentry>
    <term>
     <parameter>flags</parameter>
    </term>
    <listitem>
     <para>
      Bit mask of
      <literal>EventListener::OPT_*</literal>
      constants. See
      <link linkend="eventlistener.constants">EventListener constants</link>
      .
     </para>
    </listitem>
   </varlistentry>
   <varlistentry>
    <term>
     <parameter>backlog</parameter>
    </term>
    <listitem>
     <para>
      Controls the maximum number of pending connections that the network
      stack should allow to wait in a not-yet-accepted state at any time; see
      documentation for your system’s
      <literal>listen</literal>
      function for more details. If
      <parameter>backlog</parameter>
      is negative, Libevent tries to pick a good value for the
      <parameter>backlog</parameter>
      ; if it is zero, Event assumes that
      <literal>listen</literal>
      is already called on the socket(
      <parameter>target</parameter>
      )
     </para>
    </listitem>
   </varlistentry>
   <varlistentry>
    <term>
     <parameter>target</parameter>
    </term>
    <listitem>
     <para>
      May be string, socket resource, or a stream associated with a socket. In
      case if
      <parameter>target</parameter>
      is a string, the string will be parsed as network address. It will be
      interpreted as a UNIX domain socket path, if prefixed with
      <literal>'unix:'</literal>
      , e.g.
      <literal>'unix:/tmp/my.sock'</literal>
      .
     </para>
    </listitem>
   </varlistentry>
  </variablelist>
 </refsect1>
 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   Returns
   <classname>EventListener</classname>
   object representing the event connection listener.
  </para>
 </refsect1>
 <refsect1 role="changelog">
  &reftitle.changelog;
  <para>
   <informaltable>
    <tgroup cols="2">
     <thead>
      <row>
       <entry>&Version;</entry>
       <entry>&Description;</entry>
      </row>
     </thead>
     <tbody>
      <row>
       <entry>PECL event 1.5.0</entry>
       <entry>
        UNIX domain sockets&apos; support added.
       </entry>
      </row>
     </tbody>
    </tgroup>
   </informaltable>
  </para>
 </refsect1>
 <refsect1 role="examples">
  &reftitle.examples;
  <example>
   <title>
    <function>EventListener::__construct</function> example</title>
   <programlisting role="php">
<![CDATA[
<?php
/*
 * Simple echo server based on libevent's connection listener.
 *
 * Usage:
 * 1) In one terminal window run:
 *
 * $ php listener.php 9881
 *
 * 2) In another terminal window open up connection, e.g.:
 *
 * $ nc 127.0.0.1 9881
 *
 * 3) start typing. The server should repeat the input.
 */

class MyListenerConnection {
    private $bev, $base;

    public function __destruct() {
        $this->bev->free();
    }

    public function __construct($base, $fd) {
        $this->base = $base;

        $this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE);

        $this->bev->setCallbacks(array($this, "echoReadCallback"), NULL,
            array($this, "echoEventCallback"), NULL);

        if (!$this->bev->enable(Event::READ)) {
            echo "Failed to enable READ\n";
            return;
        }
    }

    public function echoReadCallback($bev, $ctx) {
        // Copy all the data from the input buffer to the output buffer
        
        // Variant #1
        $bev->output->addBuffer($bev->input);

        /* Variant #2 */
        /*
        $input    = $bev->getInput();
        $output = $bev->getOutput();
        $output->addBuffer($input);
        */
    }

    public function echoEventCallback($bev, $events, $ctx) {
        if ($events & EventBufferEvent::ERROR) {
            echo "Error from bufferevent\n";
        }

        if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) {
            //$bev->free();
            $this->__destruct();
        }
    }
}

class MyListener {
    public $base,
        $listener,
        $socket;
    private $conn = array();

    public function __destruct() {
        foreach ($this->conn as &$c) $c = NULL;
    }

    public function __construct($port) {
        $this->base = new EventBase();
        if (!$this->base) {
            echo "Couldn't open event base";
            exit(1);
        }

        // Variant #1
        /*
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if (!socket_bind($this->socket, '0.0.0.0', $port)) {
            echo "Unable to bind socket\n";
            exit(1);
        }
        $this->listener = new EventListener($this->base,
            array($this, "acceptConnCallback"), $this->base,
            EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE,
            -1, $this->socket);
         */

        // Variant #2
         $this->listener = new EventListener($this->base,
             array($this, "acceptConnCallback"), $this->base,
             EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1,
             "0.0.0.0:$port");

        if (!$this->listener) {
            echo "Couldn't create listener";
            exit(1);
        }

        $this->listener->setErrorCallback(array($this, "accept_error_cb"));
    }

    public function dispatch() {
        $this->base->dispatch();
    }

    // This callback is invoked when there is data to read on $bev
    public function acceptConnCallback($listener, $fd, $address, $ctx) {
        // We got a new connection! Set up a bufferevent for it. */
        $base = $this->base;
        $this->conn[] = new MyListenerConnection($base, $fd);
    }

    public function accept_error_cb($listener, $ctx) {
        $base = $this->base;

        fprintf(STDERR, "Got an error %d (%s) on the listener. "
            ."Shutting down.\n",
            EventUtil::getLastSocketErrno(),
            EventUtil::getLastSocketError());

        $base->exit(NULL);
    }
}

$port = 9808;

if ($argc > 1) {
    $port = (int) $argv[1];
}
if ($port <= 0 || $port > 65535) {
    exit("Invalid port");
}

$l = new MyListener($port);
$l->dispatch();
?>
]]>
   </programlisting>
  </example>
 </refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
