From 6ca5739b634a60f80ba64d5fe4d3e56371494fc9 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sat, 25 Jan 2020 16:02:35 +0000 Subject: [PATCH] Added arm libs --- linux_arm32v7/include/nice/address.h | 307 ++++ linux_arm32v7/include/nice/agent.h | 1709 +++++++++++++++++++++ linux_arm32v7/include/nice/candidate.h | 269 ++++ linux_arm32v7/include/nice/debug.h | 105 ++ linux_arm32v7/include/nice/interfaces.h | 82 + linux_arm32v7/include/nice/nice.h | 46 + linux_arm32v7/include/nice/pseudotcp.h | 599 ++++++++ linux_arm32v7/include/stun/constants.h | 203 +++ linux_arm32v7/include/stun/debug.h | 102 ++ linux_arm32v7/include/stun/stunagent.h | 521 +++++++ linux_arm32v7/include/stun/stunmessage.h | 1017 ++++++++++++ linux_arm32v7/include/stun/usages/bind.h | 165 ++ linux_arm32v7/include/stun/usages/ice.h | 240 +++ linux_arm32v7/include/stun/usages/timer.h | 240 +++ linux_arm32v7/include/stun/usages/turn.h | 301 ++++ linux_arm32v7/include/stun/win32_common.h | 74 + linux_arm32v7/lib/libnice.la | 41 + linux_arm32v7/lib/libnice.so | 1 + linux_arm32v7/lib/libnice.so.10 | 1 + linux_arm32v7/lib/libnice.so.10.9.0 | Bin 0 -> 337392 bytes linux_arm32v7/lib/pkgconfig/nice.pc | 13 + 21 files changed, 6036 insertions(+) create mode 100644 linux_arm32v7/include/nice/address.h create mode 100644 linux_arm32v7/include/nice/agent.h create mode 100644 linux_arm32v7/include/nice/candidate.h create mode 100644 linux_arm32v7/include/nice/debug.h create mode 100644 linux_arm32v7/include/nice/interfaces.h create mode 100644 linux_arm32v7/include/nice/nice.h create mode 100644 linux_arm32v7/include/nice/pseudotcp.h create mode 100644 linux_arm32v7/include/stun/constants.h create mode 100644 linux_arm32v7/include/stun/debug.h create mode 100644 linux_arm32v7/include/stun/stunagent.h create mode 100644 linux_arm32v7/include/stun/stunmessage.h create mode 100644 linux_arm32v7/include/stun/usages/bind.h create mode 100644 linux_arm32v7/include/stun/usages/ice.h create mode 100644 linux_arm32v7/include/stun/usages/timer.h create mode 100644 linux_arm32v7/include/stun/usages/turn.h create mode 100644 linux_arm32v7/include/stun/win32_common.h create mode 100755 linux_arm32v7/lib/libnice.la create mode 120000 linux_arm32v7/lib/libnice.so create mode 120000 linux_arm32v7/lib/libnice.so.10 create mode 100755 linux_arm32v7/lib/libnice.so.10.9.0 create mode 100644 linux_arm32v7/lib/pkgconfig/nice.pc diff --git a/linux_arm32v7/include/nice/address.h b/linux_arm32v7/include/nice/address.h new file mode 100644 index 0000000..fa555b2 --- /dev/null +++ b/linux_arm32v7/include/nice/address.h @@ -0,0 +1,307 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2006-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2006-2009 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: + * Youness Alaoui, Collabora Ltd. + * Dafydd Harries, Collabora Ltd. + * Kai Vehmanen + * + * 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 __LIBNICE_ADDRESS_H__ +#define __LIBNICE_ADDRESS_H__ + +/** + * SECTION:address + * @short_description: IP address convenience library + * @stability: Stable + * + * The #NiceAddress structure will allow you to easily set/get and modify an IPv4 + * or IPv6 address in order to communicate with the #NiceAgent. + */ + + +#include + +#ifdef G_OS_WIN32 +#include +#include +#else +#include +#include +#include +#include +#endif + +G_BEGIN_DECLS + + +/** + * NiceAddress: + * + * The #NiceAddress structure that represents an IPv4 or IPv6 address. + */ +struct _NiceAddress +{ + union + { + struct sockaddr addr; + struct sockaddr_in ip4; + struct sockaddr_in6 ip6; + } s; +}; + + +/** + * NICE_ADDRESS_STRING_LEN: + * + * The maximum string length representation of an address. + * When using nice_address_to_string() make sure the string has a size of + * at least %NICE_ADDRESS_STRING_LEN + */ +#define NICE_ADDRESS_STRING_LEN INET6_ADDRSTRLEN + +typedef struct _NiceAddress NiceAddress; + + +/** + * nice_address_init: + * @addr: The #NiceAddress to init + * + * Initialize a #NiceAddress into an undefined address + */ +void +nice_address_init (NiceAddress *addr); + +/** + * nice_address_new: + * + * Create a new #NiceAddress with undefined address + * You must free it with nice_address_free() + * + * Returns: The new #NiceAddress + */ +NiceAddress * +nice_address_new (void); + +/** + * nice_address_free: + * @addr: The #NiceAddress to free + * + * Frees a #NiceAddress created with nice_address_new() or nice_address_dup() + */ +void +nice_address_free (NiceAddress *addr); + +/** + * nice_address_dup: + * @addr: The #NiceAddress to dup + * + * Creates a new #NiceAddress with the same address as @addr + * + * Returns: The new #NiceAddress + */ +NiceAddress * +nice_address_dup (const NiceAddress *addr); + + +/** + * nice_address_set_ipv4: + * @addr: The #NiceAddress to modify + * @addr_ipv4: The IPv4 address + * + * Set @addr to an IPv4 address using the data from @addr_ipv4 + * + + + This function will reset the port to 0, so make sure you call it before + nice_address_set_port() + + + */ +void +nice_address_set_ipv4 (NiceAddress *addr, guint32 addr_ipv4); + + +/** + * nice_address_set_ipv6: + * @addr: The #NiceAddress to modify + * @addr_ipv6: The IPv6 address + * + * Set @addr to an IPv6 address using the data from @addr_ipv6 + * + + + This function will reset the port to 0, so make sure you call it before + nice_address_set_port() + + + */ +void +nice_address_set_ipv6 (NiceAddress *addr, const guchar *addr_ipv6); + + +/** + * nice_address_set_port: + * @addr: The #NiceAddress to modify + * @port: The port to set + * + * Set the port of @addr to @port + */ +void +nice_address_set_port (NiceAddress *addr, guint port); + +/** + * nice_address_get_port: + * @addr: The #NiceAddress to query + * + * Retreive the port of @addr + * + * Returns: The port of @addr + */ +guint +nice_address_get_port (const NiceAddress *addr); + +/** + * nice_address_set_from_string: + * @addr: The #NiceAddress to modify + * @str: The string to set + * + * Sets an IPv4 or IPv6 address from the string @str + * + * Returns: %TRUE if success, %FALSE on error + */ +gboolean +nice_address_set_from_string (NiceAddress *addr, const gchar *str); + +/** + * nice_address_set_from_sockaddr: + * @addr: The #NiceAddress to modify + * @sin: The sockaddr to set + * + * Sets an IPv4 or IPv6 address from the sockaddr structure @sin + * + */ +void +nice_address_set_from_sockaddr (NiceAddress *addr, const struct sockaddr *sin); + + +/** + * nice_address_copy_to_sockaddr: + * @addr: The #NiceAddress to query + * @sin: The sockaddr to fill + * + * Fills the sockaddr structure @sin with the address contained in @addr + * + */ +void +nice_address_copy_to_sockaddr (const NiceAddress *addr, struct sockaddr *sin); + +/** + * nice_address_equal: + * @a: First #NiceAddress to compare + * @b: Second #NiceAddress to compare + * + * Compares two #NiceAddress structures to see if they contain the same address + * and the same port. + * + * Returns: %TRUE if @a and @b are the same address, %FALSE if they are different + */ +gboolean +nice_address_equal (const NiceAddress *a, const NiceAddress *b); + +/** + * nice_address_equal_no_port: + * @a: First #NiceAddress to compare + * @b: Second #NiceAddress to compare + * + * Compares two #NiceAddress structures to see if they contain the same address, + * ignoring the port. + * + * Returns: %TRUE if @a and @b are the same address, %FALSE if they + * are different + * + * Since: 0.1.8 + */ +gboolean +nice_address_equal_no_port (const NiceAddress *a, const NiceAddress *b); + +/** + * nice_address_to_string: + * @addr: The #NiceAddress to query + * @dst: The string to fill + * + * Transforms the address @addr into a human readable string + * + */ +void +nice_address_to_string (const NiceAddress *addr, gchar *dst); + +/** + * nice_address_is_private: + * @addr: The #NiceAddress to query + * + * Verifies if the address in @addr is a private address or not + * + * Returns: %TRUE if @addr is a private address, %FALSE otherwise + */ +gboolean +nice_address_is_private (const NiceAddress *addr); + +/** + * nice_address_is_valid: + * @addr: The #NiceAddress to query + * + * Validate whether the #NiceAddress @addr is a valid IPv4 or IPv6 address + * + * Returns: %TRUE if @addr is valid, %FALSE otherwise + */ +G_GNUC_WARN_UNUSED_RESULT +gboolean +nice_address_is_valid (const NiceAddress *addr); + +/** + * nice_address_ip_version: + * @addr: The #NiceAddress to query + * + * Returns the IP version of the address + * + * Returns: 4 for IPv4, 6 for IPv6 and 0 for undefined address + */ +G_GNUC_WARN_UNUSED_RESULT +int +nice_address_ip_version (const NiceAddress *addr); + +G_END_DECLS + +#endif /* __LIBNICE_ADDRESS_H__ */ + diff --git a/linux_arm32v7/include/nice/agent.h b/linux_arm32v7/include/nice/agent.h new file mode 100644 index 0000000..1164138 --- /dev/null +++ b/linux_arm32v7/include/nice/agent.h @@ -0,0 +1,1709 @@ +/* + * 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 __LIBNICE_AGENT_H__ +#define __LIBNICE_AGENT_H__ + +/** + * SECTION:agent + * @short_description: ICE agent API implementation + * @see_also: #NiceCandidate, #NiceAddress + * @include: agent.h + * @stability: Stable + * + * The #NiceAgent is your main object when using libnice. + * It is the agent that will take care of everything relating to ICE. + * It will take care of discovering your local candidates and do + * connectivity checks to create a stream of data between you and your peer. + * + * A #NiceAgent must always be used with a #GMainLoop running the #GMainContext + * passed into nice_agent_new() (or nice_agent_new_reliable()). Without the + * #GMainContext being iterated, the agent’s timers will not fire, etc. + * + * Streams and their components are referenced by integer IDs (with respect to a + * given #NiceAgent). These IDs are guaranteed to be positive (i.e. non-zero) + * for valid streams/components. + * + * To complete the ICE connectivity checks, the user must either register + * an I/O callback (with nice_agent_attach_recv()) or call nice_agent_recv_messages() + * in a loop on a dedicated thread. + * Technically, #NiceAgent does not poll the streams on its own, since + * user data could arrive at any time; to receive STUN packets + * required for establishing ICE connectivity, it is backpiggying + * on the facility chosen by the user. #NiceAgent will handle all STUN + * packets internally; they're never actually passed to the I/O callback + * or returned from nice_agent_recv_messages() and related functions. + * + * 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 + * 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. + * + * + * Simple example on how to use libnice + * + * guint stream_id; + * gchar buffer[] = "hello world!"; + * gchar *ufrag = NULL, *pwd = NULL; + * gchar *remote_ufrag, *remote_pwd; + * GSList *lcands = NULL; + * + * // Create a nice agent, passing in the global default GMainContext. + * NiceAgent *agent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245); + * spawn_thread_to_run_main_loop (g_main_loop_new (NULL, FALSE)); + * + * // Connect the signals + * g_signal_connect (G_OBJECT (agent), "candidate-gathering-done", + * G_CALLBACK (cb_candidate_gathering_done), NULL); + * g_signal_connect (G_OBJECT (agent), "component-state-changed", + * G_CALLBACK (cb_component_state_changed), NULL); + * g_signal_connect (G_OBJECT (agent), "new-selected-pair", + * G_CALLBACK (cb_new_selected_pair), NULL); + * + * // Create a new stream with one component and start gathering candidates + * stream_id = nice_agent_add_stream (agent, 1); + * nice_agent_gather_candidates (agent, stream_id); + * + * // Attach I/O callback the component to ensure that: + * // 1) agent gets its STUN packets (not delivered to cb_nice_recv) + * // 2) you get your own data + * nice_agent_attach_recv (agent, stream_id, 1, NULL, + * cb_nice_recv, NULL); + * + * // ... Wait until the signal candidate-gathering-done is fired ... + * lcands = nice_agent_get_local_candidates(agent, stream_id, 1); + + * nice_agent_get_local_credentials(agent, stream_id, &ufrag, &pwd); + * + * // ... Send local candidates and credentials to the peer + * + * // Set the peer's remote credentials and remote candidates + * nice_agent_set_remote_credentials (agent, stream_id, remote_ufrag, remote_pwd); + * nice_agent_set_remote_candidates (agent, stream_id, 1, rcands); + * + * // ... Wait until the signal new-selected-pair is fired ... + * // Send our message! + * nice_agent_send (agent, stream_id, 1, sizeof(buffer), buffer); + * + * // Anything received will be received through the cb_nice_recv callback. + * // You must be running a GMainLoop on the global default GMainContext in + * // another thread for this to work. + * + * // Destroy the object + * g_object_unref(agent); + * + * + * + * + * Refer to the examples in the examples/ subdirectory of the libnice source for + * more complete examples. + * + */ + + +#include +#include + +/** + * NiceAgent: + * + * The #NiceAgent is the main GObject of the libnice library and represents + * the ICE agent. + */ +typedef struct _NiceAgent NiceAgent; + +#include "address.h" +#include "candidate.h" +#include "debug.h" + + +G_BEGIN_DECLS + +/** + * NiceInputMessage: + * @buffers: (array length=n_buffers): unowned array of #GInputVector buffers to + * store data in for this message + * @n_buffers: number of #GInputVectors in @buffers, or -1 to indicate @buffers + * is %NULL-terminated + * @from: (allow-none): return location to store the address of the peer who + * 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. + * + * @n_buffers may be -1 to indicate that @buffers is terminated by a + * #GInputVector with a %NULL buffer pointer. + * + * By providing arrays of #NiceInputMessages to functions like + * nice_agent_recv_messages(), multiple messages may be received with a single + * call, which is more efficient than making multiple calls in a loop. In this + * manner, nice_agent_recv_messages() is analogous to recvmmsg(); and + * #NiceInputMessage to struct mmsghdr. + * + * Since: 0.1.5 + */ +typedef struct { + GInputVector *buffers; + gint n_buffers; /* may be -1 to indicate @buffers is NULL-terminated */ + NiceAddress *from; /* return location for address of message sender */ + gsize length; /* sum of the lengths of @buffers */ +} NiceInputMessage; + +/** + * NiceOutputMessage: + * @buffers: (array length=n_buffers): unowned array of #GOutputVector buffers + * which contain data to transmit for this message + * @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. + * + * @n_buffers may be -1 to indicate that @buffers is terminated by a + * #GOutputVector with a %NULL buffer pointer. + * + * By providing arrays of #NiceOutputMessages to functions like + * nice_agent_send_messages_nonblocking(), multiple messages may be transmitted + * with a single call, which is more efficient than making multiple calls in a + * loop. In this manner, nice_agent_send_messages_nonblocking() is analogous to + * sendmmsg(); and #NiceOutputMessage to struct mmsghdr. + * + * Since: 0.1.5 + */ +typedef struct { + GOutputVector *buffers; + gint n_buffers; +} NiceOutputMessage; + + +#define NICE_TYPE_AGENT nice_agent_get_type() + +#define NICE_AGENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + NICE_TYPE_AGENT, NiceAgent)) + +#define NICE_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + NICE_TYPE_AGENT, NiceAgentClass)) + +#define NICE_IS_AGENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + NICE_TYPE_AGENT)) + +#define NICE_IS_AGENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + NICE_TYPE_AGENT)) + +#define NICE_AGENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + NICE_TYPE_AGENT, NiceAgentClass)) + +typedef struct _NiceAgentClass NiceAgentClass; + +struct _NiceAgentClass +{ + GObjectClass parent_class; +}; + + +GType nice_agent_get_type (void); + + +/** + * NICE_AGENT_MAX_REMOTE_CANDIDATES: + * + * A hard limit for the number of remote candidates. This + * limit is enforced to protect against malevolent remote + * clients. + */ +#define NICE_AGENT_MAX_REMOTE_CANDIDATES 25 + +/** + * NiceComponentState: + * @NICE_COMPONENT_STATE_DISCONNECTED: No activity scheduled + * @NICE_COMPONENT_STATE_GATHERING: Gathering local candidates + * @NICE_COMPONENT_STATE_CONNECTING: Establishing connectivity + * @NICE_COMPONENT_STATE_CONNECTED: At least one working candidate pair + * @NICE_COMPONENT_STATE_READY: ICE concluded, candidate pair selection + * is now final + * @NICE_COMPONENT_STATE_FAILED: Connectivity checks have been completed, + * but connectivity was not established + * @NICE_COMPONENT_STATE_LAST: Dummy state + * + * An enum representing the state of a component. + * See also: #NiceAgent::component-state-changed + */ +typedef enum +{ + NICE_COMPONENT_STATE_DISCONNECTED, + NICE_COMPONENT_STATE_GATHERING, + NICE_COMPONENT_STATE_CONNECTING, + NICE_COMPONENT_STATE_CONNECTED, + NICE_COMPONENT_STATE_READY, + NICE_COMPONENT_STATE_FAILED, + NICE_COMPONENT_STATE_LAST +} NiceComponentState; + + +/** + * NiceComponentType: + * @NICE_COMPONENT_TYPE_RTP: RTP Component type + * @NICE_COMPONENT_TYPE_RTCP: RTCP Component type + * + * Convenience enum representing the type of a component for use as the + * component_id for RTP/RTCP usages. + + Example of use. + + nice_agent_send (agent, stream_id, NICE_COMPONENT_TYPE_RTP, len, buf); + + + */ +typedef enum +{ + NICE_COMPONENT_TYPE_RTP = 1, + NICE_COMPONENT_TYPE_RTCP = 2 +} NiceComponentType; + + +/** + * NiceCompatibility: + * @NICE_COMPATIBILITY_RFC5245: Use compatibility with the RFC5245 ICE-UDP specs + * and RFC6544 ICE-TCP specs + * @NICE_COMPATIBILITY_GOOGLE: Use compatibility for Google Talk specs + * @NICE_COMPATIBILITY_MSN: Use compatibility for MSN Messenger specs + * @NICE_COMPATIBILITY_WLM2009: Use compatibility with Windows Live Messenger + * 2009 + * @NICE_COMPATIBILITY_OC2007: Use compatibility with Microsoft Office Communicator 2007 + * @NICE_COMPATIBILITY_OC2007R2: Use compatibility with Microsoft Office Communicator 2007 R2 + * @NICE_COMPATIBILITY_DRAFT19: Use compatibility for ICE Draft 19 specs + * @NICE_COMPATIBILITY_LAST: Dummy last compatibility mode + * + * An enum to specify which compatible specifications the #NiceAgent should use. + * Use with nice_agent_new() + * + * @NICE_COMPATIBILITY_DRAFT19 is deprecated and should not be used + * in newly-written code. It is kept for compatibility reasons and + * represents the same compatibility as @NICE_COMPATIBILITY_RFC5245 + + + If @NICE_COMPATIBILITY_RFC5245 compatibility mode is used for a non-reliable + agent, then ICE-UDP will be used with higher priority and ICE-TCP will also + be used when the UDP connectivity fails. If it is used with a reliable agent, + then ICE-UDP will be used with the TCP-Over-UDP (#PseudoTcpSocket) if ICE-TCP + fails and ICE-UDP succeeds. + + + * + */ +typedef enum +{ + NICE_COMPATIBILITY_RFC5245 = 0, + NICE_COMPATIBILITY_DRAFT19 = NICE_COMPATIBILITY_RFC5245, + NICE_COMPATIBILITY_GOOGLE, + NICE_COMPATIBILITY_MSN, + NICE_COMPATIBILITY_WLM2009, + NICE_COMPATIBILITY_OC2007, + NICE_COMPATIBILITY_OC2007R2, + NICE_COMPATIBILITY_LAST = NICE_COMPATIBILITY_OC2007R2, +} NiceCompatibility; + +/** + * NiceProxyType: + * @NICE_PROXY_TYPE_NONE: Do not use a proxy + * @NICE_PROXY_TYPE_SOCKS5: Use a SOCKS5 proxy + * @NICE_PROXY_TYPE_HTTP: Use an HTTP proxy + * @NICE_PROXY_TYPE_LAST: Dummy last proxy type + * + * An enum to specify which proxy type to use for relaying. + * Note that the proxies will only be used with TCP TURN relaying. + * See also: #NiceAgent:proxy-type + * + * Since: 0.0.4 + */ +typedef enum +{ + NICE_PROXY_TYPE_NONE = 0, + NICE_PROXY_TYPE_SOCKS5, + NICE_PROXY_TYPE_HTTP, + NICE_PROXY_TYPE_LAST = NICE_PROXY_TYPE_HTTP, +} NiceProxyType; + +/** + * NiceNominationMode: + * @NICE_NOMINATION_MODE_AGGRESSIVE: Aggressive nomination mode + * @NICE_NOMINATION_MODE_REGULAR: Regular nomination mode + * + * An enum to specity the kind of nomination mode to use by + * the agent, as described in RFC 5245. Two modes exists, + * regular and aggressive. They differ by the way the controlling + * agent chooses to put the USE-CANDIDATE attribute in its STUN + * messages. The aggressive mode is supposed to nominate a pair + * faster, than the regular mode, potentially causing the nominated + * pair to change until the connection check completes. + * + * Since: 0.1.15 + */ +typedef enum +{ + NICE_NOMINATION_MODE_REGULAR = 0, + NICE_NOMINATION_MODE_AGGRESSIVE, +} NiceNominationMode; + +/** + * NiceAgentOption: + * @NICE_AGENT_OPTION_REGULAR_NOMINATION: Enables regular nomination, default + * is aggrssive mode (see #NiceNominationMode). + * @NICE_AGENT_OPTION_RELIABLE: Enables reliable mode, possibly using PseudoTCP, * see nice_agent_new_reliable(). + * @NICE_AGENT_OPTION_LITE_MODE: Enable lite mode + * @NICE_AGENT_OPTION_ICE_TRICKLE: Enable ICE trickle mode + * @NICE_AGENT_OPTION_SUPPORT_RENOMINATION: Enable renomination triggered by NOMINATION STUN attribute + * proposed here: https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 + * + * These are options that can be passed to nice_agent_new_full(). They set + * various properties on the agent. Not including them sets the property to + * the other value. + * + * Since: 0.1.15 + */ +typedef enum { + NICE_AGENT_OPTION_REGULAR_NOMINATION = 1 << 0, + NICE_AGENT_OPTION_RELIABLE = 1 << 1, + NICE_AGENT_OPTION_LITE_MODE = 1 << 2, + NICE_AGENT_OPTION_ICE_TRICKLE = 1 << 3, + NICE_AGENT_OPTION_SUPPORT_RENOMINATION = 1 << 4, +} NiceAgentOption; + +/** + * NiceAgentRecvFunc: + * @agent: The #NiceAgent Object + * @stream_id: The id of the stream + * @component_id: The id of the component of the stream + * which received the data + * @len: The length of the data + * @buf: The buffer containing the data received + * @user_data: The user data set in nice_agent_attach_recv() + * + * Callback function when data is received on a component + * + */ +typedef void (*NiceAgentRecvFunc) ( + NiceAgent *agent, guint stream_id, guint component_id, guint len, + gchar *buf, gpointer user_data); + + +/** + * nice_agent_new: + * @ctx: The Glib Mainloop Context to use for timers + * @compat: The compatibility mode of the agent + * + * Create a new #NiceAgent. + * The returned object must be freed with g_object_unref() + * + * Returns: The new agent GObject + */ +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() + * See also: #NiceAgent::reliable-transport-writable + * + * Since: 0.0.11 + * + * Returns: The new agent GObject + */ +NiceAgent * +nice_agent_new_reliable (GMainContext *ctx, NiceCompatibility compat); + +/** + * nice_agent_new_full: + * @ctx: The Glib Mainloop Context to use for timers + * @compat: The compatibility mode of the agent + * @flags: Flags to set the properties + * + * Create a new #NiceAgent with parameters that must be be defined at + * construction time. + * The returned object must be freed with g_object_unref() + * See also: #NiceNominationMode and #NiceAgentOption + * + * Since: 0.1.15 + * + * Returns: The new agent GObject + */ +NiceAgent * +nice_agent_new_full (GMainContext *ctx, + NiceCompatibility compat, + NiceAgentOption flags); + +/** + * nice_agent_add_local_address: + * @agent: The #NiceAgent Object + * @addr: The address to listen to + * If the port is 0, then a random port will be chosen by the system + * + * Add a local address from which to derive local host candidates for + * candidate gathering. + * + * Since 0.0.5, if this method is not called, libnice will automatically + * discover the local addresses available + * + * + * See also: nice_agent_gather_candidates() + * Returns: %TRUE on success, %FALSE on fatal (memory allocation) errors + */ +gboolean +nice_agent_add_local_address (NiceAgent *agent, NiceAddress *addr); + +/** + * nice_agent_add_stream: + * @agent: The #NiceAgent Object + * @n_components: The number of components to add to the stream + * + * Adds a data stream to @agent containing @n_components components. The + * returned stream ID is guaranteed to be positive on success. + * + * Returns: The ID of the new stream, 0 on failure + **/ +guint +nice_agent_add_stream ( + NiceAgent *agent, + guint n_components); + +/** + * nice_agent_remove_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. + * + **/ +void +nice_agent_remove_stream ( + NiceAgent *agent, + guint stream_id); + + +/** + * nice_agent_set_port_range: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * @min_port: The minimum port to use + * @max_port: The maximum port to use + * + * Sets a preferred port range for allocating host candidates. + * + * If a local host candidate cannot be created on that port + * range, then the nice_agent_gather_candidates() call will fail. + * + * + * This MUST be called before nice_agent_gather_candidates() + * + * + */ +void +nice_agent_set_port_range ( + NiceAgent *agent, + guint stream_id, + guint component_id, + guint min_port, + guint max_port); + +/** + * nice_agent_set_relay_info: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * @server_ip: The IP address of the TURN server + * @server_port: The port of the TURN server + * @username: The TURN username to use for the allocate + * @password: The TURN password to use for the allocate + * @type: The type of relay to use + * + * Sets the settings for using a relay server during the candidate discovery. + * This may be called multiple times to add multiple relay servers to the + * discovery process; one TCP and one UDP, for example. + * + * Returns: %TRUE if the TURN settings were accepted. + * %FALSE if the address was invalid. + */ +gboolean nice_agent_set_relay_info( + NiceAgent *agent, + guint stream_id, + guint component_id, + const gchar *server_ip, + guint server_port, + const gchar *username, + const gchar *password, + NiceRelayType type); + +/** + * nice_agent_gather_candidates: + * @agent: The #NiceAgent object + * @stream_id: The ID of the stream to start + * + * Allocate and start listening on local candidate ports and start the remote + * candidate gathering process. + * Once done, #NiceAgent::candidate-gathering-done is called for the stream. + * As soon as this function is called, #NiceAgent::new-candidate signals may be + * emitted, even before this function returns. + * + * nice_agent_get_local_candidates() will only return non-empty results after + * calling this function. + * + * See also: nice_agent_add_local_address() + * See also: nice_agent_set_port_range() + * + * Returns: %FALSE if the stream ID is invalid or if a host candidate couldn't + * be allocated on the requested interfaces/ports; %TRUE otherwise + * + + + Local addresses can be previously set with nice_agent_add_local_address() + + + Since 0.0.5, If no local address was previously added, then the nice agent + will automatically detect the local address using + nice_interfaces_get_local_ips() + + + */ +gboolean +nice_agent_gather_candidates ( + NiceAgent *agent, + guint stream_id); + +/** + * nice_agent_set_remote_credentials: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @ufrag: nul-terminated string containing an ICE username fragment + * (length must be between 22 and 256 chars) + * @pwd: nul-terminated string containing an ICE password + * (length must be between 4 and 256 chars) + * + * Sets the remote credentials for stream @stream_id. + * + + + Stream credentials do not override per-candidate credentials if set + + + Due to the native of peer-reflexive candidates, any agent using a per-stream + credentials (RFC5245, WLM2009, OC2007R2 and DRAFT19) instead of + per-candidate credentials (GOOGLE, MSN, OC2007), must + use the nice_agent_set_remote_credentials() API instead of setting the + username and password on the candidates. + + + * + * Returns: %TRUE on success, %FALSE on error. + */ +gboolean +nice_agent_set_remote_credentials ( + NiceAgent *agent, + guint stream_id, + const gchar *ufrag, const gchar *pwd); + + +/** + * nice_agent_set_local_credentials: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @ufrag: nul-terminated string containing an ICE username fragment + * (length must be between 22 and 256 chars) + * @pwd: nul-terminated string containing an ICE password + * (length must be between 4 and 256 chars) + * + * Sets the local credentials for stream @stream_id. + * + + + This is only effective before ICE negotiation has started. + + + * + * Since 0.1.11 + * Returns: %TRUE on success, %FALSE on error. + */ +gboolean +nice_agent_set_local_credentials ( + NiceAgent *agent, + guint stream_id, + const gchar *ufrag, + const gchar *pwd); + + +/** + * nice_agent_get_local_credentials: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @ufrag: (out callee-allocates): return location for a nul-terminated string + * containing an ICE username fragment; must be freed with g_free() + * @pwd: (out callee-allocates): return location for a nul-terminated string + * containing an ICE password; must be freed with g_free() + * + * Gets the local credentials for stream @stream_id. This may be called any time + * after creating a stream using nice_agent_add_stream(). + * + * An error will be returned if this is called for a non-existent stream, or if + * either of @ufrag or @pwd are %NULL. + * + * Returns: %TRUE on success, %FALSE on error. + */ +gboolean +nice_agent_get_local_credentials ( + NiceAgent *agent, + guint stream_id, + gchar **ufrag, gchar **pwd); + +/** + * nice_agent_set_remote_candidates: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream the candidates are for + * @component_id: The ID of the component the candidates are for + * @candidates: (element-type NiceCandidate) (transfer none): a #GSList of + * #NiceCandidate items describing each candidate to add + * + * Sets, adds or updates the remote candidates for a component of a stream. + * + + + NICE_AGENT_MAX_REMOTE_CANDIDATES is the absolute maximum limit + for remote candidates. + + + You must first call nice_agent_gather_candidates() and wait for the + #NiceAgent::candidate-gathering-done signale before + calling nice_agent_set_remote_candidates() + + + Since 0.1.3, there is no need to wait for the candidate-gathering-done signal. + Remote candidates can be set even while gathering local candidates. + Newly discovered local candidates will automatically be paired with + existing remote candidates. + + + * + * Returns: The number of candidates added, negative on errors (memory + * allocation error or invalid component) + **/ +int +nice_agent_set_remote_candidates ( + NiceAgent *agent, + guint stream_id, + guint component_id, + const GSList *candidates); + + +/** + * nice_agent_send: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream to send to + * @component_id: The ID of the component to send to + * @len: The length of the buffer to send + * @buf: The buffer of data to send + * + * Sends a data payload over a stream's component. + * + + + Component state MUST be NICE_COMPONENT_STATE_READY, or as a special case, + in any state if component was in READY state before and was then restarted + + + 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. + + + In non-reliable mode, it will virtually never happen with UDP sockets, but + it might happen if the active candidate is a TURN-TCP connection that got + disconnected. + + + In both reliable and non-reliable mode, a -1 error code could also mean that + the stream_id and/or component_id are invalid. + + + * + * Returns: The number of bytes sent, or negative error code + */ +gint +nice_agent_send ( + NiceAgent *agent, + guint stream_id, + guint component_id, + guint len, + const gchar *buf); + +/** + * nice_agent_send_messages_nonblocking: + * @agent: a #NiceAgent + * @stream_id: the ID of the stream to send to + * @component_id: the ID of the component to send to + * @messages: (array length=n_messages): array of messages to send, of at least + * @n_messages entries in length + * @n_messages: number of entries in @messages + * @cancellable: (allow-none): a #GCancellable to cancel the operation from + * another thread, or %NULL + * @error: (allow-none): return location for a #GError, or %NULL + * + * Sends multiple messages on the socket identified by the given + * stream/component pair. Transmission is non-blocking, so a + * %G_IO_ERROR_WOULD_BLOCK error may be returned if the send buffer is full. + * + * As with nice_agent_send(), the given component must be in + * %NICE_COMPONENT_STATE_READY or, as a special case, in any state if it was + * previously ready and was then restarted. + * + * On success, the number of messages written to the socket will be returned, + * which may be less than @n_messages if transmission would have blocked + * 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. + * + * Returns: the number of messages sent (may be zero), or -1 on error + * + * Since: 0.1.5 + */ +gint +nice_agent_send_messages_nonblocking ( + NiceAgent *agent, + guint stream_id, + guint component_id, + const NiceOutputMessage *messages, + guint n_messages, + GCancellable *cancellable, + GError **error); + +/** + * nice_agent_get_local_candidates: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Retrieve from the agent the list of all local candidates + * for a stream's component + * + + + The caller owns the returned GSList as well as the candidates contained + within it. + To get full results, the client should wait for the + #NiceAgent::candidate-gathering-done signal. + + + * + * Returns: (element-type NiceCandidate) (transfer full): a #GSList of + * #NiceCandidate objects representing the local candidates of @agent + **/ +GSList * +nice_agent_get_local_candidates ( + NiceAgent *agent, + guint stream_id, + guint component_id); + + +/** + * nice_agent_get_remote_candidates: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Get a list of the remote candidates set on a stream's component + * + + + The caller owns the returned GSList as well as the candidates contained + within it. + + + The list of remote candidates can change during processing. + The client should register for the #NiceAgent::new-remote-candidate signal + to get notified of new remote candidates. + + + * + * Returns: (element-type NiceCandidate) (transfer full): a #GSList of + * #NiceCandidates objects representing the remote candidates set on the @agent + **/ +GSList * +nice_agent_get_remote_candidates ( + NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_agent_restart: + * @agent: The #NiceAgent Object + * + * Restarts the session as defined in ICE draft 19. This function + * needs to be called both when initiating (ICE spec section 9.1.1.1. + * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1. + * "Detecting ICE Restart") to a restart. + * + * Returns: %TRUE on success %FALSE on error + **/ +gboolean +nice_agent_restart ( + NiceAgent *agent); + +/** + * nice_agent_restart_stream: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * + * Restarts a single stream as defined in RFC 5245. This function + * needs to be called both when initiating (ICE spec section 9.1.1.1. + * "ICE Restarts"), as well as when reacting (spec section 9.2.1.1. + * "Detecting ICE Restart") to a restart. + * + * Unlike nice_agent_restart(), this applies to a single stream. It also + * does not generate a new tie breaker. + * + * Returns: %TRUE on success %FALSE on error + * + * Since: 0.1.6 + **/ +gboolean +nice_agent_restart_stream ( + NiceAgent *agent, + guint stream_id); + + +/** + * nice_agent_attach_recv: (skip) + * @agent: The #NiceAgent Object + * @stream_id: The ID of stream + * @component_id: The ID of the component + * @ctx: The Glib Mainloop Context to use for listening on the component + * @func: The callback function to be called when data is received on + * the stream's component (will not be called for STUN messages that + * should be handled by #NiceAgent itself) + * @data: user data associated with the callback + * + * Attaches the stream's component's sockets to the Glib Mainloop Context in + * order to be notified whenever data becomes available for a component, + * and to enable #NiceAgent to receive STUN messages (during the + * 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. + * + * 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 + * pair. You must iterate the previously specified #GMainContext sufficiently to + * ensure all pending I/O callbacks have been received before calling this + * function to unset @func, otherwise data loss of received packets may occur. + * + * Returns: %TRUE on success, %FALSE if the stream or component IDs are invalid. + */ +gboolean +nice_agent_attach_recv ( + NiceAgent *agent, + guint stream_id, + guint component_id, + GMainContext *ctx, + NiceAgentRecvFunc func, + gpointer data); + +/** + * nice_agent_recv: + * @agent: a #NiceAgent + * @stream_id: the ID of the stream to receive on + * @component_id: the ID of the component to receive on + * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer + * to write the received data into, of length at least @buf_len + * @buf_len: length of @buf + * @cancellable: (allow-none): a #GCancellable to allow the operation to be + * cancelled from another thread, or %NULL + * @error: (allow-none): return location for a #GError, or %NULL + * + * 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 + * + * Since: 0.1.5 + */ +gssize +nice_agent_recv ( + NiceAgent *agent, + guint stream_id, + guint component_id, + guint8 *buf, + gsize buf_len, + GCancellable *cancellable, + GError **error); + +/** + * nice_agent_recv_messages: + * @agent: a #NiceAgent + * @stream_id: the ID of the stream to receive on + * @component_id: the ID of the component to receive on + * @messages: (array length=n_messages) (out caller-allocates): caller-allocated + * array of #NiceInputMessages to write the received messages into, of length at + * least @n_messages + * @n_messages: number of entries in @messages + * @cancellable: (allow-none): a #GCancellable to allow the operation to be + * cancelled from another thread, or %NULL + * @error: (allow-none): return location for a #GError, or %NULL + * + * Block on receiving data from the given stream/component combination on + * @agent, returning only once exactly @n_messages messages have been received + * and written into @messages, the stream is closed by the other end or by + * calling nice_agent_remove_stream(), or @cancellable is cancelled. + * + * Any STUN packets received will not be added to @messages; instead, + * they'll be passed for processing to #NiceAgent itself. Since #NiceAgent + * 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. + * + * 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, + * #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. + * + * This must not be used in combination with nice_agent_attach_recv() on the + * same stream/component pair. + * + * If the stream/component pair doesn’t exist, or if a suitable candidate socket + * hasn’t yet been selected for it, a %G_IO_ERROR_BROKEN_PIPE error will be + * returned. A %G_IO_ERROR_CANCELLED error will be returned if the operation was + * cancelled. %G_IO_ERROR_FAILED will be returned for other errors. + * + * Returns: the number of valid messages written to @messages on success + * (guaranteed to be greater than 0 unless @n_messages is 0), 0 if the remote + * peer closed the stream, or -1 on error + * + * Since: 0.1.5 + */ +gint +nice_agent_recv_messages ( + NiceAgent *agent, + guint stream_id, + guint component_id, + NiceInputMessage *messages, + guint n_messages, + GCancellable *cancellable, + GError **error); + +/** + * nice_agent_recv_nonblocking: + * @agent: a #NiceAgent + * @stream_id: the ID of the stream to receive on + * @component_id: the ID of the component to receive on + * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer + * to write the received data into, of length at least @buf_len + * @buf_len: length of @buf + * @cancellable: (allow-none): a #GCancellable to allow the operation to be + * cancelled from another thread, or %NULL + * @error: (allow-none): return location for a #GError, or %NULL + * + * 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 + * + * Since: 0.1.5 + */ +gssize +nice_agent_recv_nonblocking ( + NiceAgent *agent, + guint stream_id, + guint component_id, + guint8 *buf, + gsize buf_len, + GCancellable *cancellable, + GError **error); + +/** + * nice_agent_recv_messages_nonblocking: + * @agent: a #NiceAgent + * @stream_id: the ID of the stream to receive on + * @component_id: the ID of the component to receive on + * @messages: (array length=n_messages) (out caller-allocates): caller-allocated + * array of #NiceInputMessages to write the received messages into, of length at + * least @n_messages + * @n_messages: number of entries in @messages + * @cancellable: (allow-none): a #GCancellable to allow the operation to be + * cancelled from another thread, or %NULL + * @error: (allow-none): return location for a #GError, or %NULL + * + * Try to receive data from the given stream/component combination on @agent, + * without blocking. If receiving data would block, -1 is returned and + * %G_IO_ERROR_WOULD_BLOCK is set in @error. If any other error occurs, -1 is + * returned and @error is set accordingly. Otherwise, 0 is returned if (and only + * if) @n_messages is 0. In all other cases, the number of valid messages stored + * 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 + * messages until it would block. + * + * Any STUN packets received will not be added to @messages; instead, + * they'll be passed for processing to #NiceAgent itself. Since #NiceAgent + * does not poll for messages on its own, it's therefore essential to keep + * calling this function for ICE connection establishment to work. + * + * As this function is non-blocking, @cancellable is included only for parity + * with nice_agent_recv_messages(). If @cancellable is cancelled before this + * function is called, a %G_IO_ERROR_CANCELLED error will be returned + * immediately. + * + * This must not be used in combination with nice_agent_attach_recv() on the + * 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 + * + * Since: 0.1.5 + */ +gint +nice_agent_recv_messages_nonblocking ( + NiceAgent *agent, + guint stream_id, + guint component_id, + NiceInputMessage *messages, + guint n_messages, + GCancellable *cancellable, + GError **error); + +/** + * nice_agent_set_selected_pair: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * @lfoundation: The local foundation of the candidate to use + * @rfoundation: The remote foundation of the candidate to use + * + * Sets the selected candidate pair for media transmission + * for a given stream's component. Calling this function will + * disable all further ICE processing (connection check, + * state machine updates, etc). Note that keepalives will + * continue to be sent. + * + * Returns: %TRUE on success, %FALSE if the candidate pair cannot be found + */ +gboolean +nice_agent_set_selected_pair ( + NiceAgent *agent, + guint stream_id, + guint component_id, + const gchar *lfoundation, + const gchar *rfoundation); + +/** + * nice_agent_get_selected_pair: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * @local: The local selected candidate + * @remote: The remote selected candidate + * + * Retreive the selected candidate pair for media transmission + * for a given stream's component. + * + * Returns: %TRUE on success, %FALSE if there is no selected candidate pair + */ +gboolean +nice_agent_get_selected_pair ( + NiceAgent *agent, + guint stream_id, + guint component_id, + NiceCandidate **local, + NiceCandidate **remote); + +/** + * nice_agent_get_selected_socket: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Retreive the local socket associated with the selected candidate pair + * for media transmission for a given stream's component. + * + * This is useful for adding ICE support to legacy applications that already + * have a protocol that maintains a connection. If the socket is duplicated + * before unrefing the agent, the application can take over and continue to use + * it. New applications are encouraged to use the built in libnice stream + * handling instead and let libnice handle the connection maintenance. + * + * Users of this method are encouraged to not use a TURN relay or any kind + * of proxy, as in this case, the socket will not be available to the + * application because the packets are encapsulated. + * + * Returns: (transfer full) (nullable): pointer to the #GSocket, or %NULL if + * there is no selected candidate or if the selected candidate is a relayed + * candidate. + * + * Since: 0.1.5 + */ +GSocket * +nice_agent_get_selected_socket ( + NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_agent_set_selected_remote_candidate: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * @candidate: The #NiceCandidate to select + * + * Sets the selected remote candidate for media transmission + * for a given stream's component. This is used to force the selection of + * a specific remote candidate even when connectivity checks are failing + * (e.g. non-ICE compatible candidates). + * Calling this function will disable all further ICE processing + * (connection check, state machine updates, etc). Note that keepalives will + * continue to be sent. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +nice_agent_set_selected_remote_candidate ( + NiceAgent *agent, + guint stream_id, + guint component_id, + NiceCandidate *candidate); + + +/** + * nice_agent_set_stream_tos: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @tos: The ToS to set + * + * Sets the IP_TOS and/or IPV6_TCLASS field on the stream's sockets' options + * + * Since: 0.0.9 + */ +void nice_agent_set_stream_tos ( + NiceAgent *agent, + guint stream_id, + gint tos); + + + +/** + * nice_agent_set_software: + * @agent: The #NiceAgent Object + * @software: The value of the SOFTWARE attribute to add. + * + * This function will set the value of the SOFTWARE attribute to be added to + * STUN requests, responses and error responses sent during connectivity checks. + * + * The SOFTWARE attribute will only be added in the #NICE_COMPATIBILITY_RFC5245 + * and #NICE_COMPATIBILITY_WLM2009 compatibility modes. + * + * + * + + The @software argument will be appended with the libnice version before + being sent. + + + The @software argument must be in UTF-8 encoding and only the first + 128 characters will be sent. + + + * + * Since: 0.0.10 + * + */ +void nice_agent_set_software ( + NiceAgent *agent, + const gchar *software); + +/** + * nice_agent_set_stream_name: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream to change + * @name: The new name of the stream or %NULL + * + * This function will assign a media type to a stream. The only values + * that can be used to produce a valid SDP are: "audio", "video", + * "text", "application", "image" and "message". + * + * This is only useful when parsing and generating an SDP of the + * candidates. + * + * See also: nice_agent_generate_local_sdp() + * See also: nice_agent_parse_remote_sdp() + * See also: nice_agent_get_stream_name() + * + * Returns: %TRUE if the name has been set. %FALSE in case of error + * (invalid stream or duplicate name). + * Since: 0.1.4 + */ +gboolean nice_agent_set_stream_name ( + NiceAgent *agent, + guint stream_id, + const gchar *name); + +/** + * nice_agent_get_stream_name: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream to change + * + * This function will return the name assigned to a stream. + + * See also: nice_agent_set_stream_name() + * + * Returns: The name of the stream. The name is only valid while the stream + * exists or until it changes through a call to nice_agent_set_stream_name(). + * + * + * Since: 0.1.4 + */ +const gchar *nice_agent_get_stream_name ( + NiceAgent *agent, + guint stream_id); + +/** + * nice_agent_get_default_local_candidate: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * This helper function will return the recommended default candidate to be + * used for non-ICE compatible clients. This will usually be the candidate + * with the lowest priority, since it will be the longest path but the one with + * the most chances of success. + * + + This function is only useful in order to manually generate the + local SDP + + * + * + * Returns: The candidate to be used as the default candidate, or %NULL in case + * of error. Must be freed with nice_candidate_free() once done. + * + */ +NiceCandidate * +nice_agent_get_default_local_candidate ( + NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_agent_generate_local_sdp: + * @agent: The #NiceAgent Object + * + * Generate an SDP string containing the local candidates and credentials for + * all streams and components in the agent. + * + + + The SDP will not contain any codec lines and the 'm' line will not list + any payload types. + + + It is highly recommended to set names on the streams prior to calling this + function. Unnamed streams will show up as '-' in the 'm' line, but the SDP + will not be parseable with nice_agent_parse_remote_sdp() if a stream is + unnamed. + + + The default candidate in the SDP will be selected based on the lowest + priority candidate for the first component. + + + * + * See also: nice_agent_set_stream_name() + * See also: nice_agent_parse_remote_sdp() + * See also: nice_agent_generate_local_stream_sdp() + * See also: nice_agent_generate_local_candidate_sdp() + * See also: nice_agent_get_default_local_candidate() + * + * Returns: A string representing the local SDP. Must be freed with g_free() + * once done. + * + * Since: 0.1.4 + **/ +gchar * +nice_agent_generate_local_sdp ( + NiceAgent *agent); + +/** + * nice_agent_generate_local_stream_sdp: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @include_non_ice: Whether or not to include non ICE specific lines + * (m=, c= and a=rtcp: lines) + * + * Generate an SDP string containing the local candidates and credentials + * for a stream. + * + + + The SDP will not contain any codec lines and the 'm' line will not list + any payload types. + + + It is highly recommended to set the name of the stream prior to calling this + function. Unnamed streams will show up as '-' in the 'm' line. + + + The default candidate in the SDP will be selected based on the lowest + priority candidate. + + + * + * See also: nice_agent_set_stream_name() + * See also: nice_agent_parse_remote_stream_sdp() + * See also: nice_agent_generate_local_sdp() + * See also: nice_agent_generate_local_candidate_sdp() + * See also: nice_agent_get_default_local_candidate() + * + * Returns: A string representing the local SDP for the stream. Must be freed + * with g_free() once done. + * + * Since: 0.1.4 + **/ +gchar * +nice_agent_generate_local_stream_sdp ( + NiceAgent *agent, + guint stream_id, + gboolean include_non_ice); + +/** + * nice_agent_generate_local_candidate_sdp: + * @agent: The #NiceAgent Object + * @candidate: The candidate to generate + * + * Generate an SDP string representing a local candidate. + * + * See also: nice_agent_parse_remote_candidate_sdp() + * See also: nice_agent_generate_local_sdp() + * See also: nice_agent_generate_local_stream_sdp() + * + * Returns: A string representing the SDP for the candidate. Must be freed + * with g_free() once done. + * + * Since: 0.1.4 + **/ +gchar * +nice_agent_generate_local_candidate_sdp ( + NiceAgent *agent, + NiceCandidate *candidate); + +/** + * nice_agent_parse_remote_sdp: + * @agent: The #NiceAgent Object + * @sdp: The remote SDP to parse + * + * Parse an SDP string and extracts candidates and credentials from it and sets + * them on the agent. + * + * See also: nice_agent_set_stream_name() + * See also: nice_agent_generate_local_sdp() + * See also: nice_agent_parse_remote_stream_sdp() + * See also: nice_agent_parse_remote_candidate_sdp() + * + * Returns: The number of candidates added, negative on errors + * + * Since: 0.1.4 + **/ +int +nice_agent_parse_remote_sdp ( + NiceAgent *agent, + const gchar *sdp); + + +/** + * nice_agent_parse_remote_stream_sdp: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream to parse + * @sdp: The remote SDP to parse + * @ufrag: Pointer to store the ice ufrag if non %NULL. Must be freed with + * g_free() after use + * @pwd: Pointer to store the ice password if non %NULL. Must be freed with + * g_free() after use + * + * Parse an SDP string representing a single stream and extracts candidates + * and credentials from it. + * + * See also: nice_agent_generate_local_stream_sdp() + * See also: nice_agent_parse_remote_sdp() + * See also: nice_agent_parse_remote_candidate_sdp() + * + * Returns: (element-type NiceCandidate) (transfer full): A #GSList of + * candidates parsed from the SDP, or %NULL in case of errors + * + * Since: 0.1.4 + **/ +GSList * +nice_agent_parse_remote_stream_sdp ( + NiceAgent *agent, + guint stream_id, + const gchar *sdp, + gchar **ufrag, + gchar **pwd); + + +/** + * nice_agent_parse_remote_candidate_sdp: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream the candidate belongs to + * @sdp: The remote SDP to parse + * + * Parse an SDP string and extracts the candidate from it. + * + * See also: nice_agent_generate_local_candidate_sdp() + * See also: nice_agent_parse_remote_sdp() + * See also: nice_agent_parse_remote_stream_sdp() + * + * Returns: The parsed candidate or %NULL if there was an error. + * + * Since: 0.1.4 + **/ +NiceCandidate * +nice_agent_parse_remote_candidate_sdp ( + NiceAgent *agent, + guint stream_id, + 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. + * + * 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): A #GIOStream. + * + * Since: 0.1.5 + */ +GIOStream * +nice_agent_get_io_stream ( + NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_component_state_to_string: + * @state: a #NiceComponentState + * + * Returns a string representation of the state, generally to use in debug + * messages. + * + * Returns: (transfer none): a string representation of @state + * Since: 0.1.6 + */ +const gchar * +nice_component_state_to_string (NiceComponentState state); + +/** + * nice_agent_forget_relays: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Forget all the relay servers previously added using + * nice_agent_set_relay_info(). Currently connected streams will keep + * using the relay as long as they have not been restarted and haven't + * succesfully negotiated a different path. + * + * Returns: %FALSE if the component could not be found, %TRUE otherwise + * + * Since: 0.1.6 + */ +gboolean +nice_agent_forget_relays (NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_agent_get_component_state: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Retrieves the current state of a component. + * + * Returns: the #NiceComponentState of the component and + * %NICE_COMPONENT_STATE_FAILED if the component was invalid. + * + * Since: 0.1.8 + */ +NiceComponentState +nice_agent_get_component_state (NiceAgent *agent, + guint stream_id, + guint component_id); + +/** + * nice_agent_peer_candidate_gathering_done: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * + * Notifies the agent that the remote peer has concluded candidate gathering and + * thus no more remote candidates are expected to arrive for @stream_id. + * + * This will allow the stream components without a successful connectivity check + * to stop waiting for more candidates to come and finally transit into + * %NICE_COMPONENT_STATE_FAILED. + * + * Calling the function has an effect only when #NiceAgent:trickle-ice is %TRUE. + * + * Returns: %FALSE if the stream could not be found, %TRUE otherwise + * + * Since: 0.1.16 + */ +gboolean +nice_agent_peer_candidate_gathering_done ( + NiceAgent *agent, + guint stream_id); + +/** + * nice_agent_close_async: + * @agent: The #NiceAgent object + * @callback: (nullable): A callback that will be called when the closing is + * complete + * @callback_data: (nullable): A pointer that will be passed to the callback + * + * Asynchronously closes resources the agent has allocated on remote servers. + * + * The agent will call the callback in the current #GMainContext in + * which this function is called. The #GAsyncResult in the callback + * can be ignored as this operation never fails. + * + * Calling this function before freeing the agent makes sure the allocated relay + * ports aren't left behind on TURN server but properly removed. + * + * Since: 0.1.16 + */ +void +nice_agent_close_async (NiceAgent *agent, GAsyncReadyCallback callback, + gpointer callback_data); + +/** + * nice_agent_get_sockets: + * @agent: The #NiceAgent Object + * @stream_id: The ID of the stream + * @component_id: The ID of the component + * + * Each component can have multiple sockets, this is an API to retrieve them all + * to be able to set properties. Most of the sockets for a component are created when + * calling nice_agent_gather_candidates(), so this API should be called right after to + * able to set properties on the sockets before they are used. + * + * These sockets can be a mix of UDP & TCP sockets depending on the compatibility mode + * and options that have been set. + * + * Returns: (element-type GSocket) (transfer full): An array + * containing all of the sockets for this component. Free with + * g_ptr_array_unref() when done. + * + * Since: 0.1.17 + */ +GPtrArray * +nice_agent_get_sockets (NiceAgent *agent, guint stream_id, guint component_id); + +G_END_DECLS + +#endif /* __LIBNICE_AGENT_H__ */ diff --git a/linux_arm32v7/include/nice/candidate.h b/linux_arm32v7/include/nice/candidate.h new file mode 100644 index 0000000..315daba --- /dev/null +++ b/linux_arm32v7/include/nice/candidate.h @@ -0,0 +1,269 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2006-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2006-2009 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 __LIBNICE_CANDIDATE_H__ +#define __LIBNICE_CANDIDATE_H__ + +#include +#include + + +/** + * SECTION:candidate + * @short_description: ICE candidate representation + * @see_also: #NiceAddress + * @stability: Stable + * + * A representation of an ICE candidate. Make sure you read the ICE drafts[1] to + * understand correctly the concept of ICE candidates. + * + * [1] http://tools.ietf.org/wg/mmusic/draft-ietf-mmusic-ice/ + */ + + +G_BEGIN_DECLS + +/* Constants for determining candidate priorities */ +#define NICE_CANDIDATE_TYPE_PREF_HOST 120 +#define NICE_CANDIDATE_TYPE_PREF_PEER_REFLEXIVE 110 +#define NICE_CANDIDATE_TYPE_PREF_NAT_ASSISTED 105 +#define NICE_CANDIDATE_TYPE_PREF_SERVER_REFLEXIVE 100 +#define NICE_CANDIDATE_TYPE_PREF_RELAYED_UDP 30 +#define NICE_CANDIDATE_TYPE_PREF_RELAYED 20 + +/* Priority preference constants for MS-ICE compatibility */ +#define NICE_CANDIDATE_TRANSPORT_MS_PREF_UDP 15 +#define NICE_CANDIDATE_TRANSPORT_MS_PREF_TCP 6 +#define NICE_CANDIDATE_DIRECTION_MS_PREF_PASSIVE 2 +#define NICE_CANDIDATE_DIRECTION_MS_PREF_ACTIVE 5 + +/* Max foundation size '1*32ice-char' plus terminating NULL, ICE ID-19 */ +/** + * NICE_CANDIDATE_MAX_FOUNDATION: + * + * The maximum size a candidate foundation can have. + */ +#define NICE_CANDIDATE_MAX_FOUNDATION (32+1) + + +/** + * NiceCandidateType: + * @NICE_CANDIDATE_TYPE_HOST: A host candidate + * @NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: A server reflexive candidate + * @NICE_CANDIDATE_TYPE_PEER_REFLEXIVE: A peer reflexive candidate + * @NICE_CANDIDATE_TYPE_RELAYED: A relay candidate + * + * An enum represneting the type of a candidate + */ +typedef enum +{ + NICE_CANDIDATE_TYPE_HOST, + NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE, + NICE_CANDIDATE_TYPE_PEER_REFLEXIVE, + NICE_CANDIDATE_TYPE_RELAYED, +} NiceCandidateType; + +/** + * NiceCandidateTransport: + * @NICE_CANDIDATE_TRANSPORT_UDP: UDP transport + * @NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE: TCP Active transport + * @NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE: TCP Passive transport + * @NICE_CANDIDATE_TRANSPORT_TCP_SO: TCP Simultaneous-Open transport + * + * An enum representing the type of transport to use + */ +typedef enum +{ + NICE_CANDIDATE_TRANSPORT_UDP, + NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE, + NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE, + NICE_CANDIDATE_TRANSPORT_TCP_SO, +} NiceCandidateTransport; + +/** + * NiceRelayType: + * @NICE_RELAY_TYPE_TURN_UDP: A TURN relay using UDP + * @NICE_RELAY_TYPE_TURN_TCP: A TURN relay using TCP + * @NICE_RELAY_TYPE_TURN_TLS: A TURN relay using TLS over TCP + * + * An enum representing the type of relay to use + */ +typedef enum { + NICE_RELAY_TYPE_TURN_UDP, + NICE_RELAY_TYPE_TURN_TCP, + NICE_RELAY_TYPE_TURN_TLS +} NiceRelayType; + + +typedef struct _NiceCandidate NiceCandidate; + +typedef struct _TurnServer TurnServer; + +/** + * TurnServer: + * @ref_count: Reference count for the structure. + * @server: The #NiceAddress of the TURN server + * @username: The TURN username + * @password: The TURN password + * @decoded_username: The base64 decoded TURN username + * @decoded_password: The base64 decoded TURN password + * @decoded_username_len: The length of @decoded_username + * @decoded_password_len: The length of @decoded_password + * @type: The #NiceRelayType of the server + * + * A structure to store the TURN relay settings + */ +struct _TurnServer +{ + gint ref_count; + + NiceAddress server; + gchar *username; + gchar *password; + guint8 *decoded_username; + guint8 *decoded_password; + gsize decoded_username_len; + gsize decoded_password_len; + NiceRelayType type; +}; + +/** + * NiceCandidate: + * @type: The type of candidate + * @transport: The transport being used for the candidate + * @addr: The #NiceAddress of the candidate + * @base_addr: The #NiceAddress of the base address used by the candidate + * @priority: The priority of the candidate see note + * @stream_id: The ID of the stream to which belongs the candidate + * @component_id: The ID of the component to which belongs the candidate + * @foundation: The foundation of the candidate + * @username: The candidate-specific username to use (overrides the one set + * by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials()) + * @password: The candidate-specific password to use (overrides the one set + * by nice_agent_set_local_credentials() or nice_agent_set_remote_credentials()) + * @turn: The #TurnServer settings if the candidate is + * of type %NICE_CANDIDATE_TYPE_RELAYED + * @sockptr: The underlying socket + * + * A structure to represent an ICE candidate + + + The @priority is an integer as specified in the ICE draft 19. If you are + using the MSN or the GOOGLE compatibility mode (which are based on ICE + draft 6, which uses a floating point qvalue as priority), then the @priority + value will represent the qvalue multiplied by 1000. + + + */ +struct _NiceCandidate +{ + NiceCandidateType type; + NiceCandidateTransport transport; + NiceAddress addr; + NiceAddress base_addr; + guint32 priority; + guint stream_id; + guint component_id; + gchar foundation[NICE_CANDIDATE_MAX_FOUNDATION]; + gchar *username; /* pointer to a nul-terminated username string */ + gchar *password; /* pointer to a nul-terminated password string */ + TurnServer *turn; + gpointer sockptr; +}; + +/** + * nice_candidate_new: + * @type: The #NiceCandidateType of the candidate to create + * + * Creates a new candidate. Must be freed with nice_candidate_free() + * + * Returns: A new #NiceCandidate + */ +NiceCandidate * +nice_candidate_new (NiceCandidateType type); + +/** + * nice_candidate_free: + * @candidate: The candidate to free + * + * Frees a #NiceCandidate + */ +void +nice_candidate_free (NiceCandidate *candidate); + +/** + * nice_candidate_copy: + * @candidate: The candidate to copy + * + * Makes a copy of a #NiceCandidate + * + * Returns: A new #NiceCandidate, a copy of @candidate + */ +NiceCandidate * +nice_candidate_copy (const NiceCandidate *candidate); + +/** + * nice_candidate_equal_target: + * @candidate1: A candidate + * @candidate2: A candidate + * + * Verifies that the candidates point to the same place, meaning they have + * the same transport and the same address. It ignores all other aspects. + * + * Returns: %TRUE if the candidates point to the same place + * + * Since: 0.1.15 + */ +gboolean +nice_candidate_equal_target (const NiceCandidate *candidate1, + const NiceCandidate *candidate2); + + GType nice_candidate_get_type (void); + +/** + * NICE_TYPE_CANDIDATE: + * + * A boxed type for a #NiceCandidate. + */ +#define NICE_TYPE_CANDIDATE nice_candidate_get_type () + +G_END_DECLS + +#endif /* __LIBNICE_CANDIDATE_H__ */ + diff --git a/linux_arm32v7/include/nice/debug.h b/linux_arm32v7/include/nice/debug.h new file mode 100644 index 0000000..c1a6473 --- /dev/null +++ b/linux_arm32v7/include/nice/debug.h @@ -0,0 +1,105 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2008 Nokia Corporation. All rights reserved. + * + * 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: + * Youness Alaoui, 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 + * 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 __LIBNICE_DEBUG_H__ +#define __LIBNICE_DEBUG_H__ + + +/** + * SECTION:debug + * @short_description: Debug messages utility functions + * @stability: Unstable + * + * Libnice can output a lot of information when debug messages are enabled. + * This can significantly help track down problems and/or understand what + * it's doing. + * + * You can enable/disable the debug messages by calling nice_debug_enable() + * or nice_debug_disable() and choosing whether you want only ICE debug messages + * or also stun debug messages. + * + * By default, the debug messages are disabled, unless the environment + * variable NICE_DEBUG is set, in which case, it must contain a comma separated + * list of flags specifying which debug to enable. + * The currently available flags are "nice", "stun", "pseudotcp", + * "pseudotcp-verbose" or "all" to enable all debug messages. + * If the 'pseudotcp' flag is enabled, then 'pseudotcp-verbose' gets + * automatically disabled. This is to allow the use of the 'all' flag without + * having verbose messages from pseudotcp. You can enable verbose debug messages + * from the pseudotcp layer by specifying 'pseudotcp-verbose' without the + * 'pseudotcp' flag. + * + * + * This API is unstable and is subject to change at any time... + * More flags are to come and a better API to enable/disable each flag + * should be added. + */ + + +#include + +G_BEGIN_DECLS + +/** + * nice_debug_enable: + * @with_stun: Also enable STUN debugging messages + * + * Enables libnice debug output to the terminal. Note that the + * `G_MESSAGES_DEBUG` and `NICE_DEBUG` environment variables must be set to the + * set of logging domains to print, in order for any output to be printed. Set + * them to `all` to print all debugging messages, or any of the following + * domains: + * - `libnice-stun` + * - `libnice-tests` + * - `libnice-socket` + * - `libnice` + * - `libnice-pseudotcp` + * - `libnice-pseudotcp-verbose` + */ +void nice_debug_enable (gboolean with_stun); + +/** + * nice_debug_disable: + * @with_stun: Also disable stun debugging messages + * + * Disables libnice debug output to the terminal + */ +void nice_debug_disable (gboolean with_stun); + +G_END_DECLS + +#endif /* __LIBNICE_DEBUG_H__ */ + diff --git a/linux_arm32v7/include/nice/interfaces.h b/linux_arm32v7/include/nice/interfaces.h new file mode 100644 index 0000000..50c627e --- /dev/null +++ b/linux_arm32v7/include/nice/interfaces.h @@ -0,0 +1,82 @@ +/* + * interfaces.h - Source for interface discovery code + * + * Farsight Helper functions + * Copyright (C) 2006 Youness Alaoui + * Copyright (C) 2008-2009 Collabora, Nokia + * Contact: Youness Alaoui + * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LIBNICE_INTERFACES_H__ +#define __LIBNICE_INTERFACES_H__ + +/** + * SECTION:interfaces + * @short_description: Utility functions to discover local network interfaces + * @include: interfaces.h + * @stability: Stable + * + * These utility functions allow the discovery of local network interfaces + * in a portable manner, they also allow finding the local ip addresses or + * the address allocated to a network interface. + */ + +#include + +G_BEGIN_DECLS + + +/** + * nice_interfaces_get_ip_for_interface: + * @interface_name: name of local interface + * + * Retrieves the IP address of an interface by its name. If this fails, %NULL + * is returned. + * + * Returns: (nullable) (transfer full): a newly-allocated string with the IP + * address + */ +gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name); + + +/** + * nice_interfaces_get_local_ips: + * @include_loopback: Include any loopback devices + * + * Get a list of local ipv4 interface addresses + * + * Returns: (element-type utf8) (transfer full): a newly-allocated #GList of + * strings. The caller must free it. + */ + +GList * nice_interfaces_get_local_ips (gboolean include_loopback); + + +/** + * nice_interfaces_get_local_interfaces: + * + * Get the list of local interfaces + * + * Returns: (element-type utf8) (transfer full): a newly-allocated #GList of + * strings. The caller must free it. + */ +GList * nice_interfaces_get_local_interfaces (void); + +G_END_DECLS + +#endif /* __LIBNICE_INTERFACES_H__ */ diff --git a/linux_arm32v7/include/nice/nice.h b/linux_arm32v7/include/nice/nice.h new file mode 100644 index 0000000..5587ec4 --- /dev/null +++ b/linux_arm32v7/include/nice/nice.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2006-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2006-2009 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. + * + * 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_H +#define _NICE_H + +#include "agent.h" +#include "interfaces.h" + +#endif /* _NICE_H */ + diff --git a/linux_arm32v7/include/nice/pseudotcp.h b/linux_arm32v7/include/nice/pseudotcp.h new file mode 100644 index 0000000..e087ddc --- /dev/null +++ b/linux_arm32v7/include/nice/pseudotcp.h @@ -0,0 +1,599 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2010, 2014 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: + * Youness Alaoui, Collabora Ltd. + * 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 + * 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 __LIBNICE_PSEUDOTCP_H__ +#define __LIBNICE_PSEUDOTCP_H__ + +/** + * SECTION:pseudotcp + * @short_description: Pseudo TCP implementation + * @include: pseudotcp.h + * @stability: Stable + * + * The #PseudoTcpSocket is an object implementing a Pseudo Tcp Socket for use + * over UDP. + * The socket will implement a subset of the TCP stack to allow for a reliable + * transport over non-reliable sockets (such as UDP). + * + * See the file tests/test-pseudotcp.c in the source package for an example + * of how to use the object. + * + * Since: 0.0.11 + */ + + + +#include + +#ifndef __GTK_DOC_IGNORE__ +#ifdef G_OS_WIN32 +# include + +#ifndef ECONNABORTED +# define ECONNABORTED WSAECONNABORTED +#endif + +#ifndef ENOTCONN +# define ENOTCONN WSAENOTCONN +#endif + +#ifndef EWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +#ifndef ECONNRESET +# define ECONNRESET WSAECONNRESET +#endif + +#ifndef EMSGSIZE +# define EMSGSIZE WSAEMSGSIZE +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT WSAETIMEDOUT +#endif +#endif +#endif + +#include "agent.h" + +G_BEGIN_DECLS + +/** + * PseudoTcpSocket: + * + * The #PseudoTcpSocket is the GObject implementing the Pseudo TCP Socket + * + * Since: 0.0.11 + */ +typedef struct _PseudoTcpSocket PseudoTcpSocket; + +typedef struct _PseudoTcpSocketClass PseudoTcpSocketClass; + +GType pseudo_tcp_socket_get_type (void); + +/* TYPE MACROS */ +#define PSEUDO_TCP_SOCKET_TYPE \ + (pseudo_tcp_socket_get_type ()) +#define PSEUDO_TCP_SOCKET(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), PSEUDO_TCP_SOCKET_TYPE, \ + PseudoTcpSocket)) +#define PSEUDO_TCP_SOCKET_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), PSEUDO_TCP_SOCKET_TYPE, \ + PseudoTcpSocketClass)) +#define IS_PSEUDO_TCP_SOCKET(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), PSEUDO_TCP_SOCKET_TYPE)) +#define IS_PSEUDO_TCP_SOCKET_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), PSEUDO_TCP_SOCKET_TYPE)) +#define PSEUDOTCP_SOCKET_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), PSEUDO_TCP_SOCKET_TYPE, \ + PseudoTcpSocketClass)) + +/** + * PseudoTcpDebugLevel: + * @PSEUDO_TCP_DEBUG_NONE: Disable debug messages + * @PSEUDO_TCP_DEBUG_NORMAL: Enable basic debug messages + * @PSEUDO_TCP_DEBUG_VERBOSE: Enable verbose debug messages + * + * Valid values of debug levels to be set. + * + * Since: 0.0.11 + */ +typedef enum { + PSEUDO_TCP_DEBUG_NONE = 0, + PSEUDO_TCP_DEBUG_NORMAL, + PSEUDO_TCP_DEBUG_VERBOSE, +} PseudoTcpDebugLevel; + +/** + * PseudoTcpState: + * @PSEUDO_TCP_LISTEN: The socket's initial state. The socket isn't connected and is + * listening for an incoming connection + * @PSEUDO_TCP_SYN_SENT: The socket has sent a connection request (SYN) packet and is + * waiting for an answer + * @PSEUDO_TCP_SYN_RECEIVED: The socket has received a connection request (SYN) packet. + * @PSEUDO_TCP_ESTABLISHED: The socket is connected + * @PSEUDO_TCP_CLOSED: The socket has been closed + * @PSEUDO_TCP_FIN_WAIT_1: The socket has been closed locally but not remotely + * (Since: 0.1.8) + * @PSEUDO_TCP_FIN_WAIT_2: The socket has been closed locally but not remotely + * (Since: 0.1.8) + * @PSEUDO_TCP_CLOSING: The socket has been closed locally and remotely + * (Since: 0.1.8) + * @PSEUDO_TCP_TIME_WAIT: The socket has been closed locally and remotely + * (Since: 0.1.8) + * @PSEUDO_TCP_CLOSE_WAIT: The socket has been closed remotely but not locally + * (Since: 0.1.8) + * @PSEUDO_TCP_LAST_ACK: The socket has been closed locally and remotely + * (Since: 0.1.8) + * + * An enum representing the state of the #PseudoTcpSocket. These states + * correspond to the TCP states in RFC 793. + * See also: #PseudoTcpSocket:state + * + * Since: 0.0.11 + */ +typedef enum { + PSEUDO_TCP_LISTEN, + PSEUDO_TCP_SYN_SENT, + PSEUDO_TCP_SYN_RECEIVED, + PSEUDO_TCP_ESTABLISHED, + PSEUDO_TCP_CLOSED, + PSEUDO_TCP_FIN_WAIT_1, + PSEUDO_TCP_FIN_WAIT_2, + PSEUDO_TCP_CLOSING, + PSEUDO_TCP_TIME_WAIT, + PSEUDO_TCP_CLOSE_WAIT, + PSEUDO_TCP_LAST_ACK, +} PseudoTcpState; + +/** + * PseudoTcpWriteResult: + * @WR_SUCCESS: The write operation was successful + * @WR_TOO_LARGE: The socket type requires that message be sent atomically + * and the size of the message to be sent made this impossible. + * @WR_FAIL: There was an error sending the message + * + * An enum representing the result value of the write operation requested by + * the #PseudoTcpSocket. + * See also: %PseudoTcpCallbacks:WritePacket + * + * Since: 0.0.11 + */ +typedef enum { + WR_SUCCESS, + WR_TOO_LARGE, + WR_FAIL +} PseudoTcpWriteResult; + +/** + * PseudoTcpShutdown: + * @PSEUDO_TCP_SHUTDOWN_RD: Shut down the local reader only + * @PSEUDO_TCP_SHUTDOWN_WR: Shut down the local writer only + * @PSEUDO_TCP_SHUTDOWN_RDWR: Shut down both reading and writing + * + * Options for which parts of a connection to shut down when calling + * pseudo_tcp_socket_shutdown(). These correspond to the values passed to POSIX + * shutdown(). + * + * Since: 0.1.8 + */ +typedef enum { + PSEUDO_TCP_SHUTDOWN_RD, + PSEUDO_TCP_SHUTDOWN_WR, + PSEUDO_TCP_SHUTDOWN_RDWR, +} PseudoTcpShutdown; + +/** + * PseudoTcpCallbacks: + * @user_data: A user defined pointer to be passed to the callbacks + * @PseudoTcpOpened: The #PseudoTcpSocket is now connected + * @PseudoTcpReadable: The socket is readable + * @PseudoTcpWritable: The socket is writable + * @PseudoTcpClosed: The socket was closed (both sides) + * @WritePacket: This callback is called when the socket needs to send data. + * + * A structure containing callbacks functions that will be called by the + * #PseudoTcpSocket when some events happen. + * See also: #PseudoTcpWriteResult + * + * Since: 0.0.11 + */ +typedef struct { + gpointer user_data; + void (*PseudoTcpOpened) (PseudoTcpSocket *tcp, gpointer data); + void (*PseudoTcpReadable) (PseudoTcpSocket *tcp, gpointer data); + void (*PseudoTcpWritable) (PseudoTcpSocket *tcp, gpointer data); + void (*PseudoTcpClosed) (PseudoTcpSocket *tcp, guint32 error, gpointer data); + PseudoTcpWriteResult (*WritePacket) (PseudoTcpSocket *tcp, + const gchar * buffer, guint32 len, gpointer data); +} PseudoTcpCallbacks; + +/** + * pseudo_tcp_socket_new: + * @conversation: The conversation id for the socket. + * @callbacks: A pointer to the #PseudoTcpCallbacks structure for getting + * notified of the #PseudoTcpSocket events. + * + * Creates a new #PseudoTcpSocket for the specified conversation + * + + + The @callbacks must be non-NULL, in order to get notified of packets the + socket needs to send. + + + If the @callbacks structure was dynamicly allocated, it can be freed + after the call @pseudo_tcp_socket_new + + + * + * Returns: The new #PseudoTcpSocket object, %NULL on error + * + * Since: 0.0.11 + */ +PseudoTcpSocket *pseudo_tcp_socket_new (guint32 conversation, + PseudoTcpCallbacks *callbacks); + + +/** + * pseudo_tcp_socket_connect: + * @self: The #PseudoTcpSocket object. + * + * Connects the #PseudoTcpSocket to the peer with the same conversation id. + * The connection will only be successful after the + * %PseudoTcpCallbacks:PseudoTcpOpened callback is called + * + * Returns: %TRUE on success, %FALSE on failure (not in %TCP_LISTEN state) + * See also: pseudo_tcp_socket_get_error() + * + * Since: 0.0.11 + */ +gboolean pseudo_tcp_socket_connect(PseudoTcpSocket *self); + + +/** + * pseudo_tcp_socket_recv: + * @self: The #PseudoTcpSocket object. + * @buffer: The buffer to fill with received data + * @len: The length of @buffer + * + * Receive data from the socket. + * + + + Only call this on the %PseudoTcpCallbacks:PseudoTcpReadable callback. + + + This function should be called in a loop. If this function does not + return -1 with EWOULDBLOCK as the error, the + %PseudoTcpCallbacks:PseudoTcpReadable callback will not be called again. + + + * + * Returns: The number of bytes received or -1 in case of error + * See also: pseudo_tcp_socket_get_error() + * + * Since: 0.0.11 + */ +gint pseudo_tcp_socket_recv(PseudoTcpSocket *self, char * buffer, size_t len); + + +/** + * pseudo_tcp_socket_send: + * @self: The #PseudoTcpSocket object. + * @buffer: The buffer with data to send + * @len: The length of @buffer + * + * Send data on the socket. + * + + + If this function return -1 with EWOULDBLOCK as the error, or if the return + value is lower than @len, then the %PseudoTcpCallbacks:PseudoTcpWritable + callback will be called when the socket will become writable. + + + * + * Returns: The number of bytes sent or -1 in case of error + * See also: pseudo_tcp_socket_get_error() + * + * Since: 0.0.11 + */ +gint pseudo_tcp_socket_send(PseudoTcpSocket *self, const char * buffer, + guint32 len); + + +/** + * pseudo_tcp_socket_close: + * @self: The #PseudoTcpSocket object. + * @force: %TRUE to close the socket forcefully, %FALSE to close it gracefully + * + * Close the socket for sending. If @force is set to %FALSE, the socket will + * finish sending pending data before closing. If it is set to %TRUE, the socket + * will discard pending data and close the connection immediately (sending a TCP + * RST segment). + * + * The socket will be closed in both directions – sending and receiving – and + * any pending received data must be read before calling this function, by + * calling pseudo_tcp_socket_recv() until it blocks. If any pending data is in + * the receive buffer when pseudo_tcp_socket_close() is called, a TCP RST + * segment will be sent to the peer to notify it of the data loss. + * + + + The %PseudoTcpCallbacks:PseudoTcpClosed callback will not be called once + the socket gets closed. It is only used for aborted connection. + Instead, the socket gets closed when the pseudo_tcp_socket_get_next_clock() + function returns FALSE. + + + * + * See also: pseudo_tcp_socket_get_next_clock() + * + * Since: 0.0.11 + */ +void pseudo_tcp_socket_close(PseudoTcpSocket *self, gboolean force); + +/** + * pseudo_tcp_socket_shutdown: + * @self: The #PseudoTcpSocket object. + * @how: The directions of the connection to shut down. + * + * Shut down sending, receiving, or both on the socket, depending on the value + * of @how. The behaviour of pseudo_tcp_socket_send() and + * pseudo_tcp_socket_recv() will immediately change after this function returns + * (depending on the value of @how), though the socket may continue to process + * network traffic in the background even if sending or receiving data is + * forbidden. + * + * This is equivalent to the POSIX shutdown() function. Setting @how to + * %PSEUDO_TCP_SHUTDOWN_RDWR is equivalent to calling pseudo_tcp_socket_close(). + * + * Since: 0.1.8 + */ +void pseudo_tcp_socket_shutdown (PseudoTcpSocket *self, PseudoTcpShutdown how); + +/** + * pseudo_tcp_socket_get_error: + * @self: The #PseudoTcpSocket object. + * + * Return the last encountered error. + * + + + The return value can be : + + EINVAL (for pseudo_tcp_socket_connect()). + + + EWOULDBLOCK or ENOTCONN (for pseudo_tcp_socket_recv() and + pseudo_tcp_socket_send()). + + + + * + * Returns: The error code + * See also: pseudo_tcp_socket_connect() + * See also: pseudo_tcp_socket_recv() + * See also: pseudo_tcp_socket_send() + * + * Since: 0.0.11 + */ +int pseudo_tcp_socket_get_error(PseudoTcpSocket *self); + + +/** + * pseudo_tcp_socket_get_next_clock: + * @self: The #PseudoTcpSocket object. + * @timeout: A pointer to be filled with the new timeout. + * + * Call this to determine the timeout needed before the next time call + * to pseudo_tcp_socket_notify_clock() should be made. + * + * Returns: %TRUE if @timeout was filled, %FALSE if the socket is closed and + * ready to be destroyed. + * + * See also: pseudo_tcp_socket_notify_clock() + * + * Since: 0.0.11 + */ +gboolean pseudo_tcp_socket_get_next_clock(PseudoTcpSocket *self, + guint64 *timeout); + + +/** + * pseudo_tcp_socket_notify_clock: + * @self: The #PseudoTcpSocket object. + * + * Start the processing of receiving data, pending data or syn/acks. + * Call this based on timeout value returned by + * pseudo_tcp_socket_get_next_clock(). + * It's ok to call this too frequently. + * + * See also: pseudo_tcp_socket_get_next_clock() + * + * Since: 0.0.11 + */ +void pseudo_tcp_socket_notify_clock(PseudoTcpSocket *self); + + +/** + * pseudo_tcp_socket_notify_mtu: + * @self: The #PseudoTcpSocket object. + * @mtu: The new MTU of the socket + * + * Set the MTU of the socket + * + * Since: 0.0.11 + */ +void pseudo_tcp_socket_notify_mtu(PseudoTcpSocket *self, guint16 mtu); + + +/** + * pseudo_tcp_socket_notify_packet: + * @self: The #PseudoTcpSocket object. + * @buffer: The buffer containing the received data + * @len: The length of @buffer + * + * Notify the #PseudoTcpSocket when a new packet arrives + * + * Returns: %TRUE if the packet was processed successfully, %FALSE otherwise + * + * Since: 0.0.11 + */ +gboolean pseudo_tcp_socket_notify_packet(PseudoTcpSocket *self, + const gchar * buffer, guint32 len); + + +/** + * pseudo_tcp_socket_notify_message: + * @self: The #PseudoTcpSocket object. + * @message: A #NiceInputMessage containing the received data. + * + * Notify the #PseudoTcpSocket that a new message has arrived, and enqueue the + * data in its buffers to the #PseudoTcpSocket’s receive buffer. + * + * Returns: %TRUE if the packet was processed successfully, %FALSE otherwise + * + * Since: 0.1.5 + */ +gboolean pseudo_tcp_socket_notify_message (PseudoTcpSocket *self, + NiceInputMessage *message); + + +/** + * pseudo_tcp_set_debug_level: + * @level: The level of debug to set + * + * Sets the debug level to enable/disable normal/verbose debug messages. + * + * Since: 0.0.11 + */ +void pseudo_tcp_set_debug_level (PseudoTcpDebugLevel level); + + +/** + * pseudo_tcp_socket_get_available_bytes: + * @self: The #PseudoTcpSocket object. + * + * Gets the number of bytes of data in the buffer that can be read without + * receiving more packets from the network. + * + * Returns: The number of bytes or -1 if the connection is not established + * + * Since: 0.1.5 + */ + +gint pseudo_tcp_socket_get_available_bytes (PseudoTcpSocket *self); + +/** + * pseudo_tcp_socket_can_send: + * @self: The #PseudoTcpSocket object. + * + * Returns if there is space in the send buffer to send any data. + * + * Returns: %TRUE if data can be sent, %FALSE otherwise + * + * Since: 0.1.5 + */ + +gboolean pseudo_tcp_socket_can_send (PseudoTcpSocket *self); + +/** + * pseudo_tcp_socket_get_available_send_space: + * @self: The #PseudoTcpSocket object. + * + * Gets the number of bytes of space available in the transmission buffer. + * + * Returns: The number of bytes, or 0 if the connection is not established. + * + * Since: 0.1.5 + */ +gsize pseudo_tcp_socket_get_available_send_space (PseudoTcpSocket *self); + +/** + * pseudo_tcp_socket_set_time: + * @self: The #PseudoTcpSocket object. + * @current_time: Current monotonic time, in milliseconds; or zero to use the + * system monotonic clock. + * + * Sets the current monotonic time to be used by the TCP socket when calculating + * timeouts and expiry times. If this function is not called, or is called with + * @current_time as zero, g_get_monotonic_time() will be used. Otherwise, the + * specified @current_time will be used until it is updated by calling this + * function again. + * + * This function is intended for testing only, and should not be used in + * production code. + * + * Since: 0.1.8 + */ +void pseudo_tcp_socket_set_time (PseudoTcpSocket *self, guint32 current_time); + +/** + * pseudo_tcp_socket_is_closed: + * @self: The #PseudoTcpSocket object. + * + * Gets whether the socket is closed, with the shutdown handshake completed, + * and both peers no longer able to read or write data to the connection. + * + * Returns: %TRUE if the socket is closed in both directions, %FALSE otherwise + * Since: 0.1.8 + */ +gboolean pseudo_tcp_socket_is_closed (PseudoTcpSocket *self); + +/** + * pseudo_tcp_socket_is_closed_remotely: + * @self: The #PseudoTcpSocket object. + * + * Gets whether the socket has been closed on the remote peer’s side of the + * connection (i.e. whether pseudo_tcp_socket_close() has been called there). + * This is guaranteed to return %TRUE if pseudo_tcp_socket_is_closed() returns + * %TRUE. It will not return %TRUE after pseudo_tcp_socket_close() is called + * until a FIN segment is received from the remote peer. + * + * Returns: %TRUE if the remote peer has closed its side of the connection, + * %FALSE otherwise + * Since: 0.1.8 + */ +gboolean pseudo_tcp_socket_is_closed_remotely (PseudoTcpSocket *self); + +G_END_DECLS + +#endif /* __LIBNICE_PSEUDOTCP_H__ */ + diff --git a/linux_arm32v7/include/stun/constants.h b/linux_arm32v7/include/stun/constants.h new file mode 100644 index 0000000..29e1cec --- /dev/null +++ b/linux_arm32v7/include/stun/constants.h @@ -0,0 +1,203 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2008 Nokia Corporation. All rights reserved. + * + * 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: + * Youness Alaoui, 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 + * 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 _STUN_CONSTANTS_H +#define _STUN_CONSTANTS_H + + +/** + * SECTION:stunconstants + * @short_description: STUN constants + * @include: stun/constants.h + * @stability: Stable + * + * Various constants defining parts of the STUN and TURN protocols and + * on-the-wire packet formats. + */ + +/** + * STUN_ATTRIBUTE_LENGTH_LEN: + * + * Length of the length field of a STUN attribute (in bytes). + */ +/** + * STUN_ATTRIBUTE_LENGTH_POS: + * + * Offset of the length field of a STUN attribute (in bytes). + */ +/** + * STUN_ATTRIBUTE_TYPE_LEN: + * + * Length of the type field of a STUN attribute (in bytes). + */ +/** + * STUN_ATTRIBUTE_TYPE_POS: + * + * Offset of the type field of a STUN attribute (in bytes). + */ +/** + * STUN_ATTRIBUTE_VALUE_POS: + * + * Offset of the value field of a STUN attribute (in bytes). + */ +/** + * STUN_ID_LEN: + * + * Length of the ID field of a STUN message (in bytes). + */ +/** + * STUN_MAGIC_COOKIE: + * + * Magic cookie value used to identify STUN messages. + */ +/** + * TURN_MAGIC_COOKIE: + * + * Magic cookie value used to identify TURN messages. + */ +/** + * STUN_MAX_MESSAGE_SIZE_IPV4: + * + * Maximum size of a STUN message sent over IPv4 (in bytes). + */ +/** + * STUN_MAX_MESSAGE_SIZE_IPV6: + * + * Maximum size of a STUN message sent over IPv6 (in bytes). + */ +/** + * STUN_MESSAGE_ATTRIBUTES_POS: + * + * Offset of the attributes of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_HEADER_LENGTH: + * + * Total length of a STUN message header (in bytes). + */ +/** + * STUN_MESSAGE_LENGTH_LEN: + * + * Length of the length field of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_LENGTH_POS: + * + * Offset of the length field of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_TRANS_ID_LEN: + * + * Length of the transaction ID field of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_TRANS_ID_POS: + * + * Offset of the transaction ID field of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_TYPE_LEN: + * + * Length of the type field of a STUN message (in bytes). + */ +/** + * STUN_MESSAGE_TYPE_POS: + * + * Offset of the type field of a STUN message (in bytes). + */ + +#define STUN_MESSAGE_TYPE_POS 0 +#define STUN_MESSAGE_TYPE_LEN 2 +#define STUN_MESSAGE_LENGTH_POS \ + (STUN_MESSAGE_TYPE_POS + STUN_MESSAGE_TYPE_LEN) +#define STUN_MESSAGE_LENGTH_LEN 2 +#define STUN_MESSAGE_TRANS_ID_POS \ + (STUN_MESSAGE_LENGTH_POS + STUN_MESSAGE_LENGTH_LEN) +#define STUN_MESSAGE_TRANS_ID_LEN 16 +#define STUN_MESSAGE_ATTRIBUTES_POS \ + (STUN_MESSAGE_TRANS_ID_POS + STUN_MESSAGE_TRANS_ID_LEN) + +#define STUN_MESSAGE_HEADER_LENGTH STUN_MESSAGE_ATTRIBUTES_POS + +#define STUN_ATTRIBUTE_TYPE_POS 0 +#define STUN_ATTRIBUTE_TYPE_LEN 2 +#define STUN_ATTRIBUTE_LENGTH_POS \ + (STUN_ATTRIBUTE_TYPE_POS + STUN_ATTRIBUTE_TYPE_LEN) +#define STUN_ATTRIBUTE_LENGTH_LEN 2 +#define STUN_ATTRIBUTE_VALUE_POS \ + (STUN_ATTRIBUTE_LENGTH_POS + STUN_ATTRIBUTE_LENGTH_LEN) + +/** + * STUN_ATTRIBUTE_HEADER_LENGTH: + * + * Length of a single STUN attribute header (in bytes). + */ +#define STUN_ATTRIBUTE_HEADER_LENGTH STUN_ATTRIBUTE_VALUE_POS + + +#define STUN_MAX_MESSAGE_SIZE_IPV4 576 +#define STUN_MAX_MESSAGE_SIZE_IPV6 1280 +/* #define STUN_MAX_MESSAGE_SIZE STUN_MAX_MESSAGE_SIZE_IPV4 */ + +#define STUN_ID_LEN 16 + +/** + * STUN_AGENT_MAX_SAVED_IDS: + * + * Maximum number of simultaneously ongoing STUN transactions. + */ +#define STUN_AGENT_MAX_SAVED_IDS 200 + +/** + * STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES: + * + * Maximum number of unknown attribute which can be handled in a single STUN + * message. + */ +#define STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES 256 + +#define STUN_MAGIC_COOKIE 0x2112A442 +#define TURN_MAGIC_COOKIE 0x72c64bc6 + +#ifndef TRUE +#define TRUE (1 == 1) +#endif + +#ifndef FALSE +#define FALSE (0 == 1) +#endif + +#endif /* _STUN_CONSTANTS_H */ diff --git a/linux_arm32v7/include/stun/debug.h b/linux_arm32v7/include/stun/debug.h new file mode 100644 index 0000000..47a6114 --- /dev/null +++ b/linux_arm32v7/include/stun/debug.h @@ -0,0 +1,102 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2007 Nokia Corporation. All rights reserved. + * + * 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: + * Youness Alaoui, 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 + * 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 STUN_DEBUG_H +#define STUN_DEBUG_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * stun_debug_enable: + * + * Enable debug messages to stderr + */ +void stun_debug_enable (void); + +/** + * stun_debug_disable: + * + * Disable debug messages to stderr + */ +void stun_debug_disable (void); + +/** + * StunDebugHandler: + * @format: printf()-style debug message format string + * @ap: Parameters to substitute into message placeholders + * + * Callback for a debug message from the STUN code. + */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)) +typedef void (*StunDebugHandler) (const char *format, va_list ap) + __attribute__((__format__ (__printf__, 1, 0))); +#else +typedef void (*StunDebugHandler) (const char *format, va_list ap); +#endif + +/** + * stun_set_debug_handler: + * @handler: (nullable): Handler for STUN debug messages, or %NULL to use the + * default + * + * Set a callback function to be invoked for each debug message from the STUN + * code. The callback will only be invoked if STUN debugging is enabled using + * stun_debug_enable(). + * + * The default callback prints the formatted debug message to stderr. + */ +void stun_set_debug_handler (StunDebugHandler handler); + +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)) +void stun_debug (const char *fmt, ...) + __attribute__((__format__ (__printf__, 1, 2))); +#else +void stun_debug (const char *fmt, ...); +#endif +void stun_debug_bytes (const char *prefix, const void *data, size_t len); + + +# ifdef __cplusplus +} +# endif + +#endif /* STUN_DEBUG_H */ diff --git a/linux_arm32v7/include/stun/stunagent.h b/linux_arm32v7/include/stun/stunagent.h new file mode 100644 index 0000000..95e89fd --- /dev/null +++ b/linux_arm32v7/include/stun/stunagent.h @@ -0,0 +1,521 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2008-2009 Nokia Corporation. All rights reserved. + * + * 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: + * Youness Alaoui, 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 + * 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 _STUN_AGENT_H +#define _STUN_AGENT_H + +/** + * SECTION:stunagent + * @short_description: STUN agent for building and validating STUN messages + * @include: stun/stunagent.h + * @see_also: #StunMessage + * @stability: Stable + * + * The STUN Agent allows you to create and validate STUN messages easily. + * It's main purpose is to make sure the building and validation methods used + * are compatible with the RFC you create it with. It also tracks the transaction + * ids of the requests you send, so you can validate if a STUN response you + * received should be processed by that agent or not. + * + */ + + +#ifdef _WIN32 +#include "win32_common.h" +#else +#include +#endif + +#include +#include + +/** + * StunAgent: + * + * An opaque structure representing the STUN agent. + */ +typedef struct stun_agent_t StunAgent; + +#include "stunmessage.h" +#include "debug.h" + +/** + * StunCompatibility: + * @STUN_COMPATIBILITY_RFC3489: Use the STUN specifications compatible with + * RFC 3489 + * @STUN_COMPATIBILITY_RFC5389: Use the STUN specifications compatible with + * RFC 5389 + * @STUN_COMPATIBILITY_MSICE2: Use the STUN specifications compatible with + * [MS-ICE2] (a mix between RFC3489 and RFC5389) + * @STUN_COMPATIBILITY_OC2007: Use the STUN specifications compatible with + * Microsoft Office Communicator 2007 (basically RFC3489 with swapped + * REALM and NONCE attribute hex IDs, attributes are not aligned) + * @STUN_COMPATIBILITY_WLM2009: An alias for @STUN_COMPATIBILITY_MSICE2 + * @STUN_COMPATIBILITY_LAST: Dummy last compatibility mode + * + * Enum that specifies the STUN compatibility mode of the #StunAgent + * + * @STUN_COMPATIBILITY_WLM2009 is deprecated and should not be used + * in newly-written code. It is kept for compatibility reasons and represents + * the same compatibility as @STUN_COMPATIBILITY_MSICE2. + */ +typedef enum { + STUN_COMPATIBILITY_RFC3489, + STUN_COMPATIBILITY_RFC5389, + STUN_COMPATIBILITY_MSICE2, + STUN_COMPATIBILITY_OC2007, + STUN_COMPATIBILITY_WLM2009 = STUN_COMPATIBILITY_MSICE2, + STUN_COMPATIBILITY_LAST = STUN_COMPATIBILITY_OC2007 +} StunCompatibility; + + +/** + * StunValidationStatus: + * @STUN_VALIDATION_SUCCESS: The message is validated + * @STUN_VALIDATION_NOT_STUN: This is not a valid STUN message + * @STUN_VALIDATION_INCOMPLETE_STUN: The message seems to be valid but incomplete + * @STUN_VALIDATION_BAD_REQUEST: The message does not have the cookie or the + * fingerprint while the agent needs it with its usage + * @STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST: The message is valid but + * unauthorized with no username and message-integrity attributes. + * A BAD_REQUEST error must be generated + * @STUN_VALIDATION_UNAUTHORIZED: The message is valid but unauthorized as + * the username/password do not match. + * An UNAUTHORIZED error must be generated + * @STUN_VALIDATION_UNMATCHED_RESPONSE: The message is valid but this is a + * response/error that doesn't match a previously sent request + * @STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE: The message is valid but + * contains one or more unknown comprehension attributes. + * stun_agent_build_unknown_attributes_error() should be called + * @STUN_VALIDATION_UNKNOWN_ATTRIBUTE: The message is valid but contains one + * or more unknown comprehension attributes. This is a response, or error, + * or indication message and no error response should be sent + * + * This enum is used as the return value of stun_agent_validate() and represents + * the status result of the validation of a STUN message. + */ +typedef enum { + STUN_VALIDATION_SUCCESS, + STUN_VALIDATION_NOT_STUN, + STUN_VALIDATION_INCOMPLETE_STUN, + STUN_VALIDATION_BAD_REQUEST, + STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST, + STUN_VALIDATION_UNAUTHORIZED, + STUN_VALIDATION_UNMATCHED_RESPONSE, + STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE, + STUN_VALIDATION_UNKNOWN_ATTRIBUTE, +} StunValidationStatus; + +/** + * StunAgentUsageFlags: + * @STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS: The agent should be using the short + * term credentials mechanism for authenticating STUN messages + * @STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS: The agent should be using the long + * term credentials mechanism for authenticating STUN messages + * @STUN_AGENT_USAGE_USE_FINGERPRINT: The agent should add the FINGERPRINT + * attribute to the STUN messages it creates. + * @STUN_AGENT_USAGE_ADD_SOFTWARE: The agent should add the SOFTWARE attribute + * to the STUN messages it creates. Calling nice_agent_set_software() will have + * the same effect as enabling this Usage. STUN Indications do not have the + * SOFTWARE attributes added to them though. The SOFTWARE attribute is only + * added for the RFC5389 and MSICE2 compatibility modes. + * @STUN_AGENT_USAGE_IGNORE_CREDENTIALS: The agent should ignore any credentials + * in the STUN messages it receives (the MESSAGE-INTEGRITY attribute + * will never be validated by stun_agent_validate()) + * @STUN_AGENT_USAGE_NO_INDICATION_AUTH: The agent should ignore credentials + * in the STUN messages it receives if the #StunClass of the message is + * #STUN_INDICATION (some implementation require #STUN_INDICATION messages to + * be authenticated, while others never add a MESSAGE-INTEGRITY attribute to a + * #STUN_INDICATION message) + * @STUN_AGENT_USAGE_FORCE_VALIDATER: The agent should always try to validate + * the password of a STUN message, even if it already knows what the password + * should be (a response to a previously created request). This means that the + * #StunMessageIntegrityValidate callback will always be called when there is + * a MESSAGE-INTEGRITY attribute. + * @STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES: The agent should not assume STUN + * attributes are aligned on 32-bit boundaries when parsing messages and also + * do not add padding when creating messages. + * + * This enum defines a bitflag usages for a #StunAgent and they will define how + * the agent should behave, independently of the compatibility mode it uses. + * See also: stun_agent_init() + * See also: stun_agent_validate() + */ +typedef enum { + STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS = (1 << 0), + STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS = (1 << 1), + STUN_AGENT_USAGE_USE_FINGERPRINT = (1 << 2), + STUN_AGENT_USAGE_ADD_SOFTWARE = (1 << 3), + STUN_AGENT_USAGE_IGNORE_CREDENTIALS = (1 << 4), + STUN_AGENT_USAGE_NO_INDICATION_AUTH = (1 << 5), + STUN_AGENT_USAGE_FORCE_VALIDATER = (1 << 6), + STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES = (1 << 7), +} StunAgentUsageFlags; + + +typedef struct { + StunTransactionId id; + StunMethod method; + uint8_t *key; + size_t key_len; + uint8_t long_term_key[16]; + bool long_term_valid; + bool valid; +} StunAgentSavedIds; + +struct stun_agent_t { + StunCompatibility compatibility; + StunAgentSavedIds sent_ids[STUN_AGENT_MAX_SAVED_IDS]; + uint16_t *known_attributes; + StunAgentUsageFlags usage_flags; + const char *software_attribute; + bool ms_ice2_send_legacy_connchecks; +}; + +/** + * StunDefaultValidaterData: + * @username: The username + * @username_len: The length of the @username + * @password: The password + * @password_len: The length of the @password + * + * This structure is used as an element of the user_data to the + * stun_agent_default_validater() function for authenticating a STUN + * message during validationg. + * See also: stun_agent_default_validater() + */ +typedef struct { + uint8_t *username; + size_t username_len; + uint8_t *password; + size_t password_len; +} StunDefaultValidaterData; + + +/** + * StunMessageIntegrityValidate: + * @agent: The #StunAgent + * @message: The #StunMessage being validated + * @username: The username found in the @message + * @username_len: The length of @username + * @password: The password associated with that username. This argument is a + * pointer to a byte array that must be set by the validater function. + * @password_len: The length of @password which must also be set by the + * validater function. + * @user_data: Data to give the function + * + * This is the prototype for the @validater argument of the stun_agent_validate() + * function. + * See also: stun_agent_validate() + * Returns: %TRUE if the authentication was successful, + * %FALSE if the authentication failed + */ +typedef bool (*StunMessageIntegrityValidate) (StunAgent *agent, + StunMessage *message, uint8_t *username, uint16_t username_len, + uint8_t **password, size_t *password_len, void *user_data); + +/** + * stun_agent_default_validater: + * @agent: The #StunAgent + * @message: The #StunMessage being validated + * @username: The username found in the @message + * @username_len: The length of @username + * @password: The password associated with that username. This argument is a + * pointer to a byte array that must be set by the validater function. + * @password_len: The length of @password which must also be set by the + * validater function. + * @user_data: This must be an array of #StunDefaultValidaterData structures. + * The last element in the array must have a username set to NULL + * + * This is a helper function to be used with stun_agent_validate(). If no + * complicated processing of the username needs to be done, this function can + * be used with stun_agent_validate() to quickly and easily match the username + * of a STUN message with its password. Its @user_data argument must be an array + * of #StunDefaultValidaterData which will allow us to map a username to a + * password + * See also: stun_agent_validate() + * Returns: %TRUE if the authentication was successful, + * %FALSE if the authentication failed + */ +bool stun_agent_default_validater (StunAgent *agent, + StunMessage *message, uint8_t *username, uint16_t username_len, + uint8_t **password, size_t *password_len, void *user_data); + +/** + * stun_agent_init: + * @agent: The #StunAgent to initialize + * @known_attributes: An array of #uint16_t specifying which attributes should + * be known by the agent. Any STUN message received that contains a mandatory + * attribute that is not in this array will yield a + * #STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE or a + * #STUN_VALIDATION_UNKNOWN_ATTRIBUTE error when calling stun_agent_validate() + * @compatibility: The #StunCompatibility to use for this agent. This will affect + * how the agent builds and validates the STUN messages + * @usage_flags: A bitflag using #StunAgentUsageFlags values to define which + * STUN usages the agent should use. + * + * This function must be called to initialize an agent before it is being used. + * + + + The @known_attributes data must exist in memory as long as the @agent is used + + + If the #STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS and + #STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS usage flags are not set, then the + agent will default in using the short term credentials mechanism + + + The #STUN_AGENT_USAGE_USE_FINGERPRINT and #STUN_AGENT_USAGE_ADD_SOFTWARE + usage flags are only valid if the #STUN_COMPATIBILITY_RFC5389 or + #STUN_COMPATIBILITY_MSICE2 @compatibility is used + + + */ +void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes, + StunCompatibility compatibility, StunAgentUsageFlags usage_flags); + +/** + * stun_agent_validate: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The data buffer of the STUN message + * @buffer_len: The length of @buffer + * @validater: A #StunMessageIntegrityValidate function callback that will + * be called if the agent needs to validate a MESSAGE-INTEGRITY attribute. It + * will only be called if the agent finds a message that needs authentication + * and a USERNAME is present in the STUN message, but no password is known. + * The validater will not be called if the #STUN_AGENT_USAGE_IGNORE_CREDENTIALS + * usage flag is set on the agent, and it will always be called if the + * #STUN_AGENT_USAGE_FORCE_VALIDATER usage flag is set on the agent. + * @validater_data: A user data to give to the @validater callback when it gets + * called. + * + * This function is used to validate an inbound STUN message and transform its + * data buffer into a #StunMessage. It will take care of various validation + * algorithms to make sure that the STUN message is valid and correctly + * authenticated. + * See also: stun_agent_default_validater() + * Returns: A #StunValidationStatus + + + if the return value is different from #STUN_VALIDATION_NOT_STUN or + #STUN_VALIDATION_INCOMPLETE_STUN, then the @msg argument will contain a valid + STUN message that can be used. + This means that you can use the @msg variable as the @request argument to + functions like stun_agent_init_error() or + stun_agent_build_unknown_attributes_error(). + If the return value is #STUN_VALIDATION_BAD_REQUEST, + #STUN_VALIDATION_UNAUTHORIZED or #STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST + then the @key in the #StunMessage will not be set, so that error responses + will not have a MESSAGE-INTEGRITY attribute. + + + */ +StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, + const uint8_t *buffer, size_t buffer_len, + StunMessageIntegrityValidate validater, void * validater_data); + +/** + * stun_agent_init_request: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The buffer to use in the #StunMessage + * @buffer_len: The length of the buffer + * @m: The #StunMethod of the request + * + * Creates a new STUN message of class #STUN_REQUEST and with the method @m + * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise + */ +bool stun_agent_init_request (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, StunMethod m); + +/** + * stun_agent_init_indication: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The buffer to use in the #StunMessage + * @buffer_len: The length of the buffer + * @m: The #StunMethod of the indication + * + * Creates a new STUN message of class #STUN_INDICATION and with the method @m + * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise + */ +bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, StunMethod m); + +/** + * stun_agent_init_response: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The buffer to use in the #StunMessage + * @buffer_len: The length of the buffer + * @request: The #StunMessage of class #STUN_REQUEST that this response is for + * + * Creates a new STUN message of class #STUN_RESPONSE and with the same method + * and transaction ID as the message @request. This will also copy the pointer + * to the key that was used to authenticate the request, so you won't need to + * specify the key with stun_agent_finish_message() + * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise + */ +bool stun_agent_init_response (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, const StunMessage *request); + +/** + * stun_agent_init_error: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The buffer to use in the #StunMessage + * @buffer_len: The length of the buffer + * @request: The #StunMessage of class #STUN_REQUEST that this error response + * is for + * @err: The #StunError to put in the ERROR-CODE attribute of the error response + * + * Creates a new STUN message of class #STUN_ERROR and with the same method + * and transaction ID as the message @request. This will also copy the pointer + * to the key that was used to authenticate the request (if authenticated), + * so you won't need to specify the key with stun_agent_finish_message(). + * It will then add the ERROR-CODE attribute with code @err and the associated + * string. + * Returns: %TRUE if the message was initialized correctly, %FALSE otherwise + */ +bool stun_agent_init_error (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, const StunMessage *request, + StunError err); + +/** + * stun_agent_build_unknown_attributes_error: + * @agent: The #StunAgent + * @msg: The #StunMessage to build + * @buffer: The buffer to use in the #StunMessage + * @buffer_len: The length of the buffer + * @request: The #StunMessage of class #STUN_REQUEST that this response is for + * + * Creates a new STUN message of class #STUN_ERROR and with the same method + * and transaction ID as the message @request. It will then add the ERROR-CODE + * attribute with code #STUN_ERROR_UNKNOWN_ATTRIBUTE and add all the unknown + * mandatory attributes from the @request STUN message in the + * #STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES attribute, it will then finish the message + * by calling stun_agent_finish_message() + * Returns: The size of the message built + */ +size_t stun_agent_build_unknown_attributes_error (StunAgent *agent, + StunMessage *msg, uint8_t *buffer, size_t buffer_len, + const StunMessage *request); + + +/** + * stun_agent_finish_message: + * @agent: The #StunAgent + * @msg: The #StunMessage to finish + * @key: The key to use for the MESSAGE-INTEGRITY attribute + * @key_len: The length of the @key + * + * This function will 'finish' a message and make it ready to be sent. It will + * add the MESSAGE-INTEGRITY and FINGERPRINT attributes if necessary. If the + * STUN message has a #STUN_REQUEST class, it will save the transaction id of + * the message in the agent for future matching of the response. + * See also: stun_agent_forget_transaction() + * Returns: The final size of the message built or 0 if an error occured + * + + The return value must always be checked. a value of 0 means the either + the buffer's size is too small to contain the finishing attributes + (MESSAGE-INTEGRITY, FINGERPRINT), or that there is no more free slots + for saving the sent id in the agent's state. + + + Everytime stun_agent_finish_message() is called for a #STUN_REQUEST + message, you must make sure to call stun_agent_forget_transaction() in + case the response times out and is never received. This is to avoid + filling up the #StunAgent's sent ids state preventing any further + use of the stun_agent_finish_message() + + + */ +size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg, + const uint8_t *key, size_t key_len); + +/** + * stun_agent_forget_transaction: + * @agent: The #StunAgent + * @id: The #StunTransactionId of the transaction to forget + * + * This function is used to make the #StunAgent forget about a previously + * created transaction. + * + * This function should be called when a STUN request was previously + * created with stun_agent_finish_message() and for which no response was ever + * received (timed out). The #StunAgent keeps a list of the sent transactions + * in order to validate the responses received. If the response is never received + * this will allow the #StunAgent to forget about the timed out transaction and + * free its slot for future transactions. + * + * Since: 0.0.6 + * Returns: %TRUE if the transaction was found, %FALSE otherwise + */ +bool stun_agent_forget_transaction (StunAgent *agent, StunTransactionId id); + + +/** + * stun_agent_set_software: + * @agent: The #StunAgent + * @software: The value of the SOFTWARE attribute to add. + * + * This function will set the value of the SOFTWARE attribute to be added to + * STUN requests, responses and error responses. + * + * Calling this function will automatically enable the addition of the SOFTWARE + * attribute for RFC5389 and MSICE2 compatibility modes. + * + * + * + + The @software argument must be in UTF-8 encoding and only the first + 128 characters will be sent. + + + The value of the @software argument must stay valid throughout the life of + the StunAgent's life. Do not free its content. + + + * + * Since: 0.0.10 + * + */ +void stun_agent_set_software (StunAgent *agent, const char *software); + +#endif /* _STUN_AGENT_H */ diff --git a/linux_arm32v7/include/stun/stunmessage.h b/linux_arm32v7/include/stun/stunmessage.h new file mode 100644 index 0000000..0ac9977 --- /dev/null +++ b/linux_arm32v7/include/stun/stunmessage.h @@ -0,0 +1,1017 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2008-2009 Nokia Corporation. All rights reserved. + * Contact: Rémi Denis-Courmont + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Rémi Denis-Courmont, 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 _STUN_MESSAGE_H +#define _STUN_MESSAGE_H + + +/** + * SECTION:stunmessage + * @short_description: STUN messages parsing and formatting functions + * @include: stun/stunmessage.h + * @see_also: #StunAgent + * @stability: Stable + * + * The STUN Messages API allows you to create STUN messages easily as well as to + * parse existing messages. + * + */ + + +#ifdef _WIN32 +#include "win32_common.h" +#else +#include +#include +#endif + +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +#include "constants.h" + +typedef struct _StunMessage StunMessage; + +/** + * StunClass: + * @STUN_REQUEST: A STUN Request message + * @STUN_INDICATION: A STUN indication message + * @STUN_RESPONSE: A STUN Response message + * @STUN_ERROR: A STUN Error message + * + * This enum is used to represent the class of + * a STUN message, as defined in RFC5389 + */ + +/* Message classes */ +typedef enum +{ + STUN_REQUEST=0, + STUN_INDICATION=1, + STUN_RESPONSE=2, + STUN_ERROR=3 +} StunClass; + + +/** + * StunMethod: + * @STUN_BINDING: The Binding method as defined by the RFC5389 + * @STUN_SHARED_SECRET: The Shared-Secret method as defined by the RFC3489 + * @STUN_ALLOCATE: The Allocate method as defined by the TURN draft 12 + * @STUN_SET_ACTIVE_DST: The Set-Active-Destination method as defined by + * the TURN draft 4 + * @STUN_REFRESH: The Refresh method as defined by the TURN draft 12 + * @STUN_SEND: The Send method as defined by the TURN draft 00 + * @STUN_CONNECT: The Connect method as defined by the TURN draft 4 + * @STUN_OLD_SET_ACTIVE_DST: The older Set-Active-Destination method as + * defined by the TURN draft 0 + * @STUN_IND_SEND: The Send method used in indication messages as defined + * by the TURN draft 12 + * @STUN_IND_DATA: The Data method used in indication messages as defined + * by the TURN draft 12 + * @STUN_IND_CONNECT_STATUS: The Connect-Status method used in indication + * messages as defined by the TURN draft 4 + * @STUN_CREATEPERMISSION: The CreatePermission method as defined by + * the TURN draft 12 + * @STUN_CHANNELBIND: The ChannelBind method as defined by the TURN draft 12 + * + * This enum is used to represent the method of + * a STUN message, as defined by various RFCs + */ +/* Message methods */ +typedef enum +{ + STUN_BINDING=0x001, /* RFC5389 */ + STUN_SHARED_SECRET=0x002, /* old RFC3489 */ + STUN_ALLOCATE=0x003, /* TURN-12 */ + STUN_SET_ACTIVE_DST=0x004, /* TURN-04 */ + STUN_REFRESH=0x004, /* TURN-12 */ + STUN_SEND=0x004, /* TURN-00 */ + STUN_CONNECT=0x005, /* TURN-04 */ + STUN_OLD_SET_ACTIVE_DST=0x006, /* TURN-00 */ + STUN_IND_SEND=0x006, /* TURN-12 */ + STUN_IND_DATA=0x007, /* TURN-12 */ + STUN_IND_CONNECT_STATUS=0x008, /* TURN-04 */ + STUN_CREATEPERMISSION= 0x008, /* TURN-12 */ + STUN_CHANNELBIND= 0x009 /* TURN-12 */ +} StunMethod; + +/** + * StunAttribute: + * @STUN_ATTRIBUTE_MAPPED_ADDRESS: The MAPPED-ADDRESS attribute as defined + * by RFC5389 + * @STUN_ATTRIBUTE_RESPONSE_ADDRESS: The RESPONSE-ADDRESS attribute as defined + * by RFC3489 + * @STUN_ATTRIBUTE_CHANGE_REQUEST: The CHANGE-REQUEST attribute as defined by + * RFC3489 + * @STUN_ATTRIBUTE_SOURCE_ADDRESS: The SOURCE-ADDRESS attribute as defined by + * RFC3489 + * @STUN_ATTRIBUTE_CHANGED_ADDRESS: The CHANGED-ADDRESS attribute as defined + * by RFC3489 + * @STUN_ATTRIBUTE_USERNAME: The USERNAME attribute as defined by RFC5389 + * @STUN_ATTRIBUTE_PASSWORD: The PASSWORD attribute as defined by RFC3489 + * @STUN_ATTRIBUTE_MESSAGE_INTEGRITY: The MESSAGE-INTEGRITY attribute as defined + * by RFC5389 + * @STUN_ATTRIBUTE_ERROR_CODE: The ERROR-CODE attribute as defined by RFC5389 + * @STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES: The UNKNOWN-ATTRIBUTES attribute as + * defined by RFC5389 + * @STUN_ATTRIBUTE_REFLECTED_FROM: The REFLECTED-FROM attribute as defined + * by RFC3489 + * @STUN_ATTRIBUTE_CHANNEL_NUMBER: The CHANNEL-NUMBER attribute as defined by + * TURN draft 09 and 12 + * @STUN_ATTRIBUTE_LIFETIME: The LIFETIME attribute as defined by TURN + * draft 04, 09 and 12 + * @STUN_ATTRIBUTE_MS_ALTERNATE_SERVER: The ALTERNATE-SERVER attribute as + * defined by [MS-TURN] + * @STUN_ATTRIBUTE_MAGIC_COOKIE: The MAGIC-COOKIE attribute as defined by + * the rosenberg-midcom TURN draft 08 + * @STUN_ATTRIBUTE_BANDWIDTH: The BANDWIDTH attribute as defined by TURN draft 04 + * @STUN_ATTRIBUTE_DESTINATION_ADDRESS: The DESTINATION-ADDRESS attribute as + * defined by the rosenberg-midcom TURN draft 08 + * @STUN_ATTRIBUTE_REMOTE_ADDRESS: The REMOTE-ADDRESS attribute as defined by + * TURN draft 04 + * @STUN_ATTRIBUTE_PEER_ADDRESS: The PEER-ADDRESS attribute as defined by + * TURN draft 09 + * @STUN_ATTRIBUTE_XOR_PEER_ADDRESS: The XOR-PEER-ADDRESS attribute as defined + * by TURN draft 12 + * @STUN_ATTRIBUTE_DATA: The DATA attribute as defined by TURN draft 04, + * 09 and 12 + * @STUN_ATTRIBUTE_REALM: The REALM attribute as defined by RFC5389 + * @STUN_ATTRIBUTE_NONCE: The NONCE attribute as defined by RFC5389 + * @STUN_ATTRIBUTE_RELAY_ADDRESS: The RELAY-ADDRESS attribute as defined by + * TURN draft 04 + * @STUN_ATTRIBUTE_RELAYED_ADDRESS: The RELAYED-ADDRESS attribute as defined by + * TURN draft 09 + * @STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS: The XOR-RELAYED-ADDRESS attribute as + * defined by TURN draft 12 + * @STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE: The REQUESTED-ADDRESS-TYPE attribute + * as defined by TURN-IPV6 draft 05 + * @STUN_ATTRIBUTE_REQUESTED_PORT_PROPS: The REQUESTED-PORT-PROPS attribute + * as defined by TURN draft 04 + * @STUN_ATTRIBUTE_REQUESTED_PROPS: The REQUESTED-PROPS attribute as defined + * by TURN draft 09 + * @STUN_ATTRIBUTE_EVEN_PORT: The EVEN-PORT attribute as defined by TURN draft 12 + * @STUN_ATTRIBUTE_REQUESTED_TRANSPORT: The REQUESTED-TRANSPORT attribute as + * defined by TURN draft 12 + * @STUN_ATTRIBUTE_DONT_FRAGMENT: The DONT-FRAGMENT attribute as defined + * by TURN draft 12 + * @STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS: The XOR-MAPPED-ADDRESS attribute as + * defined by RFC5389 + * @STUN_ATTRIBUTE_TIMER_VAL: The TIMER-VAL attribute as defined by TURN draft 04 + * @STUN_ATTRIBUTE_REQUESTED_IP: The REQUESTED-IP attribute as defined by + * TURN draft 04 + * @STUN_ATTRIBUTE_RESERVATION_TOKEN: The RESERVATION-TOKEN attribute as defined + * by TURN draft 09 and 12 + * @STUN_ATTRIBUTE_CONNECT_STAT: The CONNECT-STAT attribute as defined by TURN + * draft 04 + * @STUN_ATTRIBUTE_PRIORITY: The PRIORITY attribute as defined by ICE draft 19 + * @STUN_ATTRIBUTE_USE_CANDIDATE: The USE-CANDIDATE attribute as defined by + * ICE draft 19 + * @STUN_ATTRIBUTE_OPTIONS: The OPTIONS optional attribute as defined by + * libjingle + * @STUN_ATTRIBUTE_MS_VERSION: The MS-VERSION optional attribute as defined + * by [MS-TURN] + * @STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS: The XOR-MAPPED-ADDRESS optional + * attribute as defined by [MS-TURN] + * @STUN_ATTRIBUTE_SOFTWARE: The SOFTWARE optional attribute as defined by RFC5389 + * @STUN_ATTRIBUTE_ALTERNATE_SERVER: The ALTERNATE-SERVER optional attribute as + * defined by RFC5389 + * @STUN_ATTRIBUTE_FINGERPRINT: The FINGERPRINT optional attribute as defined + * by RFC5389 + * @STUN_ATTRIBUTE_ICE_CONTROLLED: The ICE-CONTROLLED optional attribute as + * defined by ICE draft 19 + * @STUN_ATTRIBUTE_ICE_CONTROLLING: The ICE-CONTROLLING optional attribute as + * defined by ICE draft 19 + * @STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER: The MS-SEQUENCE NUMBER optional attribute + * as defined by [MS-TURN] + * @STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER: The CANDIDATE-IDENTIFIER optional + * attribute as defined by [MS-ICE2] + * @STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION: The IMPLEMENTATION-VERSION + * optional attribute as defined by [MS-ICE2] + * @STUN_ATTRIBUTE_NOMINATION: The NOMINATION attribute as defined by + * draft-thatcher-ice-renomination-00 and deployed in Google Chrome + * + * Known STUN attribute types as defined by various RFCs and drafts + */ +/* Should be in sync with stun_is_unknown() */ +typedef enum +{ + /* Mandatory attributes */ + /* 0x0000 */ /* reserved */ + STUN_ATTRIBUTE_MAPPED_ADDRESS=0x0001, /* RFC5389 */ + STUN_ATTRIBUTE_RESPONSE_ADDRESS=0x0002, /* old RFC3489 */ + STUN_ATTRIBUTE_CHANGE_REQUEST=0x0003, /* old RFC3489 */ + STUN_ATTRIBUTE_SOURCE_ADDRESS=0x0004, /* old RFC3489 */ + STUN_ATTRIBUTE_CHANGED_ADDRESS=0x0005, /* old RFC3489 */ + STUN_ATTRIBUTE_USERNAME=0x0006, /* RFC5389 */ + STUN_ATTRIBUTE_PASSWORD=0x0007, /* old RFC3489 */ + STUN_ATTRIBUTE_MESSAGE_INTEGRITY=0x0008, /* RFC5389 */ + STUN_ATTRIBUTE_ERROR_CODE=0x0009, /* RFC5389 */ + STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES=0x000A, /* RFC5389 */ + STUN_ATTRIBUTE_REFLECTED_FROM=0x000B, /* old RFC3489 */ + STUN_ATTRIBUTE_CHANNEL_NUMBER=0x000C, /* TURN-12 */ + STUN_ATTRIBUTE_LIFETIME=0x000D, /* TURN-12 */ + /* MS_ALTERNATE_SERVER is only used by Microsoft's dialect, probably should + * not to be placed in STUN_ALL_KNOWN_ATTRIBUTES */ + STUN_ATTRIBUTE_MS_ALTERNATE_SERVER=0x000E, /* MS-TURN */ + STUN_ATTRIBUTE_MAGIC_COOKIE=0x000F, /* midcom-TURN 08 */ + STUN_ATTRIBUTE_BANDWIDTH=0x0010, /* TURN-04 */ + STUN_ATTRIBUTE_DESTINATION_ADDRESS=0x0011, /* midcom-TURN 08 */ + STUN_ATTRIBUTE_REMOTE_ADDRESS=0x0012, /* TURN-04 */ + STUN_ATTRIBUTE_PEER_ADDRESS=0x0012, /* TURN-09 */ + STUN_ATTRIBUTE_XOR_PEER_ADDRESS=0x0012, /* TURN-12 */ + STUN_ATTRIBUTE_DATA=0x0013, /* TURN-12 */ + STUN_ATTRIBUTE_REALM=0x0014, /* RFC5389 */ + STUN_ATTRIBUTE_NONCE=0x0015, /* RFC5389 */ + STUN_ATTRIBUTE_RELAY_ADDRESS=0x0016, /* TURN-04 */ + STUN_ATTRIBUTE_RELAYED_ADDRESS=0x0016, /* TURN-09 */ + STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS=0x0016, /* TURN-12 */ + STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE=0x0017, /* TURN-IPv6-05 */ + STUN_ATTRIBUTE_REQUESTED_PORT_PROPS=0x0018, /* TURN-04 */ + STUN_ATTRIBUTE_REQUESTED_PROPS=0x0018, /* TURN-09 */ + STUN_ATTRIBUTE_EVEN_PORT=0x0018, /* TURN-12 */ + STUN_ATTRIBUTE_REQUESTED_TRANSPORT=0x0019, /* TURN-12 */ + STUN_ATTRIBUTE_DONT_FRAGMENT=0x001A, /* TURN-12 */ + /* 0x001B */ /* reserved */ + /* 0x001C */ /* reserved */ + /* 0x001D */ /* reserved */ + /* 0x001E */ /* reserved */ + /* 0x001F */ /* reserved */ + STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS=0x0020, /* RFC5389 */ + STUN_ATTRIBUTE_TIMER_VAL=0x0021, /* TURN-04 */ + STUN_ATTRIBUTE_REQUESTED_IP=0x0022, /* TURN-04 */ + STUN_ATTRIBUTE_RESERVATION_TOKEN=0x0022, /* TURN-09 */ + STUN_ATTRIBUTE_CONNECT_STAT=0x0023, /* TURN-04 */ + STUN_ATTRIBUTE_PRIORITY=0x0024, /* ICE-19 */ + STUN_ATTRIBUTE_USE_CANDIDATE=0x0025, /* ICE-19 */ + /* 0x0026 */ /* reserved */ + /* 0x0027 */ /* reserved */ + /* 0x0028 */ /* reserved */ + /* 0x0029 */ /* reserved */ + /* 0x002A-0x7fff */ /* reserved */ + + /* Optional attributes */ + /* 0x8000-0x8021 */ /* reserved */ + STUN_ATTRIBUTE_OPTIONS=0x8001, /* libjingle */ + STUN_ATTRIBUTE_MS_VERSION=0x8008, /* MS-TURN */ + STUN_ATTRIBUTE_MS_XOR_MAPPED_ADDRESS=0x8020, /* MS-TURN */ + STUN_ATTRIBUTE_SOFTWARE=0x8022, /* RFC5389 */ + STUN_ATTRIBUTE_ALTERNATE_SERVER=0x8023, /* RFC5389 */ + /* 0x8024 */ /* reserved */ + /* 0x8025 */ /* reserved */ + /* 0x8026 */ /* reserved */ + /* 0x8027 */ /* reserved */ + STUN_ATTRIBUTE_FINGERPRINT=0x8028, /* RFC5389 */ + STUN_ATTRIBUTE_ICE_CONTROLLED=0x8029, /* ICE-19 */ + STUN_ATTRIBUTE_ICE_CONTROLLING=0x802A, /* ICE-19 */ + /* 0x802B-0x804F */ /* reserved */ + STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER=0x8050, /* MS-TURN */ + /* 0x8051-0x8053 */ /* reserved */ + STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER=0x8054, /* MS-ICE2 */ + /* 0x8055-0x806F */ /* reserved */ + STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION=0x8070, /* MS-ICE2 */ + /* 0x8071-0xC000 */ /* reserved */ + STUN_ATTRIBUTE_NOMINATION=0xC001 /* https://tools.ietf.org/html/draft-thatcher-ice-renomination-00 */ + /* 0xC002-0xFFFF */ /* reserved */ +} StunAttribute; + + +/** + * STUN_ALL_KNOWN_ATTRIBUTES: + * + * An array containing all the currently known and defined mandatory attributes + * from StunAttribute + */ +/* Should be in sync with StunAttribute */ +static const uint16_t STUN_ALL_KNOWN_ATTRIBUTES[] = + { + STUN_ATTRIBUTE_MAPPED_ADDRESS, + STUN_ATTRIBUTE_RESPONSE_ADDRESS, + STUN_ATTRIBUTE_CHANGE_REQUEST, + STUN_ATTRIBUTE_SOURCE_ADDRESS, + STUN_ATTRIBUTE_CHANGED_ADDRESS, + STUN_ATTRIBUTE_USERNAME, + STUN_ATTRIBUTE_PASSWORD, + STUN_ATTRIBUTE_MESSAGE_INTEGRITY, + STUN_ATTRIBUTE_ERROR_CODE, + STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, + STUN_ATTRIBUTE_REFLECTED_FROM, + STUN_ATTRIBUTE_CHANNEL_NUMBER, + STUN_ATTRIBUTE_LIFETIME, + STUN_ATTRIBUTE_MAGIC_COOKIE, + STUN_ATTRIBUTE_BANDWIDTH, + STUN_ATTRIBUTE_DESTINATION_ADDRESS, + STUN_ATTRIBUTE_REMOTE_ADDRESS, + STUN_ATTRIBUTE_PEER_ADDRESS, + STUN_ATTRIBUTE_XOR_PEER_ADDRESS, + STUN_ATTRIBUTE_DATA, + STUN_ATTRIBUTE_REALM, + STUN_ATTRIBUTE_NONCE, + STUN_ATTRIBUTE_RELAY_ADDRESS, + STUN_ATTRIBUTE_RELAYED_ADDRESS, + STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS, + STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE, + STUN_ATTRIBUTE_REQUESTED_PORT_PROPS, + STUN_ATTRIBUTE_REQUESTED_PROPS, + STUN_ATTRIBUTE_EVEN_PORT, + STUN_ATTRIBUTE_REQUESTED_TRANSPORT, + STUN_ATTRIBUTE_DONT_FRAGMENT, + STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, + STUN_ATTRIBUTE_TIMER_VAL, + STUN_ATTRIBUTE_REQUESTED_IP, + STUN_ATTRIBUTE_RESERVATION_TOKEN, + STUN_ATTRIBUTE_CONNECT_STAT, + STUN_ATTRIBUTE_PRIORITY, + STUN_ATTRIBUTE_USE_CANDIDATE, + 0 + }; + +/** + * STUN_MSOC_KNOWN_ATTRIBUTES: + * + * An array containing all the currently known mandatory attributes used by + * Microsoft Office Communicator as defined in [MS-TURN] + */ +static const uint16_t STUN_MSOC_KNOWN_ATTRIBUTES[] = + { + STUN_ATTRIBUTE_MAPPED_ADDRESS, + STUN_ATTRIBUTE_USERNAME, + STUN_ATTRIBUTE_MESSAGE_INTEGRITY, + STUN_ATTRIBUTE_ERROR_CODE, + STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES, + STUN_ATTRIBUTE_LIFETIME, + STUN_ATTRIBUTE_MS_ALTERNATE_SERVER, + STUN_ATTRIBUTE_MAGIC_COOKIE, + STUN_ATTRIBUTE_BANDWIDTH, + STUN_ATTRIBUTE_DESTINATION_ADDRESS, + STUN_ATTRIBUTE_REMOTE_ADDRESS, + STUN_ATTRIBUTE_DATA, + /* REALM and NONCE have swapped hexadecimal IDs in [MS-TURN]. Libnice users + * or developers can still use these enumeration values in their original + * meanings from StunAttribute anywhere in the code, as stun_message_find() + * and stun_message_append() will choose correct ID in MSOC compatibility + * modes. */ + STUN_ATTRIBUTE_NONCE, + STUN_ATTRIBUTE_REALM, + 0 + }; + +/** + * StunTransactionId: + * + * A type that holds a STUN transaction id. + */ +typedef uint8_t StunTransactionId[STUN_MESSAGE_TRANS_ID_LEN]; + + +/** + * StunError: + * @STUN_ERROR_TRY_ALTERNATE: The ERROR-CODE value for the + * "Try Alternate" error as defined in RFC5389 + * @STUN_ERROR_BAD_REQUEST: The ERROR-CODE value for the + * "Bad Request" error as defined in RFC5389 + * @STUN_ERROR_UNAUTHORIZED: The ERROR-CODE value for the + * "Unauthorized" error as defined in RFC5389 + * @STUN_ERROR_UNKNOWN_ATTRIBUTE: The ERROR-CODE value for the + * "Unknown Attribute" error as defined in RFC5389 + * @STUN_ERROR_ALLOCATION_MISMATCH:The ERROR-CODE value for the + * "Allocation Mismatch" error as defined in TURN draft 12. + * Equivalent to the "No Binding" error defined in TURN draft 04. + * @STUN_ERROR_STALE_NONCE: The ERROR-CODE value for the + * "Stale Nonce" error as defined in RFC5389 + * @STUN_ERROR_ACT_DST_ALREADY: The ERROR-CODE value for the + * "Active Destination Already Set" error as defined in TURN draft 04. + * @STUN_ERROR_UNSUPPORTED_FAMILY: The ERROR-CODE value for the + * "Address Family not Supported" error as defined in TURN IPV6 Draft 05. + * @STUN_ERROR_WRONG_CREDENTIALS: The ERROR-CODE value for the + * "Wrong Credentials" error as defined in TURN Draft 12. + * @STUN_ERROR_UNSUPPORTED_TRANSPORT:he ERROR-CODE value for the + * "Unsupported Transport Protocol" error as defined in TURN Draft 12. + * @STUN_ERROR_INVALID_IP: The ERROR-CODE value for the + * "Invalid IP Address" error as defined in TURN draft 04. + * @STUN_ERROR_INVALID_PORT: The ERROR-CODE value for the + * "Invalid Port" error as defined in TURN draft 04. + * @STUN_ERROR_OP_TCP_ONLY: The ERROR-CODE value for the + * "Operation for TCP Only" error as defined in TURN draft 04. + * @STUN_ERROR_CONN_ALREADY: The ERROR-CODE value for the + * "Connection Already Exists" error as defined in TURN draft 04. + * @STUN_ERROR_ALLOCATION_QUOTA_REACHED: The ERROR-CODE value for the + * "Allocation Quota Reached" error as defined in TURN draft 12. + * @STUN_ERROR_ROLE_CONFLICT:The ERROR-CODE value for the + * "Role Conflict" error as defined in ICE draft 19. + * @STUN_ERROR_SERVER_ERROR: The ERROR-CODE value for the + * "Server Error" error as defined in RFC5389 + * @STUN_ERROR_SERVER_CAPACITY: The ERROR-CODE value for the + * "Insufficient Capacity" error as defined in TURN draft 04. + * @STUN_ERROR_INSUFFICIENT_CAPACITY: The ERROR-CODE value for the + * "Insufficient Capacity" error as defined in TURN draft 12. + * @STUN_ERROR_MAX: The maximum possible ERROR-CODE value as defined by RFC 5389. + * + * STUN error codes as defined by various RFCs and drafts + */ +/* Should be in sync with stun_strerror() */ +typedef enum +{ + STUN_ERROR_TRY_ALTERNATE=300, /* RFC5389 */ + STUN_ERROR_BAD_REQUEST=400, /* RFC5389 */ + STUN_ERROR_UNAUTHORIZED=401, /* RFC5389 */ + STUN_ERROR_UNKNOWN_ATTRIBUTE=420, /* RFC5389 */ + STUN_ERROR_ALLOCATION_MISMATCH=437, /* TURN-12 */ + STUN_ERROR_STALE_NONCE=438, /* RFC5389 */ + STUN_ERROR_ACT_DST_ALREADY=439, /* TURN-04 */ + STUN_ERROR_UNSUPPORTED_FAMILY=440, /* TURN-IPv6-05 */ + STUN_ERROR_WRONG_CREDENTIALS=441, /* TURN-12 */ + STUN_ERROR_UNSUPPORTED_TRANSPORT=442, /* TURN-12 */ + STUN_ERROR_INVALID_IP=443, /* TURN-04 */ + STUN_ERROR_INVALID_PORT=444, /* TURN-04 */ + STUN_ERROR_OP_TCP_ONLY=445, /* TURN-04 */ + STUN_ERROR_CONN_ALREADY=446, /* TURN-04 */ + STUN_ERROR_ALLOCATION_QUOTA_REACHED=486, /* TURN-12 */ + STUN_ERROR_ROLE_CONFLICT=487, /* ICE-19 */ + STUN_ERROR_SERVER_ERROR=500, /* RFC5389 */ + STUN_ERROR_SERVER_CAPACITY=507, /* TURN-04 */ + STUN_ERROR_INSUFFICIENT_CAPACITY=508, /* TURN-12 */ + STUN_ERROR_MAX=699 +} StunError; + + +/** + * StunMessageReturn: + * @STUN_MESSAGE_RETURN_SUCCESS: The operation was successful + * @STUN_MESSAGE_RETURN_NOT_FOUND: The attribute was not found + * @STUN_MESSAGE_RETURN_INVALID: The argument or data is invalid + * @STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE: There is not enough space in the + * message to append data to it, or not enough in an argument to fill it with + * the data requested. + * @STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS: The address in the arguments or in + * the STUN message is not supported. + * + * The return value of most stun_message_* functions. + * This enum will report on whether an operation was successful or not + * and what error occured if any. + */ +typedef enum +{ + STUN_MESSAGE_RETURN_SUCCESS, + STUN_MESSAGE_RETURN_NOT_FOUND, + STUN_MESSAGE_RETURN_INVALID, + STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE, + STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS +} StunMessageReturn; + +#include "stunagent.h" + +/** + * STUN_MAX_MESSAGE_SIZE: + * + * The Maximum size of a STUN message + */ +#define STUN_MAX_MESSAGE_SIZE 65552 + +/** + * StunMessage: + * @agent: The agent that created or validated this message + * @buffer: The buffer containing the STUN message + * @buffer_len: The length of the buffer (not the size of the message) + * @key: The short term credentials key to use for authentication validation + * or that was used to finalize this message + * @key_len: The length of the associated key + * @long_term_key: The long term credential key to use for authentication + * validation or that was used to finalize this message + * @long_term_valid: Whether or not the #long_term_key variable contains valid + * data + * + * This structure represents a STUN message + */ +struct _StunMessage { + StunAgent *agent; + uint8_t *buffer; + size_t buffer_len; + uint8_t *key; + size_t key_len; + uint8_t long_term_key[16]; + bool long_term_valid; +}; + +/** + * stun_message_init: + * @msg: The #StunMessage to initialize + * @c: STUN message class (host byte order) + * @m: STUN message method (host byte order) + * @id: 16-bytes transaction ID + * + * Initializes a STUN message buffer, with no attributes. + * Returns: %TRUE if the initialization was successful + */ +bool stun_message_init (StunMessage *msg, StunClass c, StunMethod m, + const StunTransactionId id); + +/** + * stun_message_length: + * @msg: The #StunMessage + * + * Get the length of the message (including the header) + * + * Returns: The length of the message + */ +uint16_t stun_message_length (const StunMessage *msg); + +/** + * stun_message_find: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @palen: A pointer to store the length of the attribute + * + * Finds an attribute in a STUN message and fetches its content + * + * Returns: A pointer to the start of the attribute payload if found, + * otherwise NULL. + */ +const void * stun_message_find (const StunMessage * msg, StunAttribute type, + uint16_t *palen); + + +/** + * stun_message_find_flag: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * + * Looks for a flag attribute within a valid STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not zero. + */ +StunMessageReturn stun_message_find_flag (const StunMessage *msg, + StunAttribute type); + +/** + * stun_message_find32: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @pval: A pointer where to store the value (host byte order) + * + * Extracts a 32-bits attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not + * 4 bytes. + */ +StunMessageReturn stun_message_find32 (const StunMessage *msg, + StunAttribute type, uint32_t *pval); + +/** + * stun_message_find64: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @pval: A pointer where to store the value (host byte order) + * + * Extracts a 64-bits attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute's size is not + * 8 bytes. + */ +StunMessageReturn stun_message_find64 (const StunMessage *msg, + StunAttribute type, uint64_t *pval); + +/** + * stun_message_find_string: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @buf: A pointer where to store the data + * @buflen: The length of the buffer + * + * Extracts an UTF-8 string from a valid STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute is improperly + * encoded + * %STUN_MESSAGE_RETURN_NOT_ENOUGH_SPACE is return if the buffer size is too + * small to hold the string + * + + + The string will be nul-terminated. + + + * + */ +StunMessageReturn stun_message_find_string (const StunMessage *msg, + StunAttribute type, char *buf, size_t buflen); + +/** + * stun_message_find_addr: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @addr: The #sockaddr to be filled + * @addrlen: The size of the @addr variable. Must be set to the size of the + * @addr socket address and will be set to the size of the extracted socket + * address. + * + * Extracts a network address attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is + * wrong or if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_find_addr (const StunMessage *msg, + StunAttribute type, struct sockaddr_storage *addr, socklen_t *addrlen); + +/** + * stun_message_find_xor_addr: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @addr: The #sockaddr to be filled + * @addrlen: The size of the @addr variable. Must be set to the size of the + * @addr socket address and will be set to the size of the + * extracted socket address. + * + * Extracts an obfuscated network address attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is + * wrong or if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_find_xor_addr (const StunMessage *msg, + StunAttribute type, struct sockaddr_storage *addr, socklen_t *addrlen); + +/** + * stun_message_find_xor_addr_full: + * @msg: The #StunMessage + * @type: The #StunAttribute to find + * @addr: The #sockaddr to be filled + * @addrlen: The size of the @addr variable. Must be set to the size of the + * @addr socket address and will be set to the size of the + * extracted socket address. + * @magic_cookie: The magic cookie to use to XOR the address. + * + * Extracts an obfuscated network address attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the attribute payload size is + * wrong or if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_find_xor_addr_full (const StunMessage *msg, + StunAttribute type, struct sockaddr_storage *addr, + socklen_t *addrlen, uint32_t magic_cookie); + + +/** + * stun_message_find_error: + * @msg: The #StunMessage + * @code: A pointer where to store the value + * + * Extract the error response code from a STUN message + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the value is invalid + */ +StunMessageReturn stun_message_find_error (const StunMessage *msg, int *code); + + +/** + * stun_message_append: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @length: The length of the attribute + * + * Reserves room for appending an attribute to an unfinished STUN message. + * + * Returns: A pointer to an unitialized buffer of @length bytes to + * where the attribute payload must be written, or NULL if there is not + * enough room in the STUN message buffer. + */ +void *stun_message_append (StunMessage *msg, StunAttribute type, + size_t length); + +/** + * stun_message_append_bytes: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @data: The data to append + * @len: The length of the attribute + * + * Appends a binary value to a STUN message + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append_bytes (StunMessage *msg, + StunAttribute type, const void *data, size_t len); + +/** + * stun_message_append_flag: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * + * Appends an empty flag attribute to a STUN message + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append_flag (StunMessage *msg, + StunAttribute type); + +/** + * stun_message_append32: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @value: The value to append (host byte order) + * + * Appends a 32-bits value attribute to a STUN message + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append32 (StunMessage *msg, + StunAttribute type, uint32_t value); + +/** + * stun_message_append64: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @value: The value to append (host byte order) + * + * Appends a 64-bits value attribute to a STUN message + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append64 (StunMessage *msg, + StunAttribute type, uint64_t value); + +/** + * stun_message_append_string: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @str: The string to append + * + * Adds an attribute from a nul-terminated string to a STUN message + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append_string (StunMessage *msg, + StunAttribute type, const char *str); + +/** + * stun_message_append_addr: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @addr: The #sockaddr to be append + * @addrlen: The size of the @addr variable. + * + * Append a network address attribute to a STUN message + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_append_addr (StunMessage * msg, + StunAttribute type, const struct sockaddr *addr, socklen_t addrlen); + +/** + * stun_message_append_xor_addr: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @addr: The #sockaddr to be append + * @addrlen: The size of the @addr variable. + * + * Append an obfuscated network address attribute to a STUN message + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_append_xor_addr (StunMessage * msg, + StunAttribute type, const struct sockaddr_storage *addr, socklen_t addrlen); + +/** + * stun_message_append_xor_addr_full: + * @msg: The #StunMessage + * @type: The #StunAttribute to append + * @addr: The #sockaddr to be append + * @addrlen: The size of the @addr variable. + * @magic_cookie: The magic cookie to use to XOR the address. + * + * Append an obfuscated network address attribute from a STUN message. + * + * Returns: A #StunMessageReturn value. + * %STUN_MESSAGE_RETURN_INVALID is returned if the @addrlen is too small + * %STUN_MESSAGE_RETURN_UNSUPPORTED_ADDRESS if the address family is unknown. + */ +StunMessageReturn stun_message_append_xor_addr_full (StunMessage * msg, + StunAttribute type, const struct sockaddr_storage *addr, socklen_t addrlen, + uint32_t magic_cookie); + +/** + * stun_message_append_error: + * @msg: The #StunMessage + * @code: The error code value + * + * Appends the ERROR-CODE attribute to the STUN message and fills it according + * to #code + * + * Returns: A #StunMessageReturn value. + */ +StunMessageReturn stun_message_append_error (StunMessage * msg, + StunError code); + +/** + * STUN_MESSAGE_BUFFER_INCOMPLETE: + * + * Convenience macro for stun_message_validate_buffer_length() meaning that the + * data to validate does not hold a complete STUN message + */ +#define STUN_MESSAGE_BUFFER_INCOMPLETE 0 + +/** + * STUN_MESSAGE_BUFFER_INVALID: + * + * Convenience macro for stun_message_validate_buffer_length() meaning that the + * data to validate is not a valid STUN message + */ +#define STUN_MESSAGE_BUFFER_INVALID -1 + + +/** + * stun_message_validate_buffer_length: + * @msg: The buffer to validate + * @length: The length of the buffer + * @has_padding: Set TRUE if attributes should be padded to multiple of 4 bytes + * + * This function will take a data buffer and will try to validate whether it is + * a STUN message or if it's not or if it's an incomplete STUN message and will + * provide us with the length of the STUN message. + * + * Returns: The length of the valid STUN message in the buffer. + * See also: #STUN_MESSAGE_BUFFER_INCOMPLETE + * See also: #STUN_MESSAGE_BUFFER_INVALID + */ +int stun_message_validate_buffer_length (const uint8_t *msg, size_t length, + bool has_padding); + +/** + * StunInputVector: + * @buffer: a buffer containing already-received binary data + * @size: length of @buffer, in bytes + * + * Container for a single buffer which also stores its length. This is designed + * for vectored I/O: typically an array of #StunInputVectors is passed to + * functions, providing multiple buffers which store logically contiguous + * received data. + * + * This is guaranteed to be layed out identically in memory to #GInputVector. + * + * Since: 0.1.5 + */ +typedef struct { + const uint8_t *buffer; + size_t size; +} StunInputVector; + +/** + * stun_message_validate_buffer_length_fast: + * @buffers: (array length=n_buffers) (in caller-allocated): array of contiguous + * #StunInputVectors containing already-received message data + * @n_buffers: number of entries in @buffers or if -1 , then buffers is + * terminated by a #StunInputVector with the buffer pointer being %NULL. + * @total_length: total number of valid bytes stored consecutively in @buffers + * @has_padding: %TRUE if attributes should be padded to 4-byte boundaries + * + * Quickly validate whether the message in the given @buffers is potentially a + * valid STUN message, an incomplete STUN message, or if it’s definitely not one + * at all. + * + * This is designed as a first-pass validation only, and does not check the + * message’s attributes for validity. If this function returns success, the + * buffers can be compacted and a more thorough validation can be performed + * using stun_message_validate_buffer_length(). If it fails, the buffers + * definitely do not contain a complete, valid STUN message. + * + * Returns: The length of the valid STUN message in the buffer, or zero or -1 on + * failure + * See also: #STUN_MESSAGE_BUFFER_INCOMPLETE + * See also: #STUN_MESSAGE_BUFFER_INVALID + * + * Since: 0.1.5 + */ +ssize_t stun_message_validate_buffer_length_fast (StunInputVector *buffers, + int n_buffers, size_t total_length, bool has_padding); + +/** + * stun_message_id: + * @msg: The #StunMessage + * @id: The #StunTransactionId to fill + * + * Retreive the STUN transaction id from a STUN message + */ +void stun_message_id (const StunMessage *msg, StunTransactionId id); + +/** + * stun_message_get_class: + * @msg: The #StunMessage + * + * Retreive the STUN class from a STUN message + * + * Returns: The #StunClass + */ +StunClass stun_message_get_class (const StunMessage *msg); + +/** + * stun_message_get_method: + * @msg: The #StunMessage + * + * Retreive the STUN method from a STUN message + * + * Returns: The #StunMethod + */ +StunMethod stun_message_get_method (const StunMessage *msg); + +/** + * stun_message_has_attribute: + * @msg: The #StunMessage + * @type: The #StunAttribute to look for + * + * Checks if an attribute is present within a STUN message. + * + * Returns: %TRUE if the attribute is found, %FALSE otherwise + */ +bool stun_message_has_attribute (const StunMessage *msg, StunAttribute type); + + +/* Defined in stun5389.c */ +/** + * stun_message_has_cookie: + * @msg: The #StunMessage + * + * Checks if the STUN message has a RFC5389 compatible cookie + * + * Returns: %TRUE if the cookie is present, %FALSE otherwise + */ +bool stun_message_has_cookie (const StunMessage *msg); + + +/** + * stun_optional: + * @t: An attribute type + * + * Helper function that checks whether a STUN attribute is a mandatory + * or an optional attribute + * + * Returns: %TRUE if the attribute is an optional one + */ +bool stun_optional (uint16_t t); + +/** + * stun_strerror: + * @code: host-byte order error code + * + * Transforms a STUN error-code into a human readable string + * + * Returns: A static pointer to a nul-terminated error message string. + */ +const char *stun_strerror (StunError code); + + +#endif /* _STUN_MESSAGE_H */ diff --git a/linux_arm32v7/include/stun/usages/bind.h b/linux_arm32v7/include/stun/usages/bind.h new file mode 100644 index 0000000..500f9fe --- /dev/null +++ b/linux_arm32v7/include/stun/usages/bind.h @@ -0,0 +1,165 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2007-2009 Nokia Corporation. All rights reserved. + * Contact: Rémi Denis-Courmont + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Rémi Denis-Courmont, 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 STUN_BIND_H +# define STUN_BIND_H 1 + +/** + * SECTION:bind + * @short_description: STUN Binding Usage + * @include: stun/usages/bind.h + * @stability: Stable + * + * The STUN Binding usage allows for easily creating and parsing STUN Binding + * requests and responses. It offers both an asynchronous and a synchronous API + * that uses the STUN timer usage. + */ + + +#ifdef _WIN32 +# include "../win32_common.h" +#else +# include +# include +#endif + +# include "stun/stunagent.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** + * StunUsageBindReturn: + * @STUN_USAGE_BIND_RETURN_SUCCESS: The binding usage succeeded + * @STUN_USAGE_BIND_RETURN_ERROR: There was an unknown error in the bind usage + * @STUN_USAGE_BIND_RETURN_INVALID: The message is invalid and should be ignored + * @STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER: The binding request has an + * ALTERNATE-SERVER attribute + * @STUN_USAGE_BIND_RETURN_TIMEOUT: The binding was unsuccessful because it has + * timed out. + * + * Return value of stun_usage_bind_process() and stun_usage_bind_run() which + * allows you to see what status the function call returned. + */ +typedef enum { + STUN_USAGE_BIND_RETURN_SUCCESS, + STUN_USAGE_BIND_RETURN_ERROR, + STUN_USAGE_BIND_RETURN_INVALID, + STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER, + STUN_USAGE_BIND_RETURN_TIMEOUT, +} StunUsageBindReturn; + + +/** + * stun_usage_bind_create: + * @agent: The #StunAgent to use to create the binding request + * @msg: The #StunMessage to build + * @buffer: The buffer to use for creating the #StunMessage + * @buffer_len: The size of the @buffer + * + * Create a new STUN binding request to use with a STUN server. + * Returns: The length of the built message. + */ +size_t stun_usage_bind_create (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len); + +/** + * stun_usage_bind_process: + * @msg: The #StunMessage to process + * @addr: A pointer to a #sockaddr structure to fill with the mapped address + * that the STUN server gives us + * @addrlen: The length of @add. rMust be set to the size of the @addr socket + * address and will be set to the actual length of the socket address. + * @alternate_server: A pointer to a #sockaddr structure to fill with the + * address of an alternate server to which we should send our new STUN + * binding request, in case the currently used STUN server is requesting the use + * of an alternate server. This argument will only be filled if the return value + * of the function is #STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER + * @alternate_server_len: The length of @alternate_server. Must be set to + * the size of the @alternate_server socket address and will be set to the + * actual length of the socket address. + * + * Process a STUN binding response and extracts the mapped address from the STUN + * message. Also checks for the ALTERNATE-SERVER attribute. + * Returns: A #StunUsageBindReturn value. + * Note that #STUN_USAGE_BIND_RETURN_TIMEOUT cannot be returned by this function + */ +StunUsageBindReturn stun_usage_bind_process (StunMessage *msg, + struct sockaddr *addr, socklen_t *addrlen, + struct sockaddr *alternate_server, socklen_t *alternate_server_len); + +/** + * stun_usage_bind_keepalive: + * @agent: The #StunAgent to use to build the message + * @msg: The #StunMessage to build + * @buf: The buffer to use for creating the #StunMessage + * @len: The size of the @buf + * + * Creates a STUN binding indication that can be used for a keepalive. + * Since this is an indication message, no STUN response will be generated + * and it can only be used as a keepalive message. + * Returns: The length of the message to send + */ +size_t stun_usage_bind_keepalive (StunAgent *agent, StunMessage *msg, + uint8_t *buf, size_t len); + +/** + * stun_usage_bind_run: + * @srv: A pointer to the #sockaddr structure representing the STUN server's + * address + * @srvlen: The length of @srv + * @addr: A pointer to a #sockaddr structure to fill with the mapped address + * that the STUN server gives us + * @addrlen: The length of @addr + * + * This is a convenience function that will do a synchronous Binding request to + * a server and wait for its answer. It will create the socket transports and + * use the #StunTimer usage to send the request and handle the response. + * Returns: A #StunUsageBindReturn. + * Possible return values are #STUN_USAGE_BIND_RETURN_SUCCESS, + * #STUN_USAGE_BIND_RETURN_ERROR and #STUN_USAGE_BIND_RETURN_TIMEOUT + */ +StunUsageBindReturn stun_usage_bind_run (const struct sockaddr *srv, + socklen_t srvlen, struct sockaddr_storage *addr, socklen_t *addrlen); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/linux_arm32v7/include/stun/usages/ice.h b/linux_arm32v7/include/stun/usages/ice.h new file mode 100644 index 0000000..561a0ce --- /dev/null +++ b/linux_arm32v7/include/stun/usages/ice.h @@ -0,0 +1,240 @@ + +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2007-2009 Nokia Corporation. All rights reserved. + * Contact: Rémi Denis-Courmont + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Rémi Denis-Courmont, 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 STUN_CONNCHECK_H +# define STUN_CONNCHECK_H 1 + +/** + * SECTION:ice + * @short_description: STUN ICE Usage + * @include: stun/usages/ice.h + * @stability: Stable + * + * The STUN ICE usage allows for easily creating and parsing STUN Binding + * requests and responses used for ICE connectivity checks. The API allows you + * to create a connectivity check message, parse a response or create a reply + * to an incoming connectivity check request. + */ + +# include "stun/stunagent.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** + * StunUsageIceCompatibility: + * @STUN_USAGE_ICE_COMPATIBILITY_RFC5245: The ICE compatibility with RFC 5245 + * @STUN_USAGE_ICE_COMPATIBILITY_GOOGLE: The ICE compatibility with Google's + * implementation of ICE + * @STUN_USAGE_ICE_COMPATIBILITY_MSN: The ICE compatibility with MSN's + * implementation of ICE + * @STUN_USAGE_ICE_COMPATIBILITY_MSICE2: The ICE compatibility with [MS-ICE2] + * specification + * @STUN_USAGE_ICE_COMPATIBILITY_DRAFT19: The ICE compatibility with draft 19 + * @STUN_USAGE_ICE_COMPATIBILITY_WLM2009: An alias + * for @STUN_USAGE_ICE_COMPATIBILITY_MSICE2 + * + * This enum defines which compatibility modes this ICE usage can use + * + * @STUN_USAGE_ICE_COMPATIBILITY_DRAFT19 and + * @STUN_USAGE_ICE_COMPATIBILITY_WLM2009 are deprecated and should not be used + * in newly-written code. They are kept for compatibility reasons and represent + * the same compatibilities as @STUN_USAGE_ICE_COMPATIBILITY_RFC5245 and + * @STUN_USAGE_ICE_COMPATIBILITY_MSICE2 respectively. + */ +typedef enum { + STUN_USAGE_ICE_COMPATIBILITY_RFC5245, + STUN_USAGE_ICE_COMPATIBILITY_GOOGLE, + STUN_USAGE_ICE_COMPATIBILITY_MSN, + STUN_USAGE_ICE_COMPATIBILITY_MSICE2, + STUN_USAGE_ICE_COMPATIBILITY_DRAFT19 = STUN_USAGE_ICE_COMPATIBILITY_RFC5245, + STUN_USAGE_ICE_COMPATIBILITY_WLM2009 = STUN_USAGE_ICE_COMPATIBILITY_MSICE2, +} StunUsageIceCompatibility; + + +/** + * StunUsageIceReturn: + * @STUN_USAGE_ICE_RETURN_SUCCESS: The function succeeded + * @STUN_USAGE_ICE_RETURN_ERROR: There was an unspecified error + * @STUN_USAGE_ICE_RETURN_INVALID: The message is invalid for processing + * @STUN_USAGE_ICE_RETURN_ROLE_CONFLICT: A role conflict was detected + * @STUN_USAGE_ICE_RETURN_INVALID_REQUEST: The message is an not a request + * @STUN_USAGE_ICE_RETURN_INVALID_METHOD: The method of the request is invalid + * @STUN_USAGE_ICE_RETURN_MEMORY_ERROR: The buffer size is too small to hold + * the STUN reply + * @STUN_USAGE_ICE_RETURN_INVALID_ADDRESS: The mapped address argument has + * an invalid address family + * @STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS: The response is valid but no + * MAPPED-ADDRESS or XOR-MAPPED-ADDRESS attribute was found + * + * Return value of stun_usage_ice_conncheck_process() and + * stun_usage_ice_conncheck_create_reply() which allows you to see what + * status the function call returned. + */ +typedef enum { + STUN_USAGE_ICE_RETURN_SUCCESS, + STUN_USAGE_ICE_RETURN_ERROR, + STUN_USAGE_ICE_RETURN_INVALID, + STUN_USAGE_ICE_RETURN_ROLE_CONFLICT, + STUN_USAGE_ICE_RETURN_INVALID_REQUEST, + STUN_USAGE_ICE_RETURN_INVALID_METHOD, + STUN_USAGE_ICE_RETURN_MEMORY_ERROR, + STUN_USAGE_ICE_RETURN_INVALID_ADDRESS, + STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS, +} StunUsageIceReturn; + + +/** + * stun_usage_ice_conncheck_create: + * @agent: The #StunAgent to use to build the request + * @msg: The #StunMessage to build + * @buffer: The buffer to use for creating the #StunMessage + * @buffer_len: The size of the @buffer + * @username: The username to use in the request + * @username_len: The length of @username + * @password: The key to use for building the MESSAGE-INTEGRITY + * @password_len: The length of @password + * @cand_use: Set to %TRUE to append the USE-CANDIDATE flag to the request + * @controlling: Set to %TRUE if you are the controlling agent or set to + * %FALSE if you are the controlled agent. + * @priority: The value of the PRIORITY attribute + * @tie: The value of the tie-breaker to put in the ICE-CONTROLLED or + * ICE-CONTROLLING attribute + * @candidate_identifier: The foundation value to put in the + * CANDIDATE-IDENTIFIER attribute + * @compatibility: The compatibility mode to use for building the conncheck + * request + * + * Builds an ICE connectivity check STUN message. + * If the compatibility is not #STUN_USAGE_ICE_COMPATIBILITY_RFC5245, the + * @cand_use, @controlling, @priority and @tie arguments are not used. + * If the compatibility is not #STUN_USAGE_ICE_COMPATIBILITY_MSICE2, the + * @candidate_identifier argument is not used. + * Returns: The length of the message built. + */ +size_t +stun_usage_ice_conncheck_create (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, + const uint8_t *username, const size_t username_len, + const uint8_t *password, const size_t password_len, + bool cand_use, bool controlling, uint32_t priority, + uint64_t tie, const char *candidate_identifier, + StunUsageIceCompatibility compatibility); + + +/** + * stun_usage_ice_conncheck_process: + * @msg: The #StunMessage to process + * @addr: A pointer to a #sockaddr structure to fill with the mapped address + * that the STUN connectivity check response contains + * @addrlen: The length of @addr + * @compatibility: The compatibility mode to use for processing the conncheck + * response + * + * Process an ICE connectivity check STUN message and retrieve the + * mapped address from the message + * See also stun_usage_ice_conncheck_priority() and + * stun_usage_ice_conncheck_use_candidate() + * Returns: A #StunUsageIceReturn value + */ +StunUsageIceReturn stun_usage_ice_conncheck_process (StunMessage *msg, + struct sockaddr_storage *addr, socklen_t *addrlen, + StunUsageIceCompatibility compatibility); + +/** + * stun_usage_ice_conncheck_create_reply: + * @agent: The #StunAgent to use to build the response + * @req: The original STUN request to reply to + * @msg: The #StunMessage to build + * @buf: The buffer to use for creating the #StunMessage + * @plen: A pointer containing the size of the @buffer on input. + * Will contain the length of the message built on output. + * @src: A pointer to a #sockaddr structure containing the source address from + * which the request was received. Will be used as the mapped address in the + * response + * @srclen: The length of @addr + * @control: Set to %TRUE if you are the controlling agent or set to + * %FALSE if you are the controlled agent. + * @tie: The value of the tie-breaker to put in the ICE-CONTROLLED or + * ICE-CONTROLLING attribute + * @compatibility: The compatibility mode to use for building the conncheck + * response + * + * Tries to parse a STUN connectivity check request and builds a + * response accordingly. + + + In case of error, the @msg is filled with the appropriate error response + to be sent and the value of @plen is set to the size of that message. + If @plen has a size of 0, then no error response should be sent. + + + * Returns: A #StunUsageIceReturn value + */ +StunUsageIceReturn +stun_usage_ice_conncheck_create_reply (StunAgent *agent, StunMessage *req, + StunMessage *msg, uint8_t *buf, size_t *plen, + const struct sockaddr_storage *src, socklen_t srclen, + bool *control, uint64_t tie, + StunUsageIceCompatibility compatibility); + +/** + * stun_usage_ice_conncheck_priority: + * @msg: The #StunMessage to parse + * + * Extracts the priority from a STUN message. + * Returns: host byte order priority, or 0 if not specified. + */ +uint32_t stun_usage_ice_conncheck_priority (const StunMessage *msg); + +/** + * stun_usage_ice_conncheck_use_candidate: + * @msg: The #StunMessage to parse + * + * Extracts the USE-CANDIDATE attribute flag from a STUN message. + * Returns: %TRUE if the flag is set, %FALSE if not. + */ +bool stun_usage_ice_conncheck_use_candidate (const StunMessage *msg); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/linux_arm32v7/include/stun/usages/timer.h b/linux_arm32v7/include/stun/usages/timer.h new file mode 100644 index 0000000..097e75b --- /dev/null +++ b/linux_arm32v7/include/stun/usages/timer.h @@ -0,0 +1,240 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2007-2009 Nokia Corporation. All rights reserved. + * Contact: Rémi Denis-Courmont + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Rémi Denis-Courmont, 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 STUN_TIMER_H +# define STUN_TIMER_H 1 + +/** + * SECTION:timer + * @short_description: STUN timer Usage + * @include: stun/usages/timer.h + * @stability: Stable + * + * The STUN timer usage is a set of helpful utility functions that allows you + * to easily track when a STUN message should be retransmitted or considered + * as timed out. + * + * + + Simple example on how to use the timer usage + + StunTimer timer; + unsigned remainder; + StunUsageTimerReturn ret; + + // Build the message, etc.. + ... + + // Send the message and start the timer + send(socket, request, sizeof(request)); + stun_timer_start(&timer, STUN_TIMER_DEFAULT_TIMEOUT, + STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS); + + // Loop until we get the response + for (;;) { + remainder = stun_timer_remainder(&timer); + + // Poll the socket until data is received or the timer expires + if (poll (&pollfd, 1, delay) <= 0) { + // Time out and no response was received + ret = stun_timer_refresh (&timer); + if (ret == STUN_USAGE_TIMER_RETURN_TIMEOUT) { + // Transaction timed out + break; + } else if (ret == STUN_USAGE_TIMER_RETURN_RETRANSMIT) { + // A retransmission is necessary + send(socket, request, sizeof(request)); + continue; + } else if (ret == STUN_USAGE_TIMER_RETURN_SUCCESS) { + // The refresh succeeded and nothing has to be done, continue polling + continue; + } + } else { + // We received a response, read it + recv(socket, response, sizeof(response)); + break; + } + } + + // Check if the transaction timed out or not + if (ret == STUN_USAGE_TIMER_RETURN_TIMEOUT) { + // do whatever needs to be done in that case + } else { + // Parse the response + } + + + + */ + +#ifdef _WIN32 +#include +#else +# include +# include +# include +#endif + + +/** + * StunTimer: + * + * An opaque structure representing a STUN transaction retransmission timer + */ +typedef struct stun_timer_s StunTimer; + +struct stun_timer_s { + struct timeval deadline; + unsigned delay; + unsigned retransmissions; + unsigned max_retransmissions; +}; + + +/** + * STUN_TIMER_DEFAULT_TIMEOUT: + * + * The default intial timeout to use for the timer + * RFC recommendds 500, but it's ridiculous, 50ms is known to work in most + * cases as it is also what is used by SIP style VoIP when sending A-Law and + * mu-Law audio, so 200ms should be hyper safe. With an initial timeout + * of 200ms, a default of 7 transmissions, the last timeout will be + * 16 * 200ms, and we expect to receive a response from the stun server + * before (1 + 2 + 4 + 8 + 16 + 32 + 16) * 200ms = 15200 ms after the initial + * stun request has been sent. + */ +#define STUN_TIMER_DEFAULT_TIMEOUT 200 + +/** + * STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS: + * + * The default maximum retransmissions allowed before a timer decides to timeout + */ +#define STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS 7 + +/** + * STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT: + * + * The default intial timeout to use for a reliable timer + */ +#define STUN_TIMER_DEFAULT_RELIABLE_TIMEOUT 7900 + +/** + * StunUsageTimerReturn: + * @STUN_USAGE_TIMER_RETURN_SUCCESS: The timer was refreshed successfully + * and there is nothing to be done + * @STUN_USAGE_TIMER_RETURN_RETRANSMIT: The timer expired and the message + * should be retransmitted now. + * @STUN_USAGE_TIMER_RETURN_TIMEOUT: The timer expired as well as all the + * retransmissions, the transaction timed out + * + * Return value of stun_usage_timer_refresh() which provides you with status + * information on the timer. + */ +typedef enum { + STUN_USAGE_TIMER_RETURN_SUCCESS, + STUN_USAGE_TIMER_RETURN_RETRANSMIT, + STUN_USAGE_TIMER_RETURN_TIMEOUT +} StunUsageTimerReturn; + +# ifdef __cplusplus +extern "C" { +# endif + + +/** + * stun_timer_start: + * @timer: The #StunTimer to start + * @initial_timeout: The initial timeout to use before the first retransmission + * @max_retransmissions: The maximum number of transmissions before the + * #StunTimer times out + * + * Starts a STUN transaction retransmission timer. + * This should be called as soon as you send the message for the first time on + * a UDP socket. + * The timeout before the next retransmission is set to @initial_timeout, then + * each time a packet is retransmited, that timeout will be doubled, until the + * @max_retransmissions retransmissions limit is reached. + * + * To determine the total timeout value, one can use the following equation : + + total_timeout = initial_timeout * (2^(max_retransmissions + 1) - 1); + + * + * + * See also: #STUN_TIMER_DEFAULT_TIMEOUT + * + * See also: #STUN_TIMER_DEFAULT_MAX_RETRANSMISSIONS + */ +void stun_timer_start (StunTimer *timer, unsigned int initial_timeout, + unsigned int max_retransmissions); + +/** + * stun_timer_start_reliable: + * @timer: The #StunTimer to start + * @initial_timeout: The initial timeout to use before the first retransmission + * + * Starts a STUN transaction retransmission timer for a reliable transport. + * This should be called as soon as you send the message for the first time on + * a TCP socket + */ +void stun_timer_start_reliable (StunTimer *timer, unsigned int initial_timeout); + +/** + * stun_timer_refresh: + * @timer: The #StunTimer to refresh + * + * Updates a STUN transaction retransmission timer. + * Returns: A #StunUsageTimerReturn telling you what to do next + */ +StunUsageTimerReturn stun_timer_refresh (StunTimer *timer); + +/** + * stun_timer_remainder: + * @timer: The #StunTimer to query + * + * Query the timer on the time left before the next refresh should be done + * Returns: The time remaining for the timer to expire in milliseconds + */ +unsigned stun_timer_remainder (const StunTimer *timer); + +# ifdef __cplusplus +} +# endif + +#endif /* !STUN_TIMER_H */ diff --git a/linux_arm32v7/include/stun/usages/turn.h b/linux_arm32v7/include/stun/usages/turn.h new file mode 100644 index 0000000..83fa00a --- /dev/null +++ b/linux_arm32v7/include/stun/usages/turn.h @@ -0,0 +1,301 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2007-2009 Nokia Corporation. All rights reserved. + * Contact: Rémi Denis-Courmont + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Rémi Denis-Courmont, 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 STUN_TURN_H +# define STUN_TURN_H 1 + +/** + * SECTION:turn + * @short_description: TURN Allocation Usage + * @include: stun/usages/turn.h + * @stability: Stable + * + * The STUN TURN usage allows for easily creating and parsing STUN Allocate + * requests and responses used for TURN. The API allows you to create a new + * allocation or refresh an existing one as well as to parse a response to + * an allocate or refresh request. + */ + + +#ifdef _WIN32 +# include "../win32_common.h" +#else +# include +# include +#endif + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +# include "stun/stunagent.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** + * StunUsageTurnRequestPorts: + * @STUN_USAGE_TURN_REQUEST_PORT_NORMAL: Request a normal port + * @STUN_USAGE_TURN_REQUEST_PORT_EVEN: Request an even port + * @STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE: Request an even port and + * reserve the next higher port + * + * This enum is used to specify which port configuration you want when creating + * a new Allocation + */ +typedef enum { + STUN_USAGE_TURN_REQUEST_PORT_NORMAL = 0, + STUN_USAGE_TURN_REQUEST_PORT_EVEN = 1, + STUN_USAGE_TURN_REQUEST_PORT_EVEN_AND_RESERVE = 2 +} StunUsageTurnRequestPorts; + +/** + * StunUsageTurnCompatibility: + * @STUN_USAGE_TURN_COMPATIBILITY_DRAFT9: Use the specification compatible with + * TURN Draft 09 + * @STUN_USAGE_TURN_COMPATIBILITY_GOOGLE: Use the specification compatible with + * Google Talk's relay server + * @STUN_USAGE_TURN_COMPATIBILITY_MSN: Use the specification compatible with + * MSN TURN servers + * @STUN_USAGE_TURN_COMPATIBILITY_OC2007: Use the specification compatible with + * Microsoft Office Communicator 2007 + * @STUN_USAGE_TURN_COMPATIBILITY_RFC5766: Use the specification compatible with + * RFC 5766 (the final, canonical TURN standard) + * + * Specifies which TURN specification compatibility to use + */ +typedef enum { + STUN_USAGE_TURN_COMPATIBILITY_DRAFT9, + STUN_USAGE_TURN_COMPATIBILITY_GOOGLE, + STUN_USAGE_TURN_COMPATIBILITY_MSN, + STUN_USAGE_TURN_COMPATIBILITY_OC2007, + STUN_USAGE_TURN_COMPATIBILITY_RFC5766, +} StunUsageTurnCompatibility; + +/** + * StunUsageTurnReturn: + * @STUN_USAGE_TURN_RETURN_RELAY_SUCCESS: The response was successful and a relay + * address is provided + * @STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS: The response was successful and a + * relay address as well as a mapped address are provided + * @STUN_USAGE_TURN_RETURN_ERROR: The response resulted in an error + * @STUN_USAGE_TURN_RETURN_INVALID: The response is not a valid response + * @STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER: The server requests the message + * to be sent to an alternate server + * + * Return value of stun_usage_turn_process() and + * stun_usage_turn_refresh_process() which allows you to see what status the + * function call returned. + */ +typedef enum { + STUN_USAGE_TURN_RETURN_RELAY_SUCCESS, + STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS, + STUN_USAGE_TURN_RETURN_ERROR, + STUN_USAGE_TURN_RETURN_INVALID, + STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER, +} StunUsageTurnReturn; + + +/** + * stun_usage_turn_create: + * @agent: The #StunAgent to use to build the request + * @msg: The #StunMessage to build + * @buffer: The buffer to use for creating the #StunMessage + * @buffer_len: The size of the @buffer + * @previous_response: If this is the first request you are sending, set this + * argument to NULL, if it's a subsequent request you are building, then set this + * argument to the response you have received. This argument is used for building + * long term credentials (using the REALM and NONCE attributes) as well as for + * getting the RESERVATION-TOKEN attribute when you previously requested an + * allocation which reserved two ports + * @request_ports: Specify how you want to request the allocated port(s). + * This is only used if the compatibility is set to + * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 + * See #StunUsageTurnRequestPorts + * @bandwidth: The bandwidth to request from the server for the allocation. If + * this value is negative, then no BANDWIDTH attribute is added to the request. + * This is only used if the compatibility is set to + * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 + * @lifetime: The lifetime of the allocation to request from the server. If + * this value is negative, then no LIFETIME attribute is added to the request. + * This is only used if the compatibility is set to + * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 + * @username: The username to use in the request + * @username_len: The length of @username + * @password: The key to use for building the MESSAGE-INTEGRITY + * @password_len: The length of @password + * @compatibility: The compatibility mode to use for building the Allocation + * request + * + * Create a new TURN Allocation request + * Returns: The length of the message to send + */ +size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, + StunMessage *previous_response, + StunUsageTurnRequestPorts request_ports, + int32_t bandwidth, int32_t lifetime, + uint8_t *username, size_t username_len, + uint8_t *password, size_t password_len, + StunUsageTurnCompatibility compatibility); + +/** + * stun_usage_turn_create_refresh: + * @agent: The #StunAgent to use to build the request + * @msg: The #StunMessage to build + * @buffer: The buffer to use for creating the #StunMessage + * @buffer_len: The size of the @buffer + * @previous_response: If this is the first request you are sending, set this + * argument to NULL, if it's a subsequent request you are building, then set this + * argument to the response you have received. This argument is used for building + * long term credentials (using the REALM and NONCE attributes) + * @lifetime: The lifetime of the allocation to request from the server. If + * this value is negative, then no LIFETIME attribute is added to the request. + * This is only used if the compatibility is set to + * #STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 + * @username: The username to use in the request + * @username_len: The length of @username + * @password: The key to use for building the MESSAGE-INTEGRITY + * @password_len: The length of @password + * @compatibility: The compatibility mode to use for building the Allocation + * request + * + * Create a new TURN Refresh request + * Returns: The length of the message to send + */ +size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, + StunMessage *previous_response, int32_t lifetime, + uint8_t *username, size_t username_len, + uint8_t *password, size_t password_len, + StunUsageTurnCompatibility compatibility); + +/** + * stun_usage_turn_create_permission: + * @agent: The #StunAgent to use to build the request + * @msg: The #StunMessage to build + * @buffer: The buffer to use for creating the #StunMessage + * @buffer_len: The size of the @buffer + * @username: The username to use in the request + * @username_len: The length of @username + * @password: The key to use for building the MESSAGE-INTEGRITY + * @password_len: The length of @password + * @realm: The realm identifier to use in the request + * @realm_len: The length of @realm + * @nonce: Unique and securely random nonce to use in the request + * @nonce_len: The length of @nonce + * @peer: Server-reflexive host address to request permission for + * @compatibility: The compatibility mode to use for building the + * CreatePermission request + * + * Create a new TURN CreatePermission request + * + * Returns: The length of the message to send + */ +size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg, + uint8_t *buffer, size_t buffer_len, + uint8_t *username, size_t username_len, + uint8_t *password, size_t password_len, + uint8_t *realm, size_t realm_len, + uint8_t *nonce, size_t nonce_len, + struct sockaddr_storage *peer, + StunUsageTurnCompatibility compatibility); + +/** + * stun_usage_turn_process: + * @msg: The message containing the response + * @relay_addr: A pointer to a #sockaddr structure to fill with the relay address + * that the TURN server allocated for us + * @relay_addrlen: The length of @relay_addr + * @addr: A pointer to a #sockaddr structure to fill with the mapped address + * that the STUN response contains. + * This argument will only be filled if the return value + * of the function is #STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS + * @addrlen: The length of @addr + * @alternate_server: A pointer to a #sockaddr structure to fill with the + * address of an alternate server to which we should send our new STUN + * Allocate request, in case the currently used TURN server is requesting the use + * of an alternate server. This argument will only be filled if the return value + * of the function is #STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER + * In the case of @STUN_USAGE_TURN_COMPATIBILITY_OC2007 compatibility, the + * @alternate_server could be filled at any time, and should only be considered + * if the request was sent to a different server than the address returned + * in the @alternate_server field + * @alternate_server_len: The length of @alternate_server + * @bandwidth: A pointer to fill with the bandwidth the TURN server allocated us + * @lifetime: A pointer to fill with the lifetime of the allocation + * @compatibility: The compatibility mode to use for processing the Allocation + * response + * + * Process a TURN Allocate response and extract the necessary information from + * the message + * Returns: A #StunUsageTurnReturn value + */ +StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, + struct sockaddr_storage *relay_addr, socklen_t *relay_addrlen, + struct sockaddr_storage *addr, socklen_t *addrlen, + struct sockaddr_storage *alternate_server, socklen_t *alternate_server_len, + uint32_t *bandwidth, uint32_t *lifetime, + StunUsageTurnCompatibility compatibility); + +/** + * stun_usage_turn_refresh_process: + * @msg: The message containing the response + * @lifetime: A pointer to fill with the lifetime of the allocation + * @compatibility: The compatibility mode to use for processing the Refresh + * response + * + * Process a TURN Refresh response and extract the necessary information from + * the message + * Returns: A #StunUsageTurnReturn value. A #STUN_USAGE_TURN_RETURN_RELAY_SUCCESS + * means the Refresh was successful, but no relay address is given (kept the same + * as for the original allocation) + */ +StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg, + uint32_t *lifetime, StunUsageTurnCompatibility compatibility); + + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/linux_arm32v7/include/stun/win32_common.h b/linux_arm32v7/include/stun/win32_common.h new file mode 100644 index 0000000..ec833c3 --- /dev/null +++ b/linux_arm32v7/include/stun/win32_common.h @@ -0,0 +1,74 @@ +/* + * This file is part of the Nice GLib ICE library. + * + * (C) 2008-2009 Collabora Ltd. + * Contact: Youness Alaoui + * (C) 2008-2009 Nokia Corporation. All rights reserved. + * + * 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: + * Youness Alaoui, Collabora Ltd. + * Danny Smith + * + * 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. + */ + +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _WIN32_COMMON_H +#define _WIN32_COMMON_H + +#include +#include +#include + +/* On MSVC, ssize_t is SSIZE_T */ +#ifdef _MSC_VER +#include +#define ssize_t SSIZE_T +#endif + +/* Windows v10.0.16232 SDK defines MSG_ERRQUEUE, but doesn't support it with + * recvmsg, and also uses a different msghdr struct */ +#undef MSG_ERRQUEUE + +#endif /* _WIN32_COMMON_H */ diff --git a/linux_arm32v7/lib/libnice.la b/linux_arm32v7/lib/libnice.la new file mode 100755 index 0000000..12b147f --- /dev/null +++ b/linux_arm32v7/lib/libnice.la @@ -0,0 +1,41 @@ +# libnice.la - a libtool library file +# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='libnice.so.10' + +# Names of this library. +library_names='libnice.so.10.9.0 libnice.so.10 libnice.so' + +# The name of the static archive. +old_library='' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags=' -pthread' + +# Libraries that this one depends upon. +dependency_libs=' -L/root/nice/libnice/../boringssl//crypto/ -L/root/nice/libnice/../boringssl//ssl/ -L/root/nice/glibc-prebuild/linux_arm32v7/lib/arm-linux-gnueabihf -lrt -lssl -lcrypto -lgio-2.0 -lz -lresolv -lgmodule-2.0 -ldl -lgobject-2.0 -lffi -lglib-2.0 -lpcre' + +# Names of additional weak libraries provided by this library +weak_library_names='' + +# Version information for libnice. +current=19 +age=9 +revision=0 + +# Is this an already installed library? +installed=yes + +# Should we warn about portability when linking against -modules? +shouldnotlink=no + +# Files to dlopen/dlpreopen +dlopen='' +dlpreopen='' + +# Directory that this library needs to be installed in: +libdir='/root/nice/libnice/out/lib' diff --git a/linux_arm32v7/lib/libnice.so b/linux_arm32v7/lib/libnice.so new file mode 120000 index 0000000..ab8669e --- /dev/null +++ b/linux_arm32v7/lib/libnice.so @@ -0,0 +1 @@ +libnice.so.10.9.0 \ No newline at end of file diff --git a/linux_arm32v7/lib/libnice.so.10 b/linux_arm32v7/lib/libnice.so.10 new file mode 120000 index 0000000..ab8669e --- /dev/null +++ b/linux_arm32v7/lib/libnice.so.10 @@ -0,0 +1 @@ +libnice.so.10.9.0 \ No newline at end of file diff --git a/linux_arm32v7/lib/libnice.so.10.9.0 b/linux_arm32v7/lib/libnice.so.10.9.0 new file mode 100755 index 0000000000000000000000000000000000000000..88b738dbe4bd86694eed6996d9b07a0640f162d6 GIT binary patch literal 337392 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%0A&O~F1D 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 2.54 gio-2.0 >= 2.54 gobject-2.0 >= 2.54 +Requires.private: gthread-2.0 libcrypto +Libs: -L${libdir} -lnice +Cflags: -I${includedir}/nice -I${includedir}