Commit 418bfbcb authored by Olivier Crête's avatar Olivier Crête
Browse files

SPECIFIC: Allow creating a GIOStream with a non-reliable agent

Only usable with the patches from
https://bugzilla.gnome.org/show_bug.cgi?id=697907

SPECIFIC: agent: Fix GSource dispatches for UDP NiceOutputStreams

The GSource created by g_pollable_output_stream_create_source() on a
NiceOutputStream would never have been dispatched, due to not having any
poll events (or anything else); it only works for TCP streams because of
a GCancellable child source which is triggered by the TCP code.

Fix that by making ComponentSource suitable for G_IO_IN and G_IO_OUT
again, and adding that as a child source for UDP output stream GSources.

agent: SPECIFIC: Drop support for reliable streams

libnice should not be implementing pseudo-TCP support internally — it
should provide the PseudoTcpSocket as a separate API which user code can
use if it needs. If this were to be upstreamed, a deprecation path would
have to be written, continuing to support the old API. However, that
would take too long, so this commit just rips it all out.

This commit *must not* be upstreamed.

https://phabricator.collabora.co.uk/T447

agent: Add nice_agent_get_socket() to return a GDatagramBased

TODO: Needs documentation and testing.

This bumps the GLib dependency to 2.46 for GDatagramBased.

agent: Remove nice_agent_get_io_stream()

It has been replaced by nice_agent_get_socket().

TODO: This needs documenting and testing.

