
This should enable having servers that do both IPv4 and IPv6. And ideally should make life easier for app developers.
364 lines
12 KiB
C
364 lines
12 KiB
C
/*
|
||
* This file is part of the Nice GLib ICE library.
|
||
*
|
||
* (C) 2006-2010 Collabora Ltd.
|
||
* Contact: Youness Alaoui
|
||
* (C) 2006-2010 Nokia Corporation. All rights reserved.
|
||
* Contact: Kai Vehmanen
|
||
*
|
||
* 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:
|
||
* Dafydd Harries, Collabora Ltd.
|
||
* Youness Alaoui, Collabora Ltd.
|
||
* Kai Vehmanen, Nokia
|
||
*
|
||
* 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
|
||
* case the provisions of LGPL are applicable instead of those above. If you
|
||
* wish to allow use of your version of this file only under the terms of the
|
||
* LGPL and not to allow others to use your version of this file under the
|
||
* MPL, indicate your decision by deleting the provisions above and replace
|
||
* them with the notice and other provisions required by the LGPL. If you do
|
||
* not delete the provisions above, a recipient may use your version of this
|
||
* file under either the MPL or the LGPL.
|
||
*/
|
||
|
||
#ifndef _NICE_COMPONENT_H
|
||
#define _NICE_COMPONENT_H
|
||
|
||
#include <glib.h>
|
||
|
||
typedef struct _NiceComponent NiceComponent;
|
||
|
||
#include "agent.h"
|
||
#include "agent-priv.h"
|
||
#include "candidate-priv.h"
|
||
#include "stun/stunagent.h"
|
||
#include "stun/usages/timer.h"
|
||
#include "pseudotcp.h"
|
||
#include "stream.h"
|
||
#include "socket.h"
|
||
|
||
G_BEGIN_DECLS
|
||
|
||
|
||
/* (ICE §4.1.1.1, ID-19)
|
||
* ""For RTP-based media streams, the RTP itself has a component
|
||
* ID of 1, and RTCP a component ID of 2. If an agent is using RTCP it MUST
|
||
* obtain a candidate for it. If an agent is using both RTP and RTCP, it
|
||
* would end up with 2*K host candidates if an agent has K interfaces.""
|
||
*/
|
||
|
||
typedef struct _CandidatePair CandidatePair;
|
||
typedef struct _CandidatePairKeepalive CandidatePairKeepalive;
|
||
typedef struct _CandidatePairConsentCheck CandidatePairConsentCheck;
|
||
typedef struct _IncomingCheck IncomingCheck;
|
||
|
||
struct _CandidatePairKeepalive
|
||
{
|
||
guint64 next_tick; /* next tick timestamp */
|
||
guint stream_id;
|
||
guint component_id;
|
||
StunTimer timer;
|
||
};
|
||
|
||
struct _CandidatePairConsentCheck
|
||
{
|
||
GSource *tick_source;
|
||
gboolean have;
|
||
guint64 last_received; /* g_get_monotonic_time() of last remote
|
||
consent received */
|
||
};
|
||
|
||
struct _CandidatePair
|
||
{
|
||
NiceCandidateImpl *local;
|
||
NiceCandidateImpl *remote;
|
||
guint64 priority; /* candidate pair priority */
|
||
guint32 stun_priority;
|
||
CandidatePairKeepalive keepalive;
|
||
CandidatePairConsentCheck remote_consent;
|
||
};
|
||
|
||
struct _IncomingCheck
|
||
{
|
||
NiceAddress from;
|
||
NiceSocket *local_socket;
|
||
guint32 priority;
|
||
gboolean use_candidate;
|
||
uint8_t *username;
|
||
uint16_t username_len;
|
||
};
|
||
|
||
void
|
||
incoming_check_free (IncomingCheck *icheck);
|
||
|
||
/* A pair of a socket and the GSource which polls it from the main loop. All
|
||
* GSources in a Component must be attached to the same main context:
|
||
* component->ctx.
|
||
*
|
||
* Socket must be non-NULL, but source may be NULL if it has been detached.
|
||
*
|
||
* The Component is stored so this may be used as the user data for a GSource
|
||
* callback. */
|
||
typedef struct {
|
||
NiceSocket *socket;
|
||
GSource *source;
|
||
NiceComponent *component;
|
||
} SocketSource;
|
||
|
||
|
||
/* A message which has been received and processed (so is guaranteed not
|
||
* to be a STUN packet, or to contain pseudo-TCP header bytes, for example), but
|
||
* which hasn’t yet been sent to the client in an I/O callback. This could be
|
||
* due to the main context not being run, or due to the I/O callback being
|
||
* detached.
|
||
*
|
||
* The @offset member gives the byte offset into @buf which has already been
|
||
* sent to the client. #IOCallbackData buffers remain in the
|
||
* #Component::pending_io_messages queue until all of their bytes have been sent
|
||
* to the client.
|
||
*
|
||
* @offset is guaranteed to be smaller than @buf_len. */
|
||
typedef struct {
|
||
guint8 *buf; /* owned */
|
||
gsize buf_len;
|
||
gsize offset;
|
||
} IOCallbackData;
|
||
|
||
IOCallbackData *
|
||
io_callback_data_new (const guint8 *buf, gsize buf_len);
|
||
void
|
||
io_callback_data_free (IOCallbackData *data);
|
||
|
||
#define NICE_TYPE_COMPONENT nice_component_get_type()
|
||
#define NICE_COMPONENT(obj) \
|
||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), NICE_TYPE_COMPONENT, NiceComponent))
|
||
#define NICE_COMPONENT_CLASS(klass) \
|
||
(G_TYPE_CHECK_CLASS_CAST ((klass), NICE_TYPE_COMPONENT, NiceComponentClass))
|
||
#define NICE_IS_COMPONENT(obj) \
|
||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NICE_TYPE_COMPONENT))
|
||
#define NICE_IS_COMPONENT_CLASS(klass) \
|
||
(G_TYPE_CHECK_CLASS_TYPE ((klass), NICE_TYPE_COMPONENT))
|
||
#define NICE_COMPONENT_GET_CLASS(obj) \
|
||
(G_TYPE_INSTANCE_GET_CLASS ((obj), NICE_TYPE_COMPONENT, NiceComponentClass))
|
||
|
||
struct _NiceComponent {
|
||
/*< private >*/
|
||
GObject parent;
|
||
|
||
NiceComponentType type;
|
||
guint id; /* component id */
|
||
NiceComponentState state;
|
||
GSList *local_candidates; /* list of NiceCandidate objs */
|
||
GSList *remote_candidates; /* list of NiceCandidate objs */
|
||
GList *valid_candidates; /* list of owned remote NiceCandidates that are part of valid pairs */
|
||
GSList *socket_sources; /* list of SocketSource objs; must only grow monotonically */
|
||
guint socket_sources_age; /* incremented when socket_sources changes */
|
||
GQueue incoming_checks; /* list of IncomingCheck objs */
|
||
GList *turn_servers; /* List of TurnServer objs */
|
||
CandidatePair selected_pair; /* independent from checklists,
|
||
see ICE 11.1. "Sending Media" (ID-19) */
|
||
gboolean fallback_mode; /* in this case, accepts packets from all, ignore candidate validation */
|
||
NiceCandidate *restart_candidate; /* for storing active remote candidate during a restart */
|
||
NiceCandidateImpl *turn_candidate; /* for storing active turn candidate if turn servers have been cleared */
|
||
/* I/O handling. The main context must always be non-NULL, and is used for all
|
||
* socket recv() operations. All io_callback emissions are invoked in this
|
||
* context too.
|
||
*
|
||
* recv_messages and io_callback are mutually exclusive, but it is allowed for
|
||
* both to be NULL if the Component is not currently ready to receive data. */
|
||
GMutex io_mutex; /* protects io_callback, io_user_data,
|
||
pending_io_messages and io_callback_id.
|
||
immutable: can be accessed without
|
||
holding the agent lock; if the agent
|
||
lock is to be taken, it must always be
|
||
taken before this one */
|
||
NiceAgentRecvFunc io_callback; /* function called on io cb */
|
||
gpointer io_user_data; /* data passed to the io function */
|
||
GQueue pending_io_messages; /* queue of messages which have been
|
||
received but not passed to the client
|
||
in an I/O callback or recv() call yet.
|
||
each element is an owned
|
||
IOCallbackData */
|
||
guint io_callback_id; /* GSource ID of the I/O callback */
|
||
|
||
GMainContext *own_ctx; /* own context for GSources for this
|
||
component */
|
||
GMainContext *ctx; /* context for GSources for this
|
||
component (possibly set from the app) */
|
||
NiceInputMessage *recv_messages; /* unowned messages for receiving into */
|
||
guint n_recv_messages; /* length of recv_messages */
|
||
NiceInputMessageIter recv_messages_iter; /* current write position in
|
||
recv_messages */
|
||
GError **recv_buf_error; /* error information about failed reads */
|
||
|
||
GWeakRef agent_ref;
|
||
guint stream_id;
|
||
|
||
StunAgent stun_agent; /* This stun agent is used to validate all stun requests */
|
||
|
||
|
||
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;
|
||
|
||
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;
|
||
|
||
gboolean have_local_consent;
|
||
|
||
/* scratch buffer for use in the component_io_cb() function to
|
||
* hold the incoming packet, allocated at component creation, since
|
||
* the callback is a critical path, where memory allocation should
|
||
* be avoided.
|
||
*/
|
||
guint8 *recv_buffer;
|
||
guint recv_buffer_size;
|
||
|
||
/* ICE-TCP frame state */
|
||
guint8 *rfc4571_buffer;
|
||
guint rfc4571_buffer_offset;
|
||
guint rfc4571_buffer_size;
|
||
guint rfc4571_frame_offset;
|
||
guint rfc4571_frame_size;
|
||
guint rfc4571_consumed_size;
|
||
NiceAddress rfc4571_remote_addr;
|
||
gboolean rfc4571_wakeup_needed;
|
||
|
||
/* TURN resolution */
|
||
GCancellable *turn_resolving_cancellable;
|
||
};
|
||
|
||
typedef struct {
|
||
GObjectClass parent_class;
|
||
} NiceComponentClass;
|
||
|
||
GType nice_component_get_type (void);
|
||
|
||
NiceComponent *
|
||
nice_component_new (guint component_id, NiceAgent *agent, NiceStream *stream);
|
||
|
||
void
|
||
nice_component_close (NiceAgent *agent, NiceStream *stream,
|
||
NiceComponent *component);
|
||
|
||
void
|
||
nice_component_shutdown (NiceComponent *component, gboolean shutdown_read,
|
||
gboolean shutdown_write);
|
||
|
||
gboolean
|
||
nice_component_find_pair (NiceComponent *component, NiceAgent *agent,
|
||
const gchar *lfoundation, const gchar *rfoundation, CandidatePair *pair);
|
||
|
||
void
|
||
nice_component_restart (NiceComponent *component, NiceAgent *agent);
|
||
|
||
void
|
||
nice_component_update_selected_pair (NiceAgent *agent, NiceComponent *component,
|
||
const CandidatePair *pair);
|
||
|
||
NiceCandidate *
|
||
nice_component_find_remote_candidate (NiceComponent *component,
|
||
const NiceAddress *addr, NiceCandidateTransport transport);
|
||
|
||
NiceCandidateImpl *
|
||
nice_component_set_selected_remote_candidate (NiceComponent *component,
|
||
NiceAgent *agent, NiceCandidate *candidate);
|
||
|
||
void
|
||
nice_component_attach_socket (NiceComponent *component, NiceSocket *nsocket);
|
||
|
||
void
|
||
nice_component_remove_socket (NiceAgent *agent, NiceComponent *component,
|
||
NiceSocket *nsocket);
|
||
void
|
||
nice_component_detach_all_sockets (NiceComponent *component);
|
||
|
||
void
|
||
nice_component_free_socket_sources (NiceComponent *component);
|
||
|
||
GSource *
|
||
nice_component_input_source_new (NiceAgent *agent, guint stream_id,
|
||
guint component_id, GPollableInputStream *pollable_istream,
|
||
GCancellable *cancellable);
|
||
|
||
GMainContext *
|
||
nice_component_dup_io_context (NiceComponent *component);
|
||
void
|
||
nice_component_set_io_context (NiceComponent *component, GMainContext *context);
|
||
void
|
||
nice_component_set_io_callback (NiceComponent *component,
|
||
NiceAgentRecvFunc func, gpointer user_data,
|
||
NiceInputMessage *recv_messages, guint n_recv_messages,
|
||
GError **error);
|
||
void
|
||
nice_component_emit_io_callback (NiceAgent *agent, NiceComponent *component,
|
||
gsize buf_len);
|
||
gboolean
|
||
nice_component_has_io_callback (NiceComponent *component);
|
||
void
|
||
nice_component_clean_turn_servers (NiceAgent *agent, NiceComponent *component);
|
||
|
||
|
||
TurnServer *
|
||
turn_server_new (const gchar *server_ip, guint server_port,
|
||
const gchar *username, const gchar *password, NiceRelayType type);
|
||
|
||
TurnServer *
|
||
turn_server_copy (TurnServer *turn);
|
||
|
||
TurnServer *
|
||
turn_server_ref (TurnServer *turn);
|
||
|
||
void
|
||
turn_server_unref (TurnServer *turn);
|
||
|
||
void
|
||
nice_component_add_valid_candidate (NiceAgent *agent, NiceComponent *component,
|
||
const NiceCandidate *candidate);
|
||
|
||
gboolean
|
||
nice_component_verify_remote_candidate (NiceComponent *component,
|
||
const NiceAddress *address, NiceSocket *nicesock);
|
||
|
||
GPtrArray *
|
||
nice_component_get_sockets (NiceComponent *component);
|
||
|
||
guint
|
||
nice_component_compute_rfc4571_headroom (NiceComponent *component);
|
||
|
||
gboolean
|
||
nice_component_resolving_turn (NiceComponent *component);
|
||
|
||
|
||
G_END_DECLS
|
||
|
||
#endif /* _NICE_COMPONENT_H */
|
||
|