function channel_create_stdapi_net_udp_client($req, &$pkt)
 {
     my_print("creating udp client");
     $peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST);
     $peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT);
     # We can't actually do anything with local_host and local_port because PHP
     # doesn't let us specify these values in any of the exposed socket API
     # functions.
     #$local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST);
     #$local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT);
     $sock = connect($peer_host_tlv['value'], $peer_port_tlv['value'], 'udp');
     my_print("UDP channel on {$sock}");
     if (!$sock) {
         return ERROR_CONNECTION_ERROR;
     }
     #
     # If we got here, the connection worked, respond with the new channel ID
     #
     $id = register_channel($sock);
     packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
     add_reader($sock);
     return ERROR_SUCCESS;
 }
function core_channel_interact($req, &$pkt)
{
    global $readers;
    my_print("doing channel interact");
    $chan_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
    $id = $chan_tlv['value'];
    # True means start interacting, False means stop
    $toggle_tlv = packet_get_tlv($req, TLV_TYPE_BOOL);
    $c = get_channel_by_id($id);
    if ($c) {
        if ($toggle_tlv['value']) {
            # Start interacting.  If we're already interacting with this
            # channel, it's an error and we should return failure.
            if (!in_array($c[1], $readers)) {
                # stdout
                add_reader($c[1]);
                # Make sure we don't add the same resource twice in the case
                # that stdin == stderr
                if (array_key_exists(2, $c) && $c[1] != $c[2]) {
                    # stderr
                    add_reader($c[2]);
                }
                $ret = ERROR_SUCCESS;
            } else {
                # Already interacting
                $ret = ERROR_FAILURE;
            }
        } else {
            # Stop interacting.  If we're not interacting yet with this
            # channel, it's an error and we should return failure.
            if (in_array($c[1], $readers)) {
                remove_reader($c[1]);
                # stdout
                remove_reader($c[2]);
                # stderr
                $ret = ERROR_SUCCESS;
            } else {
                # Not interacting.  This is technically failure, but it seems
                # the client sends us two of these requests in quick succession
                # causing the second one to always return failure.  When that
                # happens we fail to clean up properly, so always return
                # success here.
                $ret = ERROR_SUCCESS;
            }
        }
    } else {
        # Not a valid channel
        my_print("Trying to interact with an invalid channel");
        $ret = ERROR_FAILURE;
    }
    return $ret;
}
function core_channel_interact($req, &$pkt)
{
    global $readers;
    my_print("doing channel interact");
    $chan_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
    $id = $chan_tlv['value'];
    # True means start interacting, False means stop
    $toggle_tlv = packet_get_tlv($req, TLV_TYPE_BOOL);
    $c = get_channel_by_id($id);
    if ($c) {
        if ($toggle_tlv['value']) {
            # Start interacting.  If we're already interacting with this
            # channel, it's an error and we should return failure.
            if (!in_array($c[1], $readers)) {
                # stdout
                add_reader($c[1]);
                # stderr, don't care if it fails
                if (array_key_exists(2, $c) && $c[1] != $c[2]) {
                    add_reader($c[2]);
                }
                $ret = ERROR_SUCCESS;
            } else {
                # Already interacting
                $ret = ERROR_FAILURE;
            }
        } else {
            # Stop interacting.  If we're not interacting yet with this
            # channel, it's an error and we should return failure.
            if (in_array($c[1], $readers)) {
                remove_reader($c[1]);
                # stdout
                remove_reader($c[2]);
                # stderr
                $ret = ERROR_SUCCESS;
            } else {
                # Not interacting
                $ret = ERROR_FAILURE;
            }
        }
    } else {
        # Not a valid channel
        $ret = ERROR_FAILURE;
    }
    return $ret;
}