TODO: This should *not* go upstream without turning it into a
deprecation-fest.
parent 02c10031
......@@ -46,12 +46,8 @@ libagent_la_SOURCES = \
interfaces.h \
pseudotcp.h \
pseudotcp.c \
iostream.h \
iostream.c \
inputstream.h \
inputstream.c \
outputstream.h \
outputstream.c \
datagram-based.c \
datagram-based.h \
$(BUILT_SOURCES)
libagent_la_LIBADD = \
......
......@@ -158,7 +158,6 @@ struct _NiceAgent
GSource *upnp_timer_source; /* source of upnp timeout timer */
#endif
gchar *software_attribute; /* SOFTWARE attribute */
gboolean reliable; /* property: reliable */
gboolean keepalive_conncheck; /* property: keepalive_conncheck */
GQueue pending_signals;
......
This diff is collapsed.
......@@ -72,15 +72,15 @@
*
* Each stream can receive data in one of two ways: using
* nice_agent_attach_recv() or nice_agent_recv_messages() (and the derived
* #NiceInputStream and #NiceIOStream classes accessible using
* nice_agent_get_io_stream()). nice_agent_attach_recv() is non-blocking: it
* #GDatagramBased class accessible using nice_agent_get_socket()).
* nice_agent_attach_recv() is non-blocking: it
* takes a user-provided callback function and attaches the stream’s socket to
* the provided #GMainContext, invoking the callback in that context for every
* packet received. nice_agent_recv_messages() instead blocks on receiving a
* packet, and writes it directly into a user-provided buffer. This reduces the
* number of callback invokations and (potentially) buffer copies required to
* receive packets. nice_agent_recv_messages() (or #NiceInputStream) is designed
* to be used in a blocking loop in a separate thread.
* receive packets. nice_agent_recv_messages() (or #NiceDatagramBased) is
* designed to be used in a blocking loop in a separate thread.
*
* <example>
* <title>Simple example on how to use libnice</title>
......@@ -172,10 +172,8 @@ G_BEGIN_DECLS
* transmitted the message, or %NULL
* @length: total number of valid bytes contiguously stored in @buffers
*
* Represents a single message received off the network. For reliable
* connections, this is essentially just an array of buffers (specifically,
* @from can be ignored). for non-reliable connections, it represents a single
* packet as received from the OS.
* Represents a single message received off the network, as received from the
* OS.
*
* @n_buffers may be -1 to indicate that @buffers is terminated by a
* #GInputVector with a %NULL buffer pointer.
......@@ -202,10 +200,7 @@ typedef struct {
* @n_buffers: number of #GOutputVectors in @buffers, or -1 to indicate @buffers
* is %NULL-terminated
*
* Represents a single message to transmit on the network. For
* reliable connections, this is essentially just an array of
* buffer. for non-reliable connections, it represents a single packet
* to send to the OS.
* Represents a single message to transmit on the network, to send to the OS.
*
* @n_buffers may be -1 to indicate that @buffers is terminated by a
* #GOutputVector with a %NULL buffer pointer.
......@@ -409,25 +404,6 @@ typedef void (*NiceAgentRecvFunc) (
NiceAgent *
nice_agent_new (GMainContext *ctx, NiceCompatibility compat);
/**
* nice_agent_new_reliable:
* @ctx: The Glib Mainloop Context to use for timers
* @compat: The compatibility mode of the agent
*
* Create a new #NiceAgent in reliable mode. If the connectivity is established
* through ICE-UDP, then a #PseudoTcpSocket will be transparently used to
* ensure reliability of the messages.
* The returned object must be freed with g_object_unref()
* <para> See also: #NiceAgent::reliable-transport-writable </para>
*
* Since: 0.0.11
*
* Returns: The new agent GObject
*/
NiceAgent *
nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat);
/**
* nice_agent_add_local_address:
* @agent: The #NiceAgent Object
......@@ -468,10 +444,10 @@ nice_agent_add_stream (
* @agent: The #NiceAgent Object
* @stream_id: The ID of the stream to remove
*
* Remove and free a previously created data stream from @agent. If any I/O
* streams have been created using nice_agent_get_io_stream(), they should be
* closed completely using g_io_stream_close() before this is called, or they
* will get broken pipe errors.
* Remove and free a previously created data stream from @agent. If any
* sockets have been created using nice_agent_get_socket(), they should be
* closed completely using g_datagram_based_close() before this is called, or
* they will get broken pipe errors.
*
**/
void
......@@ -709,19 +685,13 @@ nice_agent_set_remote_candidates (
in any state if component was in READY state before and was then restarted
</para>
<para>
In reliable mode, the -1 error value means either that you are not yet
connected or that the send buffer is full (equivalent to EWOULDBLOCK).
In both cases, you simply need to wait for the
#NiceAgent::reliable-transport-writable signal to be fired before resending
the data.
</para>
<para>
In non-reliable mode, it will virtually never happen with UDP sockets, but
The -1error value will virtually never happen with UDP sockets, but
it might happen if the active candidate is a TURN-TCP connection that got
disconnected.
disconnected. It means that you are not yet connected or that the send buffer
is full (equivalent to EWOULDBLOCK).
</para>
<para>
In both reliable and non-reliable mode, a -1 error code could also mean that
A -1 error code could also mean that
the stream_id and/or component_id are invalid.
</para>
</note>
......@@ -761,20 +731,10 @@ nice_agent_send (
* part-way through. Zero will be returned if @n_messages is zero, or if
* transmission would have blocked on the first message.
*
* In reliable mode, it is instead recommended to use
* nice_agent_send(). The return value can be less than @n_messages
* or 0 even if it is still possible to send a partial message. In
* this case, "nice-agent-writable" will never be triggered, so the
* application would have to use nice_agent_sent() to fill the buffer or have
* to retry sending at a later point.
*
* On failure, -1 will be returned and @error will be set. If the #NiceAgent is
* reliable and the socket is not yet connected, %G_IO_ERROR_BROKEN_PIPE will be
* returned; if the write buffer is full, %G_IO_ERROR_WOULD_BLOCK will be
* returned. In both cases, wait for the #NiceAgent::reliable-transport-writable
* signal before trying again. If the given @stream_id or @component_id are
* invalid or not yet connected, %G_IO_ERROR_BROKEN_PIPE will be returned.
* %G_IO_ERROR_FAILED will be returned for other errors.
* On failure, -1 will be returned and @error will be set. If the write buffer
* is full, %G_IO_ERROR_WOULD_BLOCK will be returned. If the given @stream_id
* or @component_id are invalid or not yet connected, %G_IO_ERROR_BROKEN_PIPE
* will be returned. %G_IO_ERROR_FAILED will be returned for other errors.
*
* Returns: the number of messages sent (may be zero), or -1 on error
*
......@@ -902,7 +862,7 @@ nice_agent_restart_stream (
* establishment of ICE connectivity).
*
* This must not be used in combination with nice_agent_recv_messages() (or
* #NiceIOStream or #NiceInputStream) on the same stream/component pair.
* #NiceDatagramBased) on the same stream/component pair.
*
* Calling nice_agent_attach_recv() with a %NULL @func will detach any existing
* callback and cause reception to be paused for the given stream/component
......@@ -936,8 +896,7 @@ nice_agent_attach_recv (
* A single-message version of nice_agent_recv_messages().
*
* Returns: the number of bytes written to @buf on success (guaranteed to be
* greater than 0 unless @buf_len is 0), 0 if in reliable mode and the remote
* peer closed the stream, or -1 on error
* greater than 0 unless @buf_len is 0), or -1 on error
*
* Since: 0.1.5
*/
......@@ -974,18 +933,16 @@ nice_agent_recv (
* does not poll for messages on its own, it's therefore essential to keep
* calling this function for ICE connection establishment to work.
*
* In the non-error case, in reliable mode, this will block until all buffers in
* all @n_messages have been filled with received data (i.e. @messages is
* treated as a large, flat array of buffers). In non-reliable mode, it will
* block until @n_messages messages have been received, each of which does not
* have to fill all the buffers in its #NiceInputMessage. In the non-reliable
* case, each #NiceInputMessage must have enough buffers to contain an entire
* message (65536 bytes), or any excess data may be silently dropped.
* In the non-error case, it will block until @n_messages messages have been
* received, each of which does not have to fill all the buffers in its
* #NiceInputMessage. Each #NiceInputMessage must have enough buffers to
* contain an entire message (65536 bytes), or any excess data may be silently
* dropped.
*
* For each received message, #NiceInputMessage::length will be set to the
* number of valid bytes stored in the message’s buffers. The bytes are stored
* sequentially in the buffers; there are no gaps apart from at the end of the
* buffer array (in non-reliable mode). If non-%NULL on input,
* buffer array. If non-%NULL on input,
* #NiceInputMessage::from will have the address of the sending peer stored in
* it. The base addresses, sizes, and number of buffers in each message will not
* be modified in any case.
......@@ -1029,8 +986,7 @@ nice_agent_recv_messages (
* A single-message version of nice_agent_recv_messages_nonblocking().
*
* Returns: the number of bytes received into @buf on success (guaranteed to be
* greater than 0 unless @buf_len is 0), 0 if in reliable mode and the remote
* peer closed the stream, or -1 on error
* greater than 0 unless @buf_len is 0), or -1 on error
*
* Since: 0.1.5
*/
......@@ -1065,9 +1021,7 @@ nice_agent_recv_nonblocking (
* in @messages is returned, and will be greater than 0.
*
* This function behaves similarly to nice_agent_recv_messages(), except that it
* will not block on filling (in reliable mode) or receiving (in non-reliable
* mode) exactly @n_messages messages. In reliable mode, it will receive bytes
* into @messages until it would block; in non-reliable mode, it will receive
* will not block on receiving exactly @n_messages messages. It will receive
* messages until it would block.
*
* Any STUN packets received will not be added to @messages; instead,
......@@ -1084,8 +1038,7 @@ nice_agent_recv_nonblocking (
* same stream/component pair.
*
* Returns: the number of valid messages written to @messages on success
* (guaranteed to be greater than 0 unless @n_messages is 0), 0 if in reliable
* mode and the remote peer closed the stream, or -1 on error
* (guaranteed to be greater than 0 unless @n_messages is 0), or -1 on error
*
* Since: 0.1.5
*/
......@@ -1507,26 +1460,14 @@ nice_agent_parse_remote_candidate_sdp (
const gchar *sdp);
/**
* nice_agent_get_io_stream:
* @agent: A #NiceAgent
* @stream_id: The ID of the stream to wrap
* @component_id: The ID of the component to wrap
*
* Gets a #GIOStream wrapper around the given stream and component in
* @agent. The I/O stream will be valid for as long as @stream_id is valid.
* The #GInputStream and #GOutputStream implement #GPollableInputStream and
* #GPollableOutputStream.
* TODO: Docs
*
* This function may only be called on reliable #NiceAgents. It is a
* programming error to try and create an I/O stream wrapper for an
* unreliable stream.
* Returns: (transfer full): TODO
*
* Returns: (transfer full): A #GIOStream.
*
* Since: 0.1.5
* Since: UNRELEASED
*/
GIOStream *
nice_agent_get_io_stream (
GDatagramBased *
nice_agent_get_socket (
NiceAgent *agent,
guint stream_id,
guint component_id);
......
......@@ -267,21 +267,6 @@ void
nice_component_close (NiceComponent *cmp)
{
IOCallbackData *data;
GOutputVector *vec;
/* Start closing the pseudo-TCP socket first. FIXME: There is a very big and
* reliably triggerable race here. pseudo_tcp_socket_close() does not block
* on the socket closing — it only sends the first packet of the FIN
* handshake. nice_component_close() will immediately afterwards close the
* underlying component sockets, aborting the handshake.
*
* On the principle that starting the FIN handshake is better than not
* starting it, even if it’s later truncated, call pseudo_tcp_socket_close().
* A long-term fix is needed in the form of making nice_component_close() (and
* all its callers) async, so we can properly block on closure. */
if (cmp->tcp) {
pseudo_tcp_socket_close (cmp->tcp, TRUE);
}
if (cmp->restart_candidate)
nice_candidate_free (cmp->restart_candidate),
......@@ -308,27 +293,12 @@ nice_component_close (NiceComponent *cmp)
nice_component_clean_turn_servers (cmp);
if (cmp->tcp_clock) {
g_source_destroy (cmp->tcp_clock);
g_source_unref (cmp->tcp_clock);
cmp->tcp_clock = NULL;
}
if (cmp->tcp_writable_cancellable) {
g_cancellable_cancel (cmp->tcp_writable_cancellable);
g_clear_object (&cmp->tcp_writable_cancellable);
}
while ((data = g_queue_pop_head (&cmp->pending_io_messages)) != NULL)
io_callback_data_free (data);
nice_component_deschedule_io_callback (cmp);
g_cancellable_cancel (cmp->stop_cancellable);
while ((vec = g_queue_pop_head (&cmp->queued_tcp_packets)) != NULL) {
g_free ((gpointer) vec->buffer);
g_slice_free (GOutputVector, vec);
}
}
/*
......@@ -662,6 +632,34 @@ nice_component_free_socket_sources (NiceComponent *component)
nice_component_clear_selected_pair (component);
}
/**
* TODO: Docs
*/
GIOCondition
nice_component_condition_check (NiceComponent *component,
GIOCondition condition)
{
GIOCondition retval = 0;
GIOCondition mask = condition | G_IO_HUP | G_IO_ERR;
GSList/*<unowned SocketSource>*/ *l; /* unowned */
for (l = component->socket_sources;
l != NULL && (retval & mask) != mask;
l = l->next) {
SocketSource *socket_source = l->data;
if (socket_source->socket == NULL ||
socket_source->socket->fileno == NULL) {
continue;
}
retval |=
g_socket_condition_check (socket_source->socket->fileno, condition);
}
return retval;
}
GMainContext *
nice_component_dup_io_context (NiceComponent *component)
{
......@@ -1001,7 +999,6 @@ nice_component_init (NiceComponent *component)
component->id = 0;
component->state = NICE_COMPONENT_STATE_DISCONNECTED;
component->restart_candidate = NULL;
component->tcp = NULL;
component->agent = NULL;
component->stream = NULL;
......@@ -1022,8 +1019,6 @@ nice_component_init (NiceComponent *component)
* are called. */
nice_component_set_io_context (component, NULL);
nice_component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
g_queue_init (&component->queued_tcp_packets);
}
static void
......@@ -1107,9 +1102,8 @@ nice_component_finalize (GObject *obj)
g_warn_if_fail (cmp->remote_candidates == NULL);
g_warn_if_fail (cmp->incoming_checks == NULL);
g_clear_object (&cmp->tcp);
g_clear_object (&cmp->stop_cancellable);
g_clear_object (&cmp->iostream);
g_clear_object (&cmp->datagram_based);
g_mutex_clear (&cmp->io_mutex);
if (cmp->stop_cancellable_source != NULL) {
......@@ -1136,11 +1130,12 @@ nice_component_finalize (GObject *obj)
*
* This is a GSource which wraps a single Component and is dispatched whenever
* any of its NiceSockets are dispatched, i.e. it proxies all poll() events for
* every socket in the Component. It is designed for use by GPollableInputStream
* and GPollableOutputStream, so that a Component can be incorporated into a
* every socket in the Component. It is designed for use by GDatagramBased,
* so that a Component can be incorporated into a
* custom main context iteration.
*
* The callbacks dispatched by a ComponentSource have type GPollableSourceFunc.
* The callbacks dispatched by a ComponentSource have type
* GDatagramBasedSourceFunc.
*
* ComponentSource supports adding a GCancellable child source which will
* additionally dispatch if a provided GCancellable is cancelled.
......@@ -1155,7 +1150,7 @@ nice_component_finalize (GObject *obj)
typedef struct {
GSource parent;
GObject *pollable_stream; /* owned */
GDatagramBased *datagram_based; /* owned */
GWeakRef agent_ref;
guint stream_id;
......@@ -1223,8 +1218,8 @@ component_source_prepare (GSource *source, gint *timeout_)
child_socket_source = g_slice_new0 (SocketSource);
child_socket_source->socket = parent_socket_source->socket;
child_socket_source->source =
g_socket_create_source (child_socket_source->socket->fileno, G_IO_IN,
NULL);
g_socket_create_source (child_socket_source->socket->fileno,
component_source->condition, NULL);
g_source_set_dummy_callback (child_socket_source->source);
g_source_add_child_source (source, child_socket_source->source);
g_source_unref (child_socket_source->source);
......@@ -1271,9 +1266,34 @@ component_source_dispatch (GSource *source, GSourceFunc callback,
gpointer user_data)
{
ComponentSource *component_source = (ComponentSource *) source;
GPollableSourceFunc func = (GPollableSourceFunc) callback;
NiceAgent *agent;
NiceComponent *component;
GDatagramBasedSourceFunc func = (GDatagramBasedSourceFunc) callback;
GIOCondition condition;
agent = g_weak_ref_get (&component_source->agent_ref);
if (!agent) {
condition = G_IO_HUP;
goto done_unlocked;
}
/* Needed due to accessing the Component. */
agent_lock ();
if (!agent_find_component (agent,
component_source->stream_id, component_source->component_id, NULL,
&component)) {
condition = G_IO_HUP;
goto done;
}
condition = nice_component_condition_check (component, G_IO_IN | G_IO_OUT);
return func (component_source->pollable_stream, user_data);
done:
agent_unlock_and_emit (agent);
g_object_unref (agent);
done_unlocked:
return func (component_source->datagram_based, condition, user_data);
}
static void
......@@ -1290,12 +1310,12 @@ component_source_finalize (GSource *source)
g_slist_free_full (component_source->socket_sources, free_child_socket_source);
g_weak_ref_clear (&component_source->agent_ref);
g_object_unref (component_source->pollable_stream);
component_source->pollable_stream = NULL;
g_clear_object (&component_source->datagram_based);
}
static gboolean
component_source_closure_callback (GObject *pollable_stream, gpointer user_data)
component_source_closure_callback (GDatagramBased *datagram_based,
gpointer user_data)
{
GClosure *closure = user_data;
GValue param_value = G_VALUE_INIT;
......@@ -1304,7 +1324,7 @@ component_source_closure_callback (GObject *pollable_stream, gpointer user_data)
g_value_init (&result_value, G_TYPE_BOOLEAN);
g_value_init (&param_value, G_TYPE_OBJECT);
g_value_set_object (&param_value, pollable_stream);
g_value_set_object (&param_value, datagram_based);
g_closure_invoke (closure, &result_value, 1, &param_value, NULL);
retval = g_value_get_boolean (&result_value);
......@@ -1328,15 +1348,15 @@ static GSourceFuncs component_source_funcs = {
* @agent: a #NiceAgent
* @stream_id: The stream's id
* @component_id: The component's number
* @pollable_stream: a #GPollableInputStream or #GPollableOutputStream to pass
* to dispatched callbacks
* @datagram_based: a #GDatagramBased to pass to dispatched callbacks
* @condition: underlying socket condition to dispatch on
* @cancellable: (allow-none): a #GCancellable, or %NULL
*
* Create a new #ComponentSource, a type of #GSource which proxies poll events
* from all sockets in the given @component.
*
* A callback function of type #GPollableSourceFunc must be connected to the
* returned #GSource using g_source_set_callback(). @pollable_stream is passed
* A callback function of type #GDatagramBasedSourceFunc must be connected to the
* returned #GSource using g_source_set_callback(). @datagram_based is passed
* to all callbacks dispatched from the #GSource, and a reference is held on it
* by the #GSource.
*
......@@ -1346,21 +1366,23 @@ static GSourceFuncs component_source_funcs = {
* Returns: (transfer full): a new #ComponentSource; unref with g_source_unref()
*/
GSource *
nice_component_input_source_new (NiceAgent *agent, guint stream_id,
guint component_id, GPollableInputStream *pollable_istream,
nice_component_source_new (NiceAgent *agent, guint stream_id,
guint component_id, GDatagramBased *datagram_based,
GIOCondition condition,
GCancellable *cancellable)
{
ComponentSource *component_source;
g_assert (G_IS_POLLABLE_INPUT_STREAM (pollable_istream));
g_assert (G_IS_DATAGRAM_BASED (datagram_based));
component_source =
(ComponentSource *)
g_source_new (&component_source_funcs, sizeof (ComponentSource));
g_source_set_name ((GSource *) component_source, "ComponentSource");
component_source->condition = condition;
component_source->component_socket_sources_age = 0;
component_source->pollable_stream = g_object_ref (pollable_istream);
component_source->datagram_based = g_object_ref (datagram_based);
g_weak_ref_init (&component_source->agent_ref, agent);
component_source->stream_id = stream_id;
component_source->component_id = component_id;
......
......@@ -49,7 +49,6 @@ typedef struct _NiceComponent NiceComponent;
#include "candidate.h"
#include "stun/stunagent.h"
#include "stun/usages/timer.h"
#include "pseudotcp.h"
#include "stream.h"
#include "socket.h"
......@@ -209,21 +208,10 @@ struct _NiceComponent {
GCancellable *stop_cancellable;
GSource *stop_cancellable_source; /* owned */
PseudoTcpSocket *tcp;
GSource* tcp_clock;
guint64 last_clock_timeout;
gboolean tcp_readable;
GCancellable *tcp_writable_cancellable;
GIOStream *iostream;
GDatagramBased *datagram_based; /* owned */
guint min_port;
guint max_port;
/* Queue of messages received before a selected socket was available to send
* ACKs on. The messages are dequeued to the pseudo-TCP socket once a selected
* UDP socket is available. This is only used for reliable Components. */
GQueue queued_tcp_packets;
};
typedef struct {
......@@ -267,11 +255,14 @@ nice_component_detach_all_sockets (NiceComponent *component);
void
nice_component_free_socket_sources (NiceComponent *component);
GIOCondition
nice_component_condition_check (NiceComponent *component,
GIOCondition condition);
GSource *
nice_component_input_source_new (NiceAgent *agent, guint stream_id,
guint component_id, GPollableInputStream *pollable_istream,
GCancellable *cancellable);
nice_component_source_new (NiceAgent *agent, guint stream_id,
guint component_id, GDatagramBased *datagram_based,
GIOCondition condition, GCancellable *cancellable);
GMainContext *
nice_component_dup_io_context (NiceComponent *component);
......
......@@ -770,10 +770,10 @@ static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
priority = nice_candidate_msn_priority (candidate_priority);
} else if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
priority = nice_candidate_ms_ice_priority (candidate_priority,
agent->reliable, FALSE);
FALSE, FALSE);
} else {
priority = nice_candidate_ice_priority (candidate_priority,
agent->reliable, FALSE);
FALSE, FALSE);
}
nice_candidate_free (candidate_priority);
......@@ -2035,14 +2035,7 @@ static unsigned int priv_compute_conncheck_timer (NiceAgent *agent)
rto = agent->timer_ta * waiting_and_in_progress;
/* We assume non-reliable streams are RTP, so we use 100 as the max */
nice_debug ("Agent %p : timer set to %dms (waiting+in_progress=%d)",
agent, agent->reliable ? MAX (rto, 500) : MAX (rto, 100),
waiting_and_in_progress);
if (agent->reliable)
return MAX (rto, 500);
else
return MAX (rto, 100);
return MAX (rto, 100);
}
/*
......@@ -2152,11 +2145,6 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
pair->sockptr = new_socket;
_priv_set_socket_tos (agent, pair->sockptr, stream2->tos);
if (agent->reliable) {
nice_socket_set_writable_callback (pair->sockptr,
_tcp_sock_is_writable, component2);
}
nice_component_attach_socket (component2, new_socket);
}
}
......
/*
* This file is part of the Nice GLib ICE library.
*
* © 2015 Collabora Ltd.
* Contact: Philip Withnall
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Nice GLib ICE library.
*
* The Initial Developers of the Original Code are Collabora Ltd and Nokia
* Corporation. All Rights Reserved.
*
* Contributors:
* Philip Withnall, Collabora Ltd.
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which