<commit_before>/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
   Copyright (C) 2009 Red Hat, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include <netinet/in.h> // IPPROTO_TCP
#include <netinet/tcp.h> // TCP_NODELAY
#include <fcntl.h>
#include <stddef.h> // NULL
#include <errno.h>
#include <spice/macros.h>
#include <spice/vd_agent.h>
#include "common/marshaller.h"
#include "common/messages.h"
#include "server/demarshallers.h"
#include "server/generated_marshallers.h"
#include "spice.h"
#include "red_common.h"
#include "reds.h"
#include "red_channel.h"
#include "inputs_channel.h"

// TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel
// since it was defined once in reds.c which contained both.
// Now that they are split we can give a more fitting value for inputs - what
// should it be?
#define REDS_AGENT_WINDOW_SIZE 10
#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1

// approximate max receive message size
#define RECEIVE_BUF_SIZE \
    (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)

struct SpiceKbdState {
    int dummy;
};

struct SpiceMouseState {
    int dummy;
};

struct SpiceTabletState {
    int dummy;
};

typedef struct InputsChannel {
    RedChannel base;
    uint8_t recv_buf[RECEIVE_BUF_SIZE];
    VDAgentMouseState mouse_state;
    uint32_t motion_count;
} InputsChannel;

enum {
    PIPE_ITEM_INIT = SPICE_MSG_INPUTS_INIT,
    PIPE_ITEM_MOUSE_MOTION_ACK = SPICE_MSG_INPUTS_MOUSE_MOTION_ACK,
    PIPE_ITEM_KEY_MODIFIERS = SPICE_MSG_INPUTS_KEY_MODIFIERS,
    PIPE_ITEM_MIGRATE = SPICE_MSG_MIGRATE,
};

typedef struct InputsPipeItem {
    PipeItem base;
    SpiceMarshaller *m;
    uint8_t *data;      /* If the marshaller malloced, pointer is here */
} InputsPipeItem;

static SpiceKbdInstance *keyboard = NULL;
static SpiceMouseInstance *mouse = NULL;
static SpiceTabletInstance *tablet = NULL;

static SpiceTimer *key_modifiers_timer;

static InputsChannel *g_inputs_channel = NULL;

#define KEY_MODIFIERS_TTL (1000 * 2) /*2sec*/

#define SCROLL_LOCK_SCAN_CODE 0x46
#define NUM_LOCK_SCAN_CODE 0x45
#define CAPS_LOCK_SCAN_CODE 0x3a

int inputs_inited(void)
{
    return !!g_inputs_channel;
}

int inputs_set_keyboard(SpiceKbdInstance *_keyboard)
{
    if (keyboard) {
        red_printf("already have keyboard");
        return -1;
    }
    keyboard = _keyboard;
    keyboard->st = spice_new0(SpiceKbdState, 1);
    return 0;
}

int inputs_set_mouse(SpiceMouseInstance *_mouse)
{
    if (mouse) {
        red_printf("already have mouse");
        return -1;
    }
    mouse = _mouse;
    mouse->st = spice_new0(SpiceMouseState, 1);
    return 0;
}

int inputs_set_tablet(SpiceTabletInstance *_tablet)
{
    if (tablet) {
        red_printf("already have tablet");
        return -1;
    }
    tablet = _tablet;
    tablet->st = spice_new0(SpiceTabletState, 1);
    return 0;
}

int inputs_has_tablet(void)
{
    return !!tablet;
}

void inputs_detach_tablet(SpiceTabletInstance *_tablet)
{
    red_printf("");
    tablet = NULL;
}

void inputs_set_tablet_logical_size(int x_res, int y_res)
{
    SpiceTabletInterface *sif;

    sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
    sif->set_logical_size(tablet, x_res, y_res);
}

const VDAgentMouseState *inputs_get_mouse_state(void)
{
    ASSERT(g_inputs_channel);
    return &g_inputs_channel->mouse_state;
}

static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
{
    InputsChannel *inputs_channel = SPICE_CONTAINEROF(channel, InputsChannel, base);

    return inputs_channel->recv_buf;
}

static void inputs_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
                                               uint8_t *msg)
{
}

#define OUTGOING_OK 0
#define OUTGOING_FAILED -1
#define OUTGOING_BLOCKED 1

#define RED_MOUSE_STATE_TO_LOCAL(state)     \
    ((state & SPICE_MOUSE_BUTTON_MASK_LEFT) |          \
     ((state & SPICE_MOUSE_BUTTON_MASK_MIDDLE) << 1) |   \
     ((state & SPICE_MOUSE_BUTTON_MASK_RIGHT) >> 1))

#define RED_MOUSE_BUTTON_STATE_TO_AGENT(state)                      \
    (((state & SPICE_MOUSE_BUTTON_MASK_LEFT) ? VD_AGENT_LBUTTON_MASK : 0) |    \
     ((state & SPICE_MOUSE_BUTTON_MASK_MIDDLE) ? VD_AGENT_MBUTTON_MASK : 0) |    \
     ((state & SPICE_MOUSE_BUTTON_MASK_RIGHT) ? VD_AGENT_RBUTTON_MASK : 0))
<commit_msg>server/inputs: return NULL on alloc_buf request for too large message<commit_after>/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
   Copyright (C) 2009 Red Hat, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include <netinet/in.h> // IPPROTO_TCP
#include <netinet/tcp.h> // TCP_NODELAY
#include <fcntl.h>
#include <stddef.h> // NULL
#include <errno.h>
#include <spice/macros.h>
#include <spice/vd_agent.h>
#include "common/marshaller.h"
#include "common/messages.h"
#include "server/demarshallers.h"
#include "server/generated_marshallers.h"
#include "spice.h"
#include "red_common.h"
#include "reds.h"
#include "red_channel.h"
#include "inputs_channel.h"

// TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel
// since it was defined once in reds.c which contained both.
// Now that they are split we can give a more fitting value for inputs - what
// should it be?
#define REDS_AGENT_WINDOW_SIZE 10
#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1

// approximate max receive message size
#define RECEIVE_BUF_SIZE \
    (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)

struct SpiceKbdState {
    int dummy;
};

struct SpiceMouseState {
    int dummy;
};

struct SpiceTabletState {
    int dummy;
};

typedef struct InputsChannel {
    RedChannel base;
    uint8_t recv_buf[RECEIVE_BUF_SIZE];
    VDAgentMouseState mouse_state;
    uint32_t motion_count;
} InputsChannel;

enum {
    PIPE_ITEM_INIT = SPICE_MSG_INPUTS_INIT,
    PIPE_ITEM_MOUSE_MOTION_ACK = SPICE_MSG_INPUTS_MOUSE_MOTION_ACK,
    PIPE_ITEM_KEY_MODIFIERS = SPICE_MSG_INPUTS_KEY_MODIFIERS,
    PIPE_ITEM_MIGRATE = SPICE_MSG_MIGRATE,
};

typedef struct InputsPipeItem {
    PipeItem base;
    SpiceMarshaller *m;
    uint8_t *data;      /* If the marshaller malloced, pointer is here */
} InputsPipeItem;

static SpiceKbdInstance *keyboard = NULL;
static SpiceMouseInstance *mouse = NULL;
static SpiceTabletInstance *tablet = NULL;

static SpiceTimer *key_modifiers_timer;

static InputsChannel *g_inputs_channel = NULL;

#define KEY_MODIFIERS_TTL (1000 * 2) /*2sec*/

#define SCROLL_LOCK_SCAN_CODE 0x46
#define NUM_LOCK_SCAN_CODE 0x45
#define CAPS_LOCK_SCAN_CODE 0x3a

int inputs_inited(void)
{
    return !!g_inputs_channel;
}

int inputs_set_keyboard(SpiceKbdInstance *_keyboard)
{
    if (keyboard) {
        red_printf("already have keyboard");
        return -1;
    }
    keyboard = _keyboard;
    keyboard->st = spice_new0(SpiceKbdState, 1);
    return 0;
}

int inputs_set_mouse(SpiceMouseInstance *_mouse)
{
    if (mouse) {
        red_printf("already have mouse");
        return -1;
    }
    mouse = _mouse;
    mouse->st = spice_new0(SpiceMouseState, 1);
    return 0;
}

int inputs_set_tablet(SpiceTabletInstance *_tablet)
{
    if (tablet) {
        red_printf("already have tablet");
        return -1;
    }
    tablet = _tablet;
    tablet->st = spice_new0(SpiceTabletState, 1);
    return 0;
}

int inputs_has_tablet(void)
{
    return !!tablet;
}

void inputs_detach_tablet(SpiceTabletInstance *_tablet)
{
    red_printf("");
    tablet = NULL;
}

void inputs_set_tablet_logical_size(int x_res, int y_res)
{
    SpiceTabletInterface *sif;

    sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base);
    sif->set_logical_size(tablet, x_res, y_res);
}

const VDAgentMouseState *inputs_get_mouse_state(void)
{
    ASSERT(g_inputs_channel);
    return &g_inputs_channel->mouse_state;
}

static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header)
{
    InputsChannel *inputs_channel = SPICE_CONTAINEROF(channel, InputsChannel, base);

    if (msg_header->size > RECEIVE_BUF_SIZE) {
        red_printf("error: too large incoming message");
        return NULL;
    }
    return inputs_channel->recv_buf;
}

static void inputs_channel_release_msg_rcv_buf(RedChannel *channel, SpiceDataHeader *msg_header,
                                               uint8_t *msg)
{
}

#define OUTGOING_OK 0
#define OUTGOING_FAILED -1
#define OUTGOING_BLOCKED 1

#define RED_MOUSE_STATE_TO_LOCAL(state)     \
    ((state & SPICE_MOUSE_BUTTON_MASK_LEFT) |          \
     ((state & SPICE_MOUSE_BUTTON_MASK_MIDDLE) << 1) |   \
     ((state & SPICE_MOUSE_BUTTON_MASK_RIGHT) >> 1))

#define RED_MOUSE_BUTTON_STATE_TO_AGENT(state)                      \
    (((state & SPICE_MOUSE_BUTTON_MASK_LEFT) ? VD_AGENT_LBUTTON_MASK : 0) |    \
     ((state & SPICE_MOUSE_BUTTON_MASK_MIDDLE) ? VD_AGENT_MBUTTON_MASK : 0) |    \
     ((state & SPICE_MOUSE_BUTTON_MASK_RIGHT) ? VD_AGENT_RBUTTON_MASK : 0))

{'fraction_non_alphanumeric': 0.090369071964164, 'fraction_numerical': 0.010517090271691499, 'mean_word_length': 3.920939147101102, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6402545', 'n_tokens_mistral': 3711, 'n_tokens_neox': 3650, 'n_words': 875}