/*
 * 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_cancel_turn_server_resolving (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_prune_relay_candidate (NiceAgent *agent,
    NiceComponent *cmp, NiceCandidateImpl *relay_cand);
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 */

