|
Packit Service |
ca3877 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
Packit Service |
ca3877 |
/*
|
|
Packit Service |
ca3877 |
* soup-websocket-connection.c: This file was originally part of Cockpit.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Copyright 2013, 2014 Red Hat, Inc.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Cockpit is free software; you can redistribute it and/or modify it
|
|
Packit Service |
ca3877 |
* under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
ca3877 |
* the Free Software Foundation; either version 2.1 of the License, or
|
|
Packit Service |
ca3877 |
* (at your option) any later version.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Cockpit is distributed in the hope that it will be useful, but
|
|
Packit Service |
ca3877 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
ca3877 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
ca3877 |
* Lesser General Public License for more details.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
ca3877 |
* along with this library; If not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include "config.h"
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include <string.h>
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include "soup-websocket-connection.h"
|
|
Packit Service |
ca3877 |
#include "soup-enum-types.h"
|
|
Packit Service |
ca3877 |
#include "soup-uri.h"
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/*
|
|
Packit Service |
ca3877 |
* SECTION:websocketconnection
|
|
Packit Service |
ca3877 |
* @title: SoupWebsocketConnection
|
|
Packit Service |
ca3877 |
* @short_description: A WebSocket connection
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* A #SoupWebsocketConnection is a WebSocket connection to a peer.
|
|
Packit Service |
ca3877 |
* This API is modeled after the W3C API for interacting with
|
|
Packit Service |
ca3877 |
* WebSockets.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The #SoupWebsocketConnection:state property will indicate the
|
|
Packit Service |
ca3877 |
* state of the connection.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Use soup_websocket_connection_send() to send a message to the peer.
|
|
Packit Service |
ca3877 |
* When a message is received the #SoupWebsocketConnection::message
|
|
Packit Service |
ca3877 |
* signal will fire.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The soup_websocket_connection_close() function will perform an
|
|
Packit Service |
ca3877 |
* orderly close of the connection. The
|
|
Packit Service |
ca3877 |
* #SoupWebsocketConnection::closed signal will fire once the
|
|
Packit Service |
ca3877 |
* connection closes, whether it was initiated by this side or the
|
|
Packit Service |
ca3877 |
* peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Connect to the #SoupWebsocketConnection::closing signal to detect
|
|
Packit Service |
ca3877 |
* when either peer begins closing the connection.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* A class representing a WebSocket connection.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnectionClass:
|
|
Packit Service |
ca3877 |
* @message: default handler for the #SoupWebsocketConnection::message signal
|
|
Packit Service |
ca3877 |
* @error: default handler for the #SoupWebsocketConnection::error signal
|
|
Packit Service |
ca3877 |
* @closing: the default handler for the #SoupWebsocketConnection:closing signal
|
|
Packit Service |
ca3877 |
* @closed: default handler for the #SoupWebsocketConnection::closed signal
|
|
Packit Service |
ca3877 |
* @pong: default handler for the #SoupWebsocketConnection::pong signal
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The abstract base class for #SoupWebsocketConnection
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
enum {
|
|
Packit Service |
ca3877 |
PROP_0,
|
|
Packit Service |
ca3877 |
PROP_IO_STREAM,
|
|
Packit Service |
ca3877 |
PROP_CONNECTION_TYPE,
|
|
Packit Service |
ca3877 |
PROP_URI,
|
|
Packit Service |
ca3877 |
PROP_ORIGIN,
|
|
Packit Service |
ca3877 |
PROP_PROTOCOL,
|
|
Packit Service |
ca3877 |
PROP_STATE,
|
|
Packit Service |
ca3877 |
PROP_MAX_INCOMING_PAYLOAD_SIZE,
|
|
Packit Service |
ca3877 |
PROP_KEEPALIVE_INTERVAL,
|
|
Packit Service |
ca3877 |
};
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
enum {
|
|
Packit Service |
ca3877 |
MESSAGE,
|
|
Packit Service |
ca3877 |
ERROR,
|
|
Packit Service |
ca3877 |
CLOSING,
|
|
Packit Service |
ca3877 |
CLOSED,
|
|
Packit Service |
ca3877 |
PONG,
|
|
Packit Service |
ca3877 |
NUM_SIGNALS
|
|
Packit Service |
ca3877 |
};
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static guint signals[NUM_SIGNALS] = { 0, };
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
typedef enum {
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_QUEUE_NORMAL = 0,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_QUEUE_URGENT = 1 << 0,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_QUEUE_LAST = 1 << 1,
|
|
Packit Service |
ca3877 |
} SoupWebsocketQueueFlags;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
typedef struct {
|
|
Packit Service |
ca3877 |
GBytes *data;
|
|
Packit Service |
ca3877 |
gsize sent;
|
|
Packit Service |
ca3877 |
gsize amount;
|
|
Packit Service |
ca3877 |
SoupWebsocketQueueFlags flags;
|
|
Packit Service |
ca3877 |
gboolean pending;
|
|
Packit Service |
ca3877 |
} Frame;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
struct _SoupWebsocketConnectionPrivate {
|
|
Packit Service |
ca3877 |
GIOStream *io_stream;
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionType connection_type;
|
|
Packit Service |
ca3877 |
SoupURI *uri;
|
|
Packit Service |
ca3877 |
char *origin;
|
|
Packit Service |
ca3877 |
char *protocol;
|
|
Packit Service |
ca3877 |
guint64 max_incoming_payload_size;
|
|
Packit Service |
ca3877 |
guint keepalive_interval;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
gushort peer_close_code;
|
|
Packit Service |
ca3877 |
char *peer_close_data;
|
|
Packit Service |
ca3877 |
gboolean close_sent;
|
|
Packit Service |
ca3877 |
gboolean close_received;
|
|
Packit Service |
ca3877 |
gboolean dirty_close;
|
|
Packit Service |
ca3877 |
GSource *close_timeout;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GMainContext *main_context;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
gboolean io_closing;
|
|
Packit Service |
ca3877 |
gboolean io_closed;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GPollableInputStream *input;
|
|
Packit Service |
ca3877 |
GSource *input_source;
|
|
Packit Service |
ca3877 |
GByteArray *incoming;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GPollableOutputStream *output;
|
|
Packit Service |
ca3877 |
GSource *output_source;
|
|
Packit Service |
ca3877 |
GQueue outgoing;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Current message being assembled */
|
|
Packit Service |
ca3877 |
guint8 message_opcode;
|
|
Packit Service |
ca3877 |
GByteArray *message_data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GSource *keepalive_timeout;
|
|
Packit Service |
ca3877 |
};
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024
|
|
Packit Service |
f07534 |
#define READ_BUFFER_SIZE 1024
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_DEFINE_TYPE_WITH_PRIVATE (SoupWebsocketConnection, soup_websocket_connection, G_TYPE_OBJECT)
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void queue_frame (SoupWebsocketConnection *self, SoupWebsocketQueueFlags flags,
|
|
Packit Service |
ca3877 |
gpointer data, gsize len, gsize amount);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void protocol_error_and_close (SoupWebsocketConnection *self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
static gboolean on_web_socket_input (GObject *pollable_stream,
|
|
Packit Service |
f07534 |
gpointer user_data);
|
|
Packit Service |
f07534 |
static gboolean on_web_socket_output (GObject *pollable_stream,
|
|
Packit Service |
f07534 |
gpointer user_data);
|
|
Packit Service |
f07534 |
|
|
Packit Service |
e0d935 |
/* Code below is based on g_utf8_validate() implementation,
|
|
Packit Service |
e0d935 |
* but handling NULL characters as valid, as expected by
|
|
Packit Service |
e0d935 |
* WebSockets and compliant with RFC 3629.
|
|
Packit Service |
e0d935 |
*/
|
|
Packit Service |
e0d935 |
#define VALIDATE_BYTE(mask, expect) \
|
|
Packit Service |
e0d935 |
G_STMT_START { \
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY((*(guchar *)p & (mask)) != (expect))) \
|
|
Packit Service |
e0d935 |
return FALSE; \
|
|
Packit Service |
e0d935 |
} G_STMT_END
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
/* see IETF RFC 3629 Section 4 */
|
|
Packit Service |
e0d935 |
static gboolean
|
|
Packit Service |
e0d935 |
utf8_validate (const char *str,
|
|
Packit Service |
e0d935 |
gsize max_len)
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
{
|
|
Packit Service |
e0d935 |
const gchar *p;
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
for (p = str; ((p - str) < max_len); p++) {
|
|
Packit Service |
e0d935 |
if (*(guchar *)p < 128)
|
|
Packit Service |
e0d935 |
/* done */;
|
|
Packit Service |
e0d935 |
else {
|
|
Packit Service |
e0d935 |
if (*(guchar *)p < 0xe0) { /* 110xxxxx */
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY (max_len - (p - str) < 2))
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY (*(guchar *)p < 0xc2))
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
} else {
|
|
Packit Service |
e0d935 |
if (*(guchar *)p < 0xf0) { /* 1110xxxx */
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY (max_len - (p - str) < 3))
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
switch (*(guchar *)p++ & 0x0f) {
|
|
Packit Service |
e0d935 |
case 0:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xe0, 0xa0); /* 0xa0 ... 0xbf */
|
|
Packit Service |
e0d935 |
break;
|
|
Packit Service |
e0d935 |
case 0x0d:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xe0, 0x80); /* 0x80 ... 0x9f */
|
|
Packit Service |
e0d935 |
break;
|
|
Packit Service |
e0d935 |
default:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
} else if (*(guchar *)p < 0xf5) { /* 11110xxx excluding out-of-range */
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY (max_len - (p - str) < 4))
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
switch (*(guchar *)p++ & 0x07) {
|
|
Packit Service |
e0d935 |
case 0:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
|
Packit Service |
e0d935 |
if (G_UNLIKELY((*(guchar *)p & 0x30) == 0))
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
break;
|
|
Packit Service |
e0d935 |
case 4:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xf0, 0x80); /* 0x80 ... 0x8f */
|
|
Packit Service |
e0d935 |
break;
|
|
Packit Service |
e0d935 |
default:
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
p++;
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
|
Packit Service |
e0d935 |
} else {
|
|
Packit Service |
e0d935 |
return FALSE;
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
p++;
|
|
Packit Service |
e0d935 |
VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
return TRUE;
|
|
Packit Service |
e0d935 |
}
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
e0d935 |
#undef VALIDATE_BYTE
|
|
Packit Service |
e0d935 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
frame_free (gpointer data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
Frame *frame = data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (frame) {
|
|
Packit Service |
ca3877 |
g_bytes_unref (frame->data);
|
|
Packit Service |
ca3877 |
g_slice_free (Frame, frame);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_init (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv = self->pv = soup_websocket_connection_get_instance_private (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv->incoming = g_byte_array_sized_new (1024);
|
|
Packit Service |
ca3877 |
g_queue_init (&pv->outgoing);
|
|
Packit Service |
ca3877 |
pv->main_context = g_main_context_ref_thread_default ();
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
on_iostream_closed (GObject *source,
|
|
Packit Service |
ca3877 |
GAsyncResult *result,
|
|
Packit Service |
ca3877 |
gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = user_data;
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
GError *error = NULL;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* We treat connection as closed even if close fails */
|
|
Packit Service |
ca3877 |
pv->io_closed = TRUE;
|
|
Packit Service |
ca3877 |
g_io_stream_close_finish (pv->io_stream, result, &error);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (error) {
|
|
Packit Service |
ca3877 |
g_debug ("error closing web socket stream: %s", error->message);
|
|
Packit Service |
ca3877 |
if (!pv->dirty_close)
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[ERROR], 0, error);
|
|
Packit Service |
ca3877 |
pv->dirty_close = TRUE;
|
|
Packit Service |
ca3877 |
g_error_free (error);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_assert (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_CLOSED);
|
|
Packit Service |
ca3877 |
g_debug ("closed: completed io stream close");
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[CLOSED], 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_object_unref (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_start_input_source (SoupWebsocketConnection *self)
|
|
Packit Service |
f07534 |
{
|
|
Packit Service |
f07534 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
if (pv->input_source)
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
pv->input_source = g_pollable_input_stream_create_source (pv->input, NULL);
|
|
Packit Service |
f07534 |
g_source_set_callback (pv->input_source, (GSourceFunc)on_web_socket_input, self, NULL);
|
|
Packit Service |
f07534 |
g_source_attach (pv->input_source, pv->main_context);
|
|
Packit Service |
f07534 |
}
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_input_source (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->input_source) {
|
|
Packit Service |
ca3877 |
g_debug ("stopping input source");
|
|
Packit Service |
ca3877 |
g_source_destroy (pv->input_source);
|
|
Packit Service |
ca3877 |
g_source_unref (pv->input_source);
|
|
Packit Service |
ca3877 |
pv->input_source = NULL;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_start_output_source (SoupWebsocketConnection *self)
|
|
Packit Service |
f07534 |
{
|
|
Packit Service |
f07534 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
if (pv->output_source)
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
pv->output_source = g_pollable_output_stream_create_source (pv->output, NULL);
|
|
Packit Service |
f07534 |
g_source_set_callback (pv->output_source, (GSourceFunc)on_web_socket_output, self, NULL);
|
|
Packit Service |
f07534 |
g_source_attach (pv->output_source, pv->main_context);
|
|
Packit Service |
f07534 |
}
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_output_source (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->output_source) {
|
|
Packit Service |
ca3877 |
g_debug ("stopping output source");
|
|
Packit Service |
ca3877 |
g_source_destroy (pv->output_source);
|
|
Packit Service |
ca3877 |
g_source_unref (pv->output_source);
|
|
Packit Service |
ca3877 |
pv->output_source = NULL;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
keepalive_stop_timeout (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->keepalive_timeout) {
|
|
Packit Service |
ca3877 |
g_source_destroy (pv->keepalive_timeout);
|
|
Packit Service |
ca3877 |
g_source_unref (pv->keepalive_timeout);
|
|
Packit Service |
ca3877 |
pv->keepalive_timeout = NULL;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
close_io_stop_timeout (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->close_timeout) {
|
|
Packit Service |
ca3877 |
g_source_destroy (pv->close_timeout);
|
|
Packit Service |
ca3877 |
g_source_unref (pv->close_timeout);
|
|
Packit Service |
ca3877 |
pv->close_timeout = NULL;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
close_io_stream (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
keepalive_stop_timeout (self);
|
|
Packit Service |
ca3877 |
close_io_stop_timeout (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!pv->io_closing) {
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_input_source (self);
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_output_source (self);
|
|
Packit Service |
ca3877 |
pv->io_closing = TRUE;
|
|
Packit Service |
ca3877 |
g_debug ("closing io stream");
|
|
Packit Service |
ca3877 |
g_io_stream_close_async (pv->io_stream, G_PRIORITY_DEFAULT,
|
|
Packit Service |
ca3877 |
NULL, on_iostream_closed, g_object_ref (self));
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_object_notify (G_OBJECT (self), "state");
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
shutdown_wr_io_stream (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
GSocket *socket;
|
|
Packit Service |
ca3877 |
GError *error = NULL;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_output_source (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (G_IS_SOCKET_CONNECTION (pv->io_stream)) {
|
|
Packit Service |
ca3877 |
socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (pv->io_stream));
|
|
Packit Service |
ca3877 |
g_socket_shutdown (socket, FALSE, TRUE, &error);
|
|
Packit Service |
ca3877 |
if (error != NULL) {
|
|
Packit Service |
ca3877 |
g_debug ("error shutting down io stream: %s", error->message);
|
|
Packit Service |
ca3877 |
g_error_free (error);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_object_notify (G_OBJECT (self), "state");
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gboolean
|
|
Packit Service |
ca3877 |
on_timeout_close_io (gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (user_data);
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv->close_timeout = 0;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("peer did not close io when expected");
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return FALSE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
close_io_after_timeout (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
const int timeout = 5;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->close_timeout)
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("waiting %d seconds for peer to close io", timeout);
|
|
Packit Service |
ca3877 |
pv->close_timeout = g_timeout_source_new_seconds (timeout);
|
|
Packit Service |
ca3877 |
g_source_set_callback (pv->close_timeout, on_timeout_close_io, self, NULL);
|
|
Packit Service |
ca3877 |
g_source_attach (pv->close_timeout, pv->main_context);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
xor_with_mask (const guint8 *mask,
|
|
Packit Service |
ca3877 |
guint8 *data,
|
|
Packit Service |
ca3877 |
gsize len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
gsize n;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Do the masking */
|
|
Packit Service |
ca3877 |
for (n = 0; n < len; n++)
|
|
Packit Service |
ca3877 |
data[n] ^= mask[n & 3];
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
send_message (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
SoupWebsocketQueueFlags flags,
|
|
Packit Service |
ca3877 |
guint8 opcode,
|
|
Packit Service |
ca3877 |
const guint8 *data,
|
|
Packit Service |
ca3877 |
gsize length)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
gsize buffered_amount = length;
|
|
Packit Service |
ca3877 |
GByteArray *bytes;
|
|
Packit Service |
ca3877 |
gsize frame_len;
|
|
Packit Service |
ca3877 |
guint8 *outer;
|
|
Packit Service |
ca3877 |
guint8 *mask = 0;
|
|
Packit Service |
ca3877 |
guint8 *at;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!(soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_OPEN)) {
|
|
Packit Service |
ca3877 |
g_debug ("Ignoring message since the connection is closed or is closing");
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
bytes = g_byte_array_sized_new (14 + length);
|
|
Packit Service |
ca3877 |
outer = bytes->data;
|
|
Packit Service |
ca3877 |
outer[0] = 0x80 | opcode;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* If control message, check payload size */
|
|
Packit Service |
ca3877 |
if (opcode & 0x08) {
|
|
Packit Service |
ca3877 |
if (length > 125) {
|
|
Packit Service |
ca3877 |
g_warning ("WebSocket control message payload exceeds size limit");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
buffered_amount = 0;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (length < 126) {
|
|
Packit Service |
ca3877 |
outer[1] = (0xFF & length); /* mask | 7-bit-len */
|
|
Packit Service |
ca3877 |
bytes->len = 2;
|
|
Packit Service |
ca3877 |
} else if (length < 65536) {
|
|
Packit Service |
ca3877 |
outer[1] = 126; /* mask | 16-bit-len */
|
|
Packit Service |
ca3877 |
outer[2] = (length >> 8) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[3] = (length >> 0) & 0xFF;
|
|
Packit Service |
ca3877 |
bytes->len = 4;
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
outer[1] = 127; /* mask | 64-bit-len */
|
|
Packit Service |
ca3877 |
#if GLIB_SIZEOF_SIZE_T > 4
|
|
Packit Service |
ca3877 |
outer[2] = (length >> 56) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[3] = (length >> 48) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[4] = (length >> 40) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[5] = (length >> 32) & 0xFF;
|
|
Packit Service |
ca3877 |
#else
|
|
Packit Service |
ca3877 |
outer[2] = outer[3] = outer[4] = outer[5] = 0;
|
|
Packit Service |
ca3877 |
#endif
|
|
Packit Service |
ca3877 |
outer[6] = (length >> 24) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[7] = (length >> 16) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[8] = (length >> 8) & 0xFF;
|
|
Packit Service |
ca3877 |
outer[9] = (length >> 0) & 0xFF;
|
|
Packit Service |
ca3877 |
bytes->len = 10;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* The server side doesn't need to mask, so we don't. There's
|
|
Packit Service |
ca3877 |
* probably a client somewhere that's not expecting it.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
if (self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_CLIENT) {
|
|
Packit Service |
ca3877 |
guint32 rnd = g_random_int ();
|
|
Packit Service |
ca3877 |
outer[1] |= 0x80;
|
|
Packit Service |
ca3877 |
mask = outer + bytes->len;
|
|
Packit Service |
ca3877 |
memcpy (mask, &rnd, sizeof (rnd));
|
|
Packit Service |
ca3877 |
bytes->len += 4;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
at = bytes->data + bytes->len;
|
|
Packit Service |
ca3877 |
g_byte_array_append (bytes, data, length);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_CLIENT)
|
|
Packit Service |
ca3877 |
xor_with_mask (mask, at, length);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
frame_len = bytes->len;
|
|
Packit Service |
ca3877 |
queue_frame (self, flags, g_byte_array_free (bytes, FALSE),
|
|
Packit Service |
ca3877 |
frame_len, buffered_amount);
|
|
Packit Service |
ca3877 |
g_debug ("queued %d frame of len %u", (int)opcode, (guint)frame_len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
send_close (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
SoupWebsocketQueueFlags flags,
|
|
Packit Service |
ca3877 |
gushort code,
|
|
Packit Service |
ca3877 |
const char *reason)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
/* Note that send_message truncates as expected */
|
|
Packit Service |
ca3877 |
char buffer[128];
|
|
Packit Service |
ca3877 |
gsize len = 0;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (code != 0) {
|
|
Packit Service |
ca3877 |
buffer[len++] = code >> 8;
|
|
Packit Service |
ca3877 |
buffer[len++] = code & 0xFF;
|
|
Packit Service |
ca3877 |
if (reason)
|
|
Packit Service |
ca3877 |
len += g_strlcpy (buffer + len, reason, sizeof (buffer) - len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
send_message (self, flags, 0x08, (guint8 *)buffer, len);
|
|
Packit Service |
ca3877 |
self->pv->close_sent = TRUE;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
keepalive_stop_timeout (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
emit_error_and_close (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
GError *error,
|
|
Packit Service |
ca3877 |
gboolean prejudice)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
gboolean ignore = FALSE;
|
|
Packit Service |
ca3877 |
gushort code;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_CLOSED) {
|
|
Packit Service |
ca3877 |
g_error_free (error);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (error && error->domain == SOUP_WEBSOCKET_ERROR)
|
|
Packit Service |
ca3877 |
code = error->code;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
code = SOUP_WEBSOCKET_CLOSE_GOING_AWAY;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
self->pv->dirty_close = TRUE;
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[ERROR], 0, error);
|
|
Packit Service |
ca3877 |
g_error_free (error);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* If already closing, just ignore this stuff */
|
|
Packit Service |
ca3877 |
switch (soup_websocket_connection_get_state (self)) {
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_STATE_CLOSED:
|
|
Packit Service |
ca3877 |
ignore = TRUE;
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_STATE_CLOSING:
|
|
Packit Service |
ca3877 |
ignore = !prejudice;
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (ignore) {
|
|
Packit Service |
ca3877 |
g_debug ("already closing/closed, ignoring error");
|
|
Packit Service |
ca3877 |
} else if (prejudice) {
|
|
Packit Service |
ca3877 |
g_debug ("forcing close due to error");
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
g_debug ("requesting close due to error");
|
|
Packit Service |
ca3877 |
send_close (self, SOUP_WEBSOCKET_QUEUE_URGENT | SOUP_WEBSOCKET_QUEUE_LAST, code, NULL);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
protocol_error_and_close_full (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
gboolean prejudice)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GError *error;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
error = g_error_new_literal (SOUP_WEBSOCKET_ERROR,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR,
|
|
Packit Service |
ca3877 |
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ?
|
|
Packit Service |
ca3877 |
"Received invalid WebSocket response from the client" :
|
|
Packit Service |
ca3877 |
"Received invalid WebSocket response from the server");
|
|
Packit Service |
ca3877 |
emit_error_and_close (self, error, prejudice);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
protocol_error_and_close (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
protocol_error_and_close_full (self, FALSE);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
bad_data_error_and_close (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GError *error;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
error = g_error_new_literal (SOUP_WEBSOCKET_ERROR,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_CLOSE_BAD_DATA,
|
|
Packit Service |
ca3877 |
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ?
|
|
Packit Service |
ca3877 |
"Received invalid WebSocket data from the client" :
|
|
Packit Service |
ca3877 |
"Received invalid WebSocket data from the server");
|
|
Packit Service |
ca3877 |
emit_error_and_close (self, error, FALSE);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
too_big_error_and_close (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
guint64 payload_len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GError *error;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
error = g_error_new_literal (SOUP_WEBSOCKET_ERROR,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_CLOSE_TOO_BIG,
|
|
Packit Service |
ca3877 |
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ?
|
|
Packit Service |
ca3877 |
"Received extremely large WebSocket data from the client" :
|
|
Packit Service |
ca3877 |
"Received extremely large WebSocket data from the server");
|
|
Packit Service |
ca3877 |
g_debug ("%s is trying to frame of size %" G_GUINT64_FORMAT " or greater, but max supported size is %" G_GUINT64_FORMAT,
|
|
Packit Service |
ca3877 |
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client",
|
|
Packit Service |
ca3877 |
payload_len, self->pv->max_incoming_payload_size);
|
|
Packit Service |
ca3877 |
emit_error_and_close (self, error, TRUE);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
close_connection (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
gushort code,
|
|
Packit Service |
ca3877 |
const char *data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketQueueFlags flags;
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->close_sent) {
|
|
Packit Service |
ca3877 |
g_debug ("close code already sent");
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Validate the closing code received by the peer */
|
|
Packit Service |
ca3877 |
switch (code) {
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_NORMAL:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_GOING_AWAY:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_UNSUPPORTED_DATA:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_BAD_DATA:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_POLICY_VIOLATION:
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_TOO_BIG:
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_NO_EXTENSION:
|
|
Packit Service |
ca3877 |
if (pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER) {
|
|
Packit Service |
ca3877 |
g_debug ("Wrong closing code %d received for a server connection",
|
|
Packit Service |
ca3877 |
code);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case SOUP_WEBSOCKET_CLOSE_SERVER_ERROR:
|
|
Packit Service |
ca3877 |
if (pv->connection_type != SOUP_WEBSOCKET_CONNECTION_SERVER) {
|
|
Packit Service |
ca3877 |
g_debug ("Wrong closing code %d received for a non server connection",
|
|
Packit Service |
ca3877 |
code);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
if (code < 3000) {
|
|
Packit Service |
ca3877 |
g_debug ("Wrong closing code %d received", code);
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[CLOSING], 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->close_received)
|
|
Packit Service |
ca3877 |
g_debug ("responding to close request");
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
flags = 0;
|
|
Packit Service |
ca3877 |
if (pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER && pv->close_received)
|
|
Packit Service |
ca3877 |
flags |= SOUP_WEBSOCKET_QUEUE_LAST;
|
|
Packit Service |
ca3877 |
send_close (self, flags, code, data);
|
|
Packit Service |
ca3877 |
close_io_after_timeout (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
receive_close (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
const guint8 *data,
|
|
Packit Service |
ca3877 |
gsize len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv->peer_close_code = 0;
|
|
Packit Service |
ca3877 |
g_free (pv->peer_close_data);
|
|
Packit Service |
ca3877 |
pv->peer_close_data = NULL;
|
|
Packit Service |
ca3877 |
pv->close_received = TRUE;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (len) {
|
|
Packit Service |
ca3877 |
case 0:
|
|
Packit Service |
ca3877 |
/* Send a clean close when having an empty payload */
|
|
Packit Service |
ca3877 |
close_connection (self, 1000, NULL);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
case 1:
|
|
Packit Service |
ca3877 |
/* Send a protocol error since the close code is incomplete */
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
/* Store the code/data payload */
|
|
Packit Service |
ca3877 |
pv->peer_close_code = (guint16)data[0] << 8 | data[1];
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (len > 2) {
|
|
Packit Service |
ca3877 |
data += 2;
|
|
Packit Service |
ca3877 |
len -= 2;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
e0d935 |
if (!utf8_validate ((const char *)data, len)) {
|
|
Packit Service |
ca3877 |
g_debug ("received non-UTF8 close data: %d '%.*s' %d", (int)len, (int)len, (char *)data, (int)data[0]);
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv->peer_close_data = g_strndup ((char *)data, len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Once we receive close response on server, close immediately */
|
|
Packit Service |
ca3877 |
if (pv->close_sent) {
|
|
Packit Service |
ca3877 |
shutdown_wr_io_stream (self);
|
|
Packit Service |
ca3877 |
if (pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER)
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
close_connection (self, pv->peer_close_code, pv->peer_close_data);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
receive_ping (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
const guint8 *data,
|
|
Packit Service |
ca3877 |
gsize len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
/* Send back a pong with same data */
|
|
Packit Service |
ca3877 |
g_debug ("received ping, responding");
|
|
Packit Service |
ca3877 |
send_message (self, SOUP_WEBSOCKET_QUEUE_URGENT, 0x0A, data, len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
receive_pong (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
const guint8 *data,
|
|
Packit Service |
ca3877 |
gsize len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GByteArray *bytes;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("received pong message");
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
bytes = g_byte_array_sized_new (len + 1);
|
|
Packit Service |
ca3877 |
g_byte_array_append (bytes, data, len);
|
|
Packit Service |
ca3877 |
/* Always null terminate, as a convenience */
|
|
Packit Service |
ca3877 |
g_byte_array_append (bytes, (guchar *)"\0", 1);
|
|
Packit Service |
ca3877 |
/* But don't include the null terminator in the byte count */
|
|
Packit Service |
ca3877 |
bytes->len--;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[PONG], 0, bytes);
|
|
Packit Service |
ca3877 |
g_byte_array_unref (bytes);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
process_contents (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
gboolean control,
|
|
Packit Service |
ca3877 |
gboolean fin,
|
|
Packit Service |
ca3877 |
guint8 opcode,
|
|
Packit Service |
ca3877 |
gconstpointer payload,
|
|
Packit Service |
ca3877 |
gsize payload_len)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
GBytes *message;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f69f0c |
if (pv->close_sent && pv->close_received)
|
|
Packit Service |
f69f0c |
return;
|
|
Packit Service |
f69f0c |
|
|
Packit Service |
ca3877 |
if (control) {
|
|
Packit Service |
ca3877 |
/* Control frames must never be fragmented */
|
|
Packit Service |
ca3877 |
if (!fin) {
|
|
Packit Service |
ca3877 |
g_debug ("received fragmented control frame");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("received control frame %d with %d payload", (int)opcode, (int)payload_len);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (opcode) {
|
|
Packit Service |
ca3877 |
case 0x08:
|
|
Packit Service |
ca3877 |
receive_close (self, payload, payload_len);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case 0x09:
|
|
Packit Service |
ca3877 |
receive_ping (self, payload, payload_len);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case 0x0A:
|
|
Packit Service |
ca3877 |
receive_pong (self, payload, payload_len);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
g_debug ("received unsupported control frame: %d", (int)opcode);
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
} else if (pv->close_received) {
|
|
Packit Service |
ca3877 |
g_debug ("received message after close was received");
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
/* A message frame */
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!fin && opcode) {
|
|
Packit Service |
ca3877 |
/* Initial fragment of a message */
|
|
Packit Service |
ca3877 |
if (pv->message_data) {
|
|
Packit Service |
ca3877 |
g_debug ("received out of order initial message fragment");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
g_debug ("received initial fragment frame %d with %d payload", (int)opcode, (int)payload_len);
|
|
Packit Service |
ca3877 |
} else if (!fin && !opcode) {
|
|
Packit Service |
ca3877 |
/* Middle fragment of a message */
|
|
Packit Service |
ca3877 |
if (!pv->message_data) {
|
|
Packit Service |
ca3877 |
g_debug ("received out of order middle message fragment");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
g_debug ("received middle fragment frame with %d payload", (int)payload_len);
|
|
Packit Service |
ca3877 |
} else if (fin && !opcode) {
|
|
Packit Service |
ca3877 |
/* Last fragment of a message */
|
|
Packit Service |
ca3877 |
if (!pv->message_data) {
|
|
Packit Service |
ca3877 |
g_debug ("received out of order ending message fragment");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
g_debug ("received last fragment frame with %d payload", (int)payload_len);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
/* An unfragmented message */
|
|
Packit Service |
ca3877 |
g_assert (opcode != 0);
|
|
Packit Service |
ca3877 |
if (pv->message_data) {
|
|
Packit Service |
ca3877 |
g_debug ("received unfragmented message when fragment was expected");
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
g_debug ("received frame %d with %d payload", (int)opcode, (int)payload_len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (opcode) {
|
|
Packit Service |
ca3877 |
pv->message_opcode = opcode;
|
|
Packit Service |
ca3877 |
pv->message_data = g_byte_array_sized_new (payload_len + 1);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (pv->message_opcode) {
|
|
Packit Service |
ca3877 |
case 0x01:
|
|
Packit Service |
ca3877 |
case 0x02:
|
|
Packit Service |
ca3877 |
g_byte_array_append (pv->message_data, payload, payload_len);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
g_debug ("received unknown data frame: %d", (int)opcode);
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Actually deliver the message? */
|
|
Packit Service |
ca3877 |
if (fin) {
|
|
Packit Service |
ca3877 |
if (pv->message_opcode == 0x01 &&
|
|
Packit Service |
e0d935 |
!utf8_validate((const char *)pv->message_data->data,
|
|
Packit Service |
e0d935 |
pv->message_data->len)) {
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("received invalid non-UTF8 text data");
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Discard the entire message */
|
|
Packit Service |
ca3877 |
g_byte_array_unref (pv->message_data);
|
|
Packit Service |
ca3877 |
pv->message_data = NULL;
|
|
Packit Service |
ca3877 |
pv->message_opcode = 0;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
bad_data_error_and_close (self);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Always null terminate, as a convenience */
|
|
Packit Service |
ca3877 |
g_byte_array_append (pv->message_data, (guchar *)"\0", 1);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* But don't include the null terminator in the byte count */
|
|
Packit Service |
ca3877 |
pv->message_data->len--;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
opcode = pv->message_opcode;
|
|
Packit Service |
ca3877 |
message = g_byte_array_free_to_bytes (pv->message_data);
|
|
Packit Service |
ca3877 |
pv->message_data = NULL;
|
|
Packit Service |
ca3877 |
pv->message_opcode = 0;
|
|
Packit Service |
ca3877 |
g_debug ("message: delivering %d with %d length",
|
|
Packit Service |
ca3877 |
(int)opcode, (int)g_bytes_get_size (message));
|
|
Packit Service |
ca3877 |
g_signal_emit (self, signals[MESSAGE], 0, (int)opcode, message);
|
|
Packit Service |
ca3877 |
g_bytes_unref (message);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gboolean
|
|
Packit Service |
ca3877 |
process_frame (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
guint8 *header;
|
|
Packit Service |
ca3877 |
guint8 *payload;
|
|
Packit Service |
ca3877 |
guint64 payload_len;
|
|
Packit Service |
ca3877 |
guint8 *mask;
|
|
Packit Service |
ca3877 |
gboolean fin;
|
|
Packit Service |
ca3877 |
gboolean control;
|
|
Packit Service |
ca3877 |
gboolean masked;
|
|
Packit Service |
ca3877 |
guint8 opcode;
|
|
Packit Service |
ca3877 |
gsize len;
|
|
Packit Service |
ca3877 |
gsize at;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
len = self->pv->incoming->len;
|
|
Packit Service |
ca3877 |
if (len < 2)
|
|
Packit Service |
ca3877 |
return FALSE; /* need more data */
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
header = self->pv->incoming->data;
|
|
Packit Service |
ca3877 |
fin = ((header[0] & 0x80) != 0);
|
|
Packit Service |
ca3877 |
control = header[0] & 0x08;
|
|
Packit Service |
ca3877 |
opcode = header[0] & 0x0f;
|
|
Packit Service |
ca3877 |
masked = ((header[1] & 0x80) != 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* We do not support extensions, reserved bits must be 0 */
|
|
Packit Service |
ca3877 |
if (header[0] & 0x70) {
|
|
Packit Service |
ca3877 |
protocol_error_and_close (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (header[1] & 0x7f) {
|
|
Packit Service |
ca3877 |
case 126:
|
|
Packit Service |
ca3877 |
at = 4;
|
|
Packit Service |
ca3877 |
if (len < at)
|
|
Packit Service |
ca3877 |
return FALSE; /* need more data */
|
|
Packit Service |
ca3877 |
payload_len = (((guint16)header[2] << 8) |
|
|
Packit Service |
ca3877 |
((guint16)header[3] << 0));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
case 127:
|
|
Packit Service |
ca3877 |
at = 10;
|
|
Packit Service |
ca3877 |
if (len < at)
|
|
Packit Service |
ca3877 |
return FALSE; /* need more data */
|
|
Packit Service |
ca3877 |
payload_len = (((guint64)header[2] << 56) |
|
|
Packit Service |
ca3877 |
((guint64)header[3] << 48) |
|
|
Packit Service |
ca3877 |
((guint64)header[4] << 40) |
|
|
Packit Service |
ca3877 |
((guint64)header[5] << 32) |
|
|
Packit Service |
ca3877 |
((guint64)header[6] << 24) |
|
|
Packit Service |
ca3877 |
((guint64)header[7] << 16) |
|
|
Packit Service |
ca3877 |
((guint64)header[8] << 8) |
|
|
Packit Service |
ca3877 |
((guint64)header[9] << 0));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
payload_len = header[1] & 0x7f;
|
|
Packit Service |
ca3877 |
at = 2;
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Safety valve */
|
|
Packit Service |
ca3877 |
if (self->pv->max_incoming_payload_size > 0 &&
|
|
Packit Service |
ca3877 |
payload_len >= self->pv->max_incoming_payload_size) {
|
|
Packit Service |
ca3877 |
too_big_error_and_close (self, payload_len);
|
|
Packit Service |
ca3877 |
return FALSE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (len < at + payload_len)
|
|
Packit Service |
ca3877 |
return FALSE; /* need more data */
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
payload = header + at;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (masked) {
|
|
Packit Service |
ca3877 |
mask = header + at;
|
|
Packit Service |
ca3877 |
payload += 4;
|
|
Packit Service |
ca3877 |
at += 4;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (len < at + payload_len)
|
|
Packit Service |
ca3877 |
return FALSE; /* need more data */
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
xor_with_mask (mask, payload, payload_len);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Note that now that we've unmasked, we've modified the buffer, we can
|
|
Packit Service |
ca3877 |
* only return below via discarding or processing the message
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
process_contents (self, control, fin, opcode, payload, payload_len);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Move past the parsed frame */
|
|
Packit Service |
ca3877 |
g_byte_array_remove_range (self->pv->incoming, 0, at + payload_len);
|
|
Packit Service |
ca3877 |
return TRUE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
process_incoming (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
while (process_frame (self))
|
|
Packit Service |
ca3877 |
;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_read (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
GError *error = NULL;
|
|
Packit Service |
ca3877 |
gboolean end = FALSE;
|
|
Packit Service |
ca3877 |
gssize count;
|
|
Packit Service |
ca3877 |
gsize len;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_input_source (self);
|
|
Packit Service |
f07534 |
|
|
Packit Service |
ca3877 |
do {
|
|
Packit Service |
ca3877 |
len = pv->incoming->len;
|
|
Packit Service |
f07534 |
g_byte_array_set_size (pv->incoming, len + READ_BUFFER_SIZE);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
count = g_pollable_input_stream_read_nonblocking (pv->input,
|
|
Packit Service |
ca3877 |
pv->incoming->data + len,
|
|
Packit Service |
f07534 |
READ_BUFFER_SIZE, NULL, &error);
|
|
Packit Service |
ca3877 |
if (count < 0) {
|
|
Packit Service |
ca3877 |
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
|
Packit Service |
ca3877 |
g_error_free (error);
|
|
Packit Service |
ca3877 |
count = 0;
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
emit_error_and_close (self, error, TRUE);
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
} else if (count == 0) {
|
|
Packit Service |
ca3877 |
end = TRUE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
pv->incoming->len = len + count;
|
|
Packit Service |
ca3877 |
} while (count > 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
process_incoming (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (end) {
|
|
Packit Service |
ca3877 |
if (!pv->close_sent || !pv->close_received) {
|
|
Packit Service |
ca3877 |
pv->dirty_close = TRUE;
|
|
Packit Service |
ca3877 |
g_debug ("connection unexpectedly closed by peer");
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
g_debug ("peer has closed socket");
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_start_input_source (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gboolean
|
|
Packit Service |
f07534 |
on_web_socket_input (GObject *pollable_stream,
|
|
Packit Service |
f07534 |
gpointer user_data)
|
|
Packit Service |
f07534 |
{
|
|
Packit Service |
f07534 |
soup_websocket_connection_read (SOUP_WEBSOCKET_CONNECTION (user_data));
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
return G_SOURCE_REMOVE;
|
|
Packit Service |
f07534 |
}
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
static void
|
|
Packit Service |
f07534 |
soup_websocket_connection_write (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
const guint8 *data;
|
|
Packit Service |
ca3877 |
GError *error = NULL;
|
|
Packit Service |
ca3877 |
Frame *frame;
|
|
Packit Service |
ca3877 |
gssize count;
|
|
Packit Service |
ca3877 |
gsize len;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_stop_output_source (self);
|
|
Packit Service |
f07534 |
|
|
Packit Service |
ca3877 |
if (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_CLOSED) {
|
|
Packit Service |
ca3877 |
g_debug ("Ignoring message since the connection is closed");
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
frame = g_queue_peek_head (&pv->outgoing);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* No more frames to send */
|
|
Packit Service |
f07534 |
if (frame == NULL)
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
data = g_bytes_get_data (frame->data, &len;;
|
|
Packit Service |
ca3877 |
g_assert (len > 0);
|
|
Packit Service |
ca3877 |
g_assert (len > frame->sent);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
count = g_pollable_output_stream_write_nonblocking (pv->output,
|
|
Packit Service |
ca3877 |
data + frame->sent,
|
|
Packit Service |
ca3877 |
len - frame->sent,
|
|
Packit Service |
ca3877 |
NULL, &error);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (count < 0) {
|
|
Packit Service |
ca3877 |
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
|
Packit Service |
ca3877 |
g_clear_error (&error);
|
|
Packit Service |
ca3877 |
count = 0;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("failed to send frame because it would block, marking as pending");
|
|
Packit Service |
ca3877 |
frame->pending = TRUE;
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
emit_error_and_close (self, error, TRUE);
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
frame->sent += count;
|
|
Packit Service |
ca3877 |
if (frame->sent >= len) {
|
|
Packit Service |
ca3877 |
g_debug ("sent frame");
|
|
Packit Service |
ca3877 |
g_queue_pop_head (&pv->outgoing);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (frame->flags & SOUP_WEBSOCKET_QUEUE_LAST) {
|
|
Packit Service |
ca3877 |
if (pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER) {
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
shutdown_wr_io_stream (self);
|
|
Packit Service |
ca3877 |
close_io_after_timeout (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
frame_free (frame);
|
|
Packit Service |
f07534 |
|
|
Packit Service |
f07534 |
if (g_queue_is_empty (&pv->outgoing))
|
|
Packit Service |
f07534 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_start_output_source (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
static gboolean
|
|
Packit Service |
f07534 |
on_web_socket_output (GObject *pollable_stream,
|
|
Packit Service |
f07534 |
gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
f07534 |
soup_websocket_connection_write (SOUP_WEBSOCKET_CONNECTION (user_data));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
return G_SOURCE_REMOVE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
queue_frame (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
SoupWebsocketQueueFlags flags,
|
|
Packit Service |
ca3877 |
gpointer data,
|
|
Packit Service |
ca3877 |
gsize len,
|
|
Packit Service |
ca3877 |
gsize amount)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
Frame *frame;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->close_sent == FALSE);
|
|
Packit Service |
ca3877 |
g_return_if_fail (data != NULL);
|
|
Packit Service |
ca3877 |
g_return_if_fail (len > 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
frame = g_slice_new0 (Frame);
|
|
Packit Service |
ca3877 |
frame->data = g_bytes_new_take (data, len);
|
|
Packit Service |
ca3877 |
frame->amount = amount;
|
|
Packit Service |
ca3877 |
frame->flags = flags;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* If urgent put at front of queue */
|
|
Packit Service |
ca3877 |
if (flags & SOUP_WEBSOCKET_QUEUE_URGENT) {
|
|
Packit Service |
ca3877 |
GList *l;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Find out the first frame that is not urgent or partially sent or pending */
|
|
Packit Service |
ca3877 |
for (l = g_queue_peek_head_link (&pv->outgoing); l != NULL; l = l->next) {
|
|
Packit Service |
ca3877 |
Frame *prev = l->data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!(prev->flags & SOUP_WEBSOCKET_QUEUE_URGENT) &&
|
|
Packit Service |
ca3877 |
prev->sent == 0 && !prev->pending)
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_queue_insert_before (&pv->outgoing, l, frame);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
g_queue_push_tail (&pv->outgoing, frame);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_write (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_constructed (GObject *object)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
GInputStream *is;
|
|
Packit Service |
ca3877 |
GOutputStream *os;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_OBJECT_CLASS (soup_websocket_connection_parent_class)->constructed (object);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->io_stream != NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
is = g_io_stream_get_input_stream (pv->io_stream);
|
|
Packit Service |
ca3877 |
g_return_if_fail (G_IS_POLLABLE_INPUT_STREAM (is));
|
|
Packit Service |
ca3877 |
pv->input = G_POLLABLE_INPUT_STREAM (is);
|
|
Packit Service |
ca3877 |
g_return_if_fail (g_pollable_input_stream_can_poll (pv->input));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
os = g_io_stream_get_output_stream (pv->io_stream);
|
|
Packit Service |
ca3877 |
g_return_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (os));
|
|
Packit Service |
ca3877 |
pv->output = G_POLLABLE_OUTPUT_STREAM (os);
|
|
Packit Service |
ca3877 |
g_return_if_fail (g_pollable_output_stream_can_poll (pv->output));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
f07534 |
soup_websocket_connection_start_input_source (self);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_property (GObject *object,
|
|
Packit Service |
ca3877 |
guint prop_id,
|
|
Packit Service |
ca3877 |
GValue *value,
|
|
Packit Service |
ca3877 |
GParamSpec *pspec)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (prop_id) {
|
|
Packit Service |
ca3877 |
case PROP_IO_STREAM:
|
|
Packit Service |
ca3877 |
g_value_set_object (value, soup_websocket_connection_get_io_stream (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_CONNECTION_TYPE:
|
|
Packit Service |
ca3877 |
g_value_set_enum (value, soup_websocket_connection_get_connection_type (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_URI:
|
|
Packit Service |
ca3877 |
g_value_set_boxed (value, soup_websocket_connection_get_uri (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_ORIGIN:
|
|
Packit Service |
ca3877 |
g_value_set_string (value, soup_websocket_connection_get_origin (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_PROTOCOL:
|
|
Packit Service |
ca3877 |
g_value_set_string (value, soup_websocket_connection_get_protocol (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_STATE:
|
|
Packit Service |
ca3877 |
g_value_set_enum (value, soup_websocket_connection_get_state (self));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_MAX_INCOMING_PAYLOAD_SIZE:
|
|
Packit Service |
ca3877 |
g_value_set_uint64 (value, pv->max_incoming_payload_size);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_KEEPALIVE_INTERVAL:
|
|
Packit Service |
ca3877 |
g_value_set_uint (value, pv->keepalive_interval);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_set_property (GObject *object,
|
|
Packit Service |
ca3877 |
guint prop_id,
|
|
Packit Service |
ca3877 |
const GValue *value,
|
|
Packit Service |
ca3877 |
GParamSpec *pspec)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
switch (prop_id) {
|
|
Packit Service |
ca3877 |
case PROP_IO_STREAM:
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->io_stream == NULL);
|
|
Packit Service |
ca3877 |
pv->io_stream = g_value_dup_object (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_CONNECTION_TYPE:
|
|
Packit Service |
ca3877 |
pv->connection_type = g_value_get_enum (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_URI:
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->uri == NULL);
|
|
Packit Service |
ca3877 |
pv->uri = g_value_dup_boxed (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_ORIGIN:
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->origin == NULL);
|
|
Packit Service |
ca3877 |
pv->origin = g_value_dup_string (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_PROTOCOL:
|
|
Packit Service |
ca3877 |
g_return_if_fail (pv->protocol == NULL);
|
|
Packit Service |
ca3877 |
pv->protocol = g_value_dup_string (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_MAX_INCOMING_PAYLOAD_SIZE:
|
|
Packit Service |
ca3877 |
pv->max_incoming_payload_size = g_value_get_uint64 (value);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
case PROP_KEEPALIVE_INTERVAL:
|
|
Packit Service |
ca3877 |
soup_websocket_connection_set_keepalive_interval (self,
|
|
Packit Service |
ca3877 |
g_value_get_uint (value));
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
default:
|
|
Packit Service |
ca3877 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_dispose (GObject *object)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
self->pv->dirty_close = TRUE;
|
|
Packit Service |
ca3877 |
close_io_stream (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_OBJECT_CLASS (soup_websocket_connection_parent_class)->dispose (object);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_finalize (GObject *object)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (object);
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_free (pv->peer_close_data);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_main_context_unref (pv->main_context);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->incoming)
|
|
Packit Service |
ca3877 |
g_byte_array_free (pv->incoming, TRUE);
|
|
Packit Service |
ca3877 |
while (!g_queue_is_empty (&pv->outgoing))
|
|
Packit Service |
ca3877 |
frame_free (g_queue_pop_head (&pv->outgoing));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_clear_object (&pv->io_stream);
|
|
Packit Service |
ca3877 |
g_assert (!pv->input_source);
|
|
Packit Service |
ca3877 |
g_assert (!pv->output_source);
|
|
Packit Service |
ca3877 |
g_assert (pv->io_closing);
|
|
Packit Service |
ca3877 |
g_assert (pv->io_closed);
|
|
Packit Service |
ca3877 |
g_assert (!pv->close_timeout);
|
|
Packit Service |
ca3877 |
g_assert (!pv->keepalive_timeout);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->message_data)
|
|
Packit Service |
ca3877 |
g_byte_array_free (pv->message_data, TRUE);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->uri)
|
|
Packit Service |
ca3877 |
soup_uri_free (pv->uri);
|
|
Packit Service |
ca3877 |
g_free (pv->origin);
|
|
Packit Service |
ca3877 |
g_free (pv->protocol);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_OBJECT_CLASS (soup_websocket_connection_parent_class)->finalize (object);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_class_init (SoupWebsocketConnectionClass *klass)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
gobject_class->constructed = soup_websocket_connection_constructed;
|
|
Packit Service |
ca3877 |
gobject_class->get_property = soup_websocket_connection_get_property;
|
|
Packit Service |
ca3877 |
gobject_class->set_property = soup_websocket_connection_set_property;
|
|
Packit Service |
ca3877 |
gobject_class->dispose = soup_websocket_connection_dispose;
|
|
Packit Service |
ca3877 |
gobject_class->finalize = soup_websocket_connection_finalize;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:io-stream:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The underlying IO stream the WebSocket is communicating
|
|
Packit Service |
ca3877 |
* over.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The input and output streams must be pollable streams.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_IO_STREAM,
|
|
Packit Service |
ca3877 |
g_param_spec_object ("io-stream",
|
|
Packit Service |
ca3877 |
"I/O Stream",
|
|
Packit Service |
ca3877 |
"Underlying I/O stream",
|
|
Packit Service |
ca3877 |
G_TYPE_IO_STREAM,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:connection-type:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The type of connection (client/server).
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_CONNECTION_TYPE,
|
|
Packit Service |
ca3877 |
g_param_spec_enum ("connection-type",
|
|
Packit Service |
ca3877 |
"Connection type",
|
|
Packit Service |
ca3877 |
"Connection type (client/server)",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION_TYPE,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_CONNECTION_UNKNOWN,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:uri:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The URI of the WebSocket.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* For servers this represents the address of the WebSocket,
|
|
Packit Service |
ca3877 |
* and for clients it is the address connected to.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_URI,
|
|
Packit Service |
ca3877 |
g_param_spec_boxed ("uri",
|
|
Packit Service |
ca3877 |
"URI",
|
|
Packit Service |
ca3877 |
"The WebSocket URI",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_URI,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:origin:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The client's Origin.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_ORIGIN,
|
|
Packit Service |
ca3877 |
g_param_spec_string ("origin",
|
|
Packit Service |
ca3877 |
"Origin",
|
|
Packit Service |
ca3877 |
"The WebSocket origin",
|
|
Packit Service |
ca3877 |
NULL,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:protocol:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The chosen protocol, or %NULL if a protocol was not agreed
|
|
Packit Service |
ca3877 |
* upon.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_PROTOCOL,
|
|
Packit Service |
ca3877 |
g_param_spec_string ("protocol",
|
|
Packit Service |
ca3877 |
"Protocol",
|
|
Packit Service |
ca3877 |
"The chosen WebSocket protocol",
|
|
Packit Service |
ca3877 |
NULL,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT_ONLY |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:state:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The current state of the WebSocket.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_STATE,
|
|
Packit Service |
ca3877 |
g_param_spec_enum ("state",
|
|
Packit Service |
ca3877 |
"State",
|
|
Packit Service |
ca3877 |
"State ",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_STATE,
|
|
Packit Service |
ca3877 |
SOUP_WEBSOCKET_STATE_OPEN,
|
|
Packit Service |
ca3877 |
G_PARAM_READABLE |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:max-incoming-payload-size:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The maximum payload size for incoming packets the protocol expects
|
|
Packit Service |
ca3877 |
* or 0 to not limit it.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.56
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_MAX_INCOMING_PAYLOAD_SIZE,
|
|
Packit Service |
ca3877 |
g_param_spec_uint64 ("max-incoming-payload-size",
|
|
Packit Service |
ca3877 |
"Max incoming payload size",
|
|
Packit Service |
ca3877 |
"Max incoming payload size ",
|
|
Packit Service |
ca3877 |
0,
|
|
Packit Service |
ca3877 |
G_MAXUINT64,
|
|
Packit Service |
ca3877 |
MAX_INCOMING_PAYLOAD_SIZE_DEFAULT,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection:keepalive-interval:
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Interval in seconds on when to send a ping message which will
|
|
Packit Service |
ca3877 |
* serve as a keepalive message. If set to 0 the keepalive message is
|
|
Packit Service |
ca3877 |
* disabled.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.58
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
g_object_class_install_property (gobject_class, PROP_KEEPALIVE_INTERVAL,
|
|
Packit Service |
ca3877 |
g_param_spec_uint ("keepalive-interval",
|
|
Packit Service |
ca3877 |
"Keepalive interval",
|
|
Packit Service |
ca3877 |
"Keepalive interval",
|
|
Packit Service |
ca3877 |
0,
|
|
Packit Service |
ca3877 |
G_MAXUINT,
|
|
Packit Service |
ca3877 |
0,
|
|
Packit Service |
ca3877 |
G_PARAM_READWRITE |
|
|
Packit Service |
ca3877 |
G_PARAM_CONSTRUCT |
|
|
Packit Service |
ca3877 |
G_PARAM_STATIC_STRINGS));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection::message:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @type: the type of message contents
|
|
Packit Service |
ca3877 |
* @message: the message data
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Emitted when we receive a message from the peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* As a convenience, the @message data will always be
|
|
Packit Service |
ca3877 |
* NUL-terminated, but the NUL byte will not be included in
|
|
Packit Service |
ca3877 |
* the length count.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
signals[MESSAGE] = g_signal_new ("message",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
G_SIGNAL_RUN_FIRST,
|
|
Packit Service |
ca3877 |
G_STRUCT_OFFSET (SoupWebsocketConnectionClass, message),
|
|
Packit Service |
ca3877 |
NULL, NULL, g_cclosure_marshal_generic,
|
|
Packit Service |
ca3877 |
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_BYTES);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection::error:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @error: the error that occured
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Emitted when an error occurred on the WebSocket. This may
|
|
Packit Service |
ca3877 |
* be fired multiple times. Fatal errors will be followed by
|
|
Packit Service |
ca3877 |
* the #SoupWebsocketConnection::closed signal being emitted.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
signals[ERROR] = g_signal_new ("error",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
G_SIGNAL_RUN_FIRST,
|
|
Packit Service |
ca3877 |
G_STRUCT_OFFSET (SoupWebsocketConnectionClass, error),
|
|
Packit Service |
ca3877 |
NULL, NULL, g_cclosure_marshal_generic,
|
|
Packit Service |
ca3877 |
G_TYPE_NONE, 1, G_TYPE_ERROR);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection::closing:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* This signal will be emitted during an orderly close.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
signals[CLOSING] = g_signal_new ("closing",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
G_SIGNAL_RUN_LAST,
|
|
Packit Service |
ca3877 |
G_STRUCT_OFFSET (SoupWebsocketConnectionClass, closing),
|
|
Packit Service |
ca3877 |
NULL, NULL, g_cclosure_marshal_generic,
|
|
Packit Service |
ca3877 |
G_TYPE_NONE, 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection::closed:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Emitted when the connection has completely closed, either
|
|
Packit Service |
ca3877 |
* due to an orderly close from the peer, one initiated via
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_close() or a fatal error
|
|
Packit Service |
ca3877 |
* condition that caused a close.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* This signal will be emitted once.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
signals[CLOSED] = g_signal_new ("closed",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
G_SIGNAL_RUN_FIRST,
|
|
Packit Service |
ca3877 |
G_STRUCT_OFFSET (SoupWebsocketConnectionClass, closed),
|
|
Packit Service |
ca3877 |
NULL, NULL, g_cclosure_marshal_generic,
|
|
Packit Service |
ca3877 |
G_TYPE_NONE, 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* SoupWebsocketConnection::pong:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @message: the application data (if any)
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Emitted when we receive a Pong frame (solicited or
|
|
Packit Service |
ca3877 |
* unsolicited) from the peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* As a convenience, the @message data will always be
|
|
Packit Service |
ca3877 |
* NUL-terminated, but the NUL byte will not be included in
|
|
Packit Service |
ca3877 |
* the length count.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.60
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
signals[PONG] = g_signal_new ("pong",
|
|
Packit Service |
ca3877 |
SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
G_SIGNAL_RUN_FIRST,
|
|
Packit Service |
ca3877 |
G_STRUCT_OFFSET (SoupWebsocketConnectionClass, pong),
|
|
Packit Service |
ca3877 |
NULL, NULL, g_cclosure_marshal_generic,
|
|
Packit Service |
ca3877 |
G_TYPE_NONE, 1, G_TYPE_BYTES);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_new:
|
|
Packit Service |
ca3877 |
* @stream: a #GIOStream connected to the WebSocket server
|
|
Packit Service |
ca3877 |
* @uri: the URI of the connection
|
|
Packit Service |
ca3877 |
* @type: the type of connection (client/side)
|
|
Packit Service |
ca3877 |
* @origin: (allow-none): the Origin of the client
|
|
Packit Service |
ca3877 |
* @protocol: (allow-none): the subprotocol in use
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Creates a #SoupWebsocketConnection on @stream. This should be
|
|
Packit Service |
ca3877 |
* called after completing the handshake to begin using the WebSocket
|
|
Packit Service |
ca3877 |
* protocol.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: a new #SoupWebsocketConnection
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_new (GIOStream *stream,
|
|
Packit Service |
ca3877 |
SoupURI *uri,
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionType type,
|
|
Packit Service |
ca3877 |
const char *origin,
|
|
Packit Service |
ca3877 |
const char *protocol)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (uri != NULL, NULL);
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (type != SOUP_WEBSOCKET_CONNECTION_UNKNOWN, NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return g_object_new (SOUP_TYPE_WEBSOCKET_CONNECTION,
|
|
Packit Service |
ca3877 |
"io-stream", stream,
|
|
Packit Service |
ca3877 |
"uri", uri,
|
|
Packit Service |
ca3877 |
"connection-type", type,
|
|
Packit Service |
ca3877 |
"origin", origin,
|
|
Packit Service |
ca3877 |
"protocol", protocol,
|
|
Packit Service |
ca3877 |
NULL);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_io_stream:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the I/O stream the WebSocket is communicating over.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: (transfer none): the WebSocket's I/O stream.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
GIOStream *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_io_stream (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->io_stream;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_connection_type:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the connection type (client/server) of the connection.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the connection type
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionType
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_connection_type (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), SOUP_WEBSOCKET_CONNECTION_UNKNOWN);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->connection_type;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_uri:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the URI of the WebSocket.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* For servers this represents the address of the WebSocket, and
|
|
Packit Service |
ca3877 |
* for clients it is the address connected to.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: (transfer none): the URI
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
SoupURI *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_uri (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->uri;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_origin:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the origin of the WebSocket.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: (nullable): the origin, or %NULL
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
const char *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_origin (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->origin;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_protocol:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the protocol chosen via negotiation with the peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: (nullable): the chosen protocol, or %NULL
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
const char *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_protocol (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->protocol;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_state:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the current state of the WebSocket.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the state
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
SoupWebsocketState
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_state (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (self->pv->io_closed)
|
|
Packit Service |
ca3877 |
return SOUP_WEBSOCKET_STATE_CLOSED;
|
|
Packit Service |
ca3877 |
else if (self->pv->io_closing || self->pv->close_sent)
|
|
Packit Service |
ca3877 |
return SOUP_WEBSOCKET_STATE_CLOSING;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
return SOUP_WEBSOCKET_STATE_OPEN;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_close_code:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the close code received from the WebSocket peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* This only becomes valid once the WebSocket is in the
|
|
Packit Service |
ca3877 |
* %SOUP_WEBSOCKET_STATE_CLOSED state. The value will often be in the
|
|
Packit Service |
ca3877 |
* #SoupWebsocketCloseCode enumeration, but may also be an application
|
|
Packit Service |
ca3877 |
* defined close code.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the close code or zero.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
gushort
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_close_code (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->peer_close_code;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_close_data:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Get the close data received from the WebSocket peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* This only becomes valid once the WebSocket is in the
|
|
Packit Service |
ca3877 |
* %SOUP_WEBSOCKET_STATE_CLOSED state. The data may be freed once
|
|
Packit Service |
ca3877 |
* the main loop is run, so copy it if you need to keep it around.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the close data or %NULL
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
const char *
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_close_data (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return self->pv->peer_close_data;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_send_text:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @text: the message contents
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
e0d935 |
* Send a %NULL-terminated text (UTF-8) message to the peer. If you need
|
|
Packit Service |
e0d935 |
* to send text messages containing %NULL characters use
|
|
Packit Service |
e0d935 |
* soup_websocket_connection_send_message() instead.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The message is queued to be sent and will be sent when the main loop
|
|
Packit Service |
ca3877 |
* is run.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_send_text (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
const char *text)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
gsize length;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
g_return_if_fail (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_OPEN);
|
|
Packit Service |
ca3877 |
g_return_if_fail (text != NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
length = strlen (text);
|
|
Packit Service |
e0d935 |
g_return_if_fail (utf8_validate (text, length));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
send_message (self, SOUP_WEBSOCKET_QUEUE_NORMAL, 0x01, (const guint8 *) text, length);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_send_binary:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @data: (array length=length) (element-type guint8): the message contents
|
|
Packit Service |
ca3877 |
* @length: the length of @data
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Send a binary message to the peer.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The message is queued to be sent and will be sent when the main loop
|
|
Packit Service |
ca3877 |
* is run.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_send_binary (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
gconstpointer data,
|
|
Packit Service |
ca3877 |
gsize length)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
g_return_if_fail (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_OPEN);
|
|
Packit Service |
ca3877 |
g_return_if_fail (data != NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
send_message (self, SOUP_WEBSOCKET_QUEUE_NORMAL, 0x02, data, length);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_close:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @code: close code
|
|
Packit Service |
ca3877 |
* @data: (allow-none): close data
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Close the connection in an orderly fashion.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Note that until the #SoupWebsocketConnection::closed signal fires, the connection
|
|
Packit Service |
ca3877 |
* is not yet completely closed. The close message is not even sent until the
|
|
Packit Service |
ca3877 |
* main loop runs.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The @code and @data are sent to the peer along with the close request.
|
|
Packit Service |
ca3877 |
* Note that the @data must be UTF-8 valid.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.50
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_close (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
gushort code,
|
|
Packit Service |
ca3877 |
const char *data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
g_return_if_fail (!pv->close_sent);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (code != SOUP_WEBSOCKET_CLOSE_NO_STATUS &&
|
|
Packit Service |
ca3877 |
code != SOUP_WEBSOCKET_CLOSE_ABNORMAL &&
|
|
Packit Service |
ca3877 |
code != SOUP_WEBSOCKET_CLOSE_TLS_HANDSHAKE);
|
|
Packit Service |
ca3877 |
if (pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER)
|
|
Packit Service |
ca3877 |
g_return_if_fail (code != SOUP_WEBSOCKET_CLOSE_NO_EXTENSION);
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
g_return_if_fail (code != SOUP_WEBSOCKET_CLOSE_SERVER_ERROR);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
close_connection (self, code, data);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_max_incoming_payload_size:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Gets the maximum payload size allowed for incoming packets.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the maximum payload size.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.56
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
guint64
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_max_incoming_payload_size (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), MAX_INCOMING_PAYLOAD_SIZE_DEFAULT);
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return pv->max_incoming_payload_size;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_set_max_incoming_payload_size:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @max_incoming_payload_size: the maximum payload size
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Sets the maximum payload size allowed for incoming packets. It
|
|
Packit Service |
ca3877 |
* does not limit the outgoing packet size.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.56
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_set_max_incoming_payload_size (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
guint64 max_incoming_payload_size)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->max_incoming_payload_size != max_incoming_payload_size) {
|
|
Packit Service |
ca3877 |
pv->max_incoming_payload_size = max_incoming_payload_size;
|
|
Packit Service |
ca3877 |
g_object_notify (G_OBJECT (self), "max-incoming-payload-size");
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_get_keepalive_interval:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Gets the keepalive interval in seconds or 0 if disabled.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Returns: the keepalive interval.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.58
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
guint
|
|
Packit Service |
ca3877 |
soup_websocket_connection_get_keepalive_interval (SoupWebsocketConnection *self)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self), 0);
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return pv->keepalive_interval;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gboolean
|
|
Packit Service |
ca3877 |
on_queue_ping (gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (user_data);
|
|
Packit Service |
ca3877 |
static const char ping_payload[] = "libsoup";
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_debug ("sending ping message");
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
send_message (self, SOUP_WEBSOCKET_QUEUE_NORMAL, 0x09,
|
|
Packit Service |
ca3877 |
(guint8 *) ping_payload, strlen(ping_payload));
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return G_SOURCE_CONTINUE;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_websocket_connection_set_keepalive_interval:
|
|
Packit Service |
ca3877 |
* @self: the WebSocket
|
|
Packit Service |
ca3877 |
* @interval: the interval to send a ping message or 0 to disable it
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Sets the interval in seconds on when to send a ping message which will serve
|
|
Packit Service |
ca3877 |
* as a keepalive message. If set to 0 the keepalive message is disabled.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Since: 2.58
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_websocket_connection_set_keepalive_interval (SoupWebsocketConnection *self,
|
|
Packit Service |
ca3877 |
guint interval)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupWebsocketConnectionPrivate *pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_if_fail (SOUP_IS_WEBSOCKET_CONNECTION (self));
|
|
Packit Service |
ca3877 |
pv = self->pv;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (pv->keepalive_interval != interval) {
|
|
Packit Service |
ca3877 |
pv->keepalive_interval = interval;
|
|
Packit Service |
ca3877 |
g_object_notify (G_OBJECT (self), "keepalive-interval");
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
keepalive_stop_timeout (self);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (interval > 0) {
|
|
Packit Service |
ca3877 |
pv->keepalive_timeout = g_timeout_source_new_seconds (interval);
|
|
Packit Service |
ca3877 |
g_source_set_callback (pv->keepalive_timeout, on_queue_ping, self, NULL);
|
|
Packit Service |
ca3877 |
g_source_attach (pv->keepalive_timeout, pv->main_context);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|