diff options
-rw-r--r-- | agent/agent-priv.h | 2 | ||||
-rw-r--r-- | agent/agent.c | 20 | ||||
-rw-r--r-- | agent/component.c | 90 | ||||
-rw-r--r-- | agent/component.h | 10 | ||||
-rw-r--r-- | agent/conncheck.c | 8 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/test-mainloop.c | 108 |
7 files changed, 127 insertions, 112 deletions
diff --git a/agent/agent-priv.h b/agent/agent-priv.h index 4d8c9b8..ada3630 100644 --- a/agent/agent-priv.h +++ b/agent/agent-priv.h @@ -114,6 +114,8 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a, * MTU and estimated typical sizes of ICE STUN packet */ #define MAX_STUN_DATAGRAM_PAYLOAD 1300 +#define NICE_COMPONENT_MAX_VALID_CANDIDATES 50 /* maximum number of validates remote candidates to keep, the number is arbitrary but hopefully large enough */ + struct _NiceAgent { GObject parent; /* gobject pointer */ diff --git a/agent/agent.c b/agent/agent.c index 77f27e3..eff62f0 100644 --- a/agent/agent.c +++ b/agent/agent.c @@ -3682,8 +3682,6 @@ agent_recv_message_unlocked ( if (retval == RECV_OOB) goto done; - agent->media_after_tick = TRUE; - /* If the message’s stated length is equal to its actual length, it’s probably * a STUN message; otherwise it’s probably data. */ if (stun_message_validate_buffer_length_fast ( @@ -3715,6 +3713,7 @@ agent_recv_message_unlocked ( nice_debug ("%s: Valid STUN packet received.", G_STRFUNC); retval = RECV_OOB; g_free (big_buf); + agent->media_after_tick = TRUE; goto done; } } @@ -3725,6 +3724,23 @@ agent_recv_message_unlocked ( g_free (big_buf); } + if (!nice_component_verify_remote_candidate (component, + message->from, nicesock)) { + if (nice_debug_is_verbose ()) { + gchar str[INET6_ADDRSTRLEN]; + + nice_address_to_string (message->from, str); + nice_debug_verbose ("Agent %p : %d:%d DROPPING packet from unknown source" + " %s:%d sock-type: %d\n", agent, stream->id, component->id, str, + nice_address_get_port (message->from), nicesock->type); + } + + retval = RECV_OOB; + goto done; + } + + agent->media_after_tick = TRUE; + /* Unhandled STUN; try handling TCP data, then pass to the client. */ if (message->length > 0 && agent->reliable) { if (!nice_socket_is_reliable (nicesock) && diff --git a/agent/component.c b/agent/component.c index a679b30..ba28ffa 100644 --- a/agent/component.c +++ b/agent/component.c @@ -435,6 +435,8 @@ nice_component_update_selected_pair (NiceComponent *component, const CandidatePa component->selected_pair.remote = pair->remote; component->selected_pair.priority = pair->priority; component->selected_pair.prflx_priority = pair->prflx_priority; + + nice_component_add_valid_candidate (component, pair->remote); } /* @@ -514,6 +516,11 @@ nice_component_set_selected_remote_candidate (NiceComponent *component, component->selected_pair.remote = remote; component->selected_pair.priority = priority; + /* Get into fallback mode where packets from any source is accepted once + * this has been called. This is the expected behavior of pre-ICE SIP. + */ + component->fallback_mode = TRUE; + return local; } @@ -1107,6 +1114,9 @@ nice_component_finalize (GObject *obj) g_warn_if_fail (cmp->remote_candidates == NULL); g_warn_if_fail (cmp->incoming_checks == NULL); + g_list_free_full (cmp->valid_candidates, + (GDestroyNotify) nice_candidate_free); + g_clear_object (&cmp->tcp); g_clear_object (&cmp->stop_cancellable); g_clear_object (&cmp->iostream); @@ -1421,3 +1431,83 @@ turn_server_unref (TurnServer *turn) g_slice_free (TurnServer, turn); } } + +void +nice_component_add_valid_candidate (NiceComponent *component, + const NiceCandidate *candidate) +{ + guint count = 0; + GList *item, *last = NULL; + + for (item = component->valid_candidates; item; item = item->next) { + NiceCandidate *cand = item->data; + + last = item; + count++; + if (nice_candidate_equal_target (cand, candidate)) + return; + } + + /* New candidate */ + + if (nice_debug_is_enabled ()) { + char str[INET6_ADDRSTRLEN]; + nice_address_to_string (&candidate->addr, str); + nice_debug ("Agent %p : %d:%d Adding valid source" + " candidate: %s:%d trans: %d\n", component->agent, + candidate->stream_id, candidate->component_id, str, + nice_address_get_port (&candidate->addr), candidate->transport); + } + + component->valid_candidates = g_list_prepend ( + component->valid_candidates, nice_candidate_copy (candidate)); + + /* Delete the last one to make sure we don't have a list that is too long, + * the candidates are not freed on ICE restart as this would be more complex, + * we just keep the list not too long. + */ + if (count > NICE_COMPONENT_MAX_VALID_CANDIDATES) { + NiceCandidate *cand = last->data; + + component->valid_candidates = g_list_delete_link ( + component->valid_candidates, last); + nice_candidate_free (cand); + } +} + +gboolean +nice_component_verify_remote_candidate (NiceComponent *component, + const NiceAddress *address, NiceSocket *nicesock) +{ + GList *item; + + if (component->fallback_mode) + return TRUE; + + for (item = component->valid_candidates; item; item = item->next) { + NiceCandidate *cand = item->data; + + if (((nicesock->type == NICE_SOCKET_TYPE_TCP_BSD && + (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE || + cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE || + cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_SO)) || + cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) && + nice_address_equal (address, &cand->addr)) { + /* fast return if it's already the first */ + if (item == component->valid_candidates) + return TRUE; + + /* Put the current candidate at the top so that in the normal use-case, + * this function becomes O(1). + */ + component->valid_candidates = g_list_remove_link ( + component->valid_candidates, item); + component->valid_candidates = g_list_concat (item, + component->valid_candidates); + + return TRUE; + } + } + + return FALSE; +} diff --git a/agent/component.h b/agent/component.h index 6712794..a8a1222 100644 --- a/agent/component.h +++ b/agent/component.h @@ -159,12 +159,14 @@ struct _NiceComponent { NiceComponentState state; GSList *local_candidates; /* list of NiceCandidate objs */ GSList *remote_candidates; /* list of NiceCandidate objs */ + GList *valid_candidates; /* list of owned remote NiceCandidates that are part of valid pairs */ GSList *socket_sources; /* list of SocketSource objs; must only grow monotonically */ guint socket_sources_age; /* incremented when socket_sources changes */ GSList *incoming_checks; /* list of IncomingCheck objs */ GList *turn_servers; /* List of TurnServer objs */ CandidatePair selected_pair; /* independent from checklists, see ICE 11.1. "Sending Media" (ID-19) */ + gboolean fallback_mode; /* in this case, accepts packets from all, ignore candidate validation */ NiceCandidate *restart_candidate; /* for storing active remote candidate during a restart */ NiceCandidate *turn_candidate; /* for storing active turn candidate if turn servers have been cleared */ /* I/O handling. The main context must always be non-NULL, and is used for all @@ -301,6 +303,14 @@ turn_server_ref (TurnServer *turn); void turn_server_unref (TurnServer *turn); +void +nice_component_add_valid_candidate (NiceComponent *component, + const NiceCandidate *candidate); + +gboolean +nice_component_verify_remote_candidate (NiceComponent *component, + const NiceAddress *address, NiceSocket *nicesock); + G_END_DECLS diff --git a/agent/conncheck.c b/agent/conncheck.c index 1dc13dd..7ffa3db 100644 --- a/agent/conncheck.c +++ b/agent/conncheck.c @@ -2627,6 +2627,7 @@ static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent * p->state = NICE_CHECK_SUCCEEDED; nice_debug ("Agent %p : conncheck %p SUCCEEDED.", agent, p); priv_conn_check_unfreeze_related (agent, stream, p); + nice_component_add_valid_candidate (component, remote_candidate); } else { if (!local_cand) { @@ -2652,8 +2653,10 @@ static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent * /* note: this is same as "adding to VALID LIST" in the spec text */ - if (new_pair) + if (new_pair) { new_pair->valid = TRUE; + nice_component_add_valid_candidate (component, remote_candidate); + } return new_pair; } @@ -2739,6 +2742,7 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStre nice_debug ("Agent %p : Mapped address not found." " conncheck %p SUCCEEDED.", agent, p); priv_conn_check_unfreeze_related (agent, stream, p); + nice_component_add_valid_candidate (component, p->remote); } else { ok_pair = priv_process_response_check_for_reflexive (agent, stream, component, p, sockptr, &sockaddr.addr, @@ -3654,6 +3658,8 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream, } } + nice_component_add_valid_candidate (component, remote_candidate); + priv_reply_to_conn_check (agent, stream, component, local_candidate, remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate); diff --git a/tests/Makefile.am b/tests/Makefile.am index 7bfe075..d24a2aa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -45,7 +45,6 @@ check_PROGRAMS = \ test-send-recv \ test-socket-is-based-on \ test-priority \ - test-mainloop \ test-fullmode \ test-restart \ test-fallback \ diff --git a/tests/test-mainloop.c b/tests/test-mainloop.c deleted file mode 100644 index 7c52daa..0000000 --- a/tests/test-mainloop.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the Nice GLib ICE library. - * - * (C) 2006, 2007 Collabora Ltd. - * Contact: Dafydd Harries - * (C) 2006, 2007 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. - * 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. - */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <string.h> - -#include <nice/nice.h> -#include "socket/socket.h" - -static GMainLoop *loop = NULL; - -static void -recv_cb ( - NiceAgent *agent, - guint stream_id, - guint component_id, - guint len, - gchar *buf, - gpointer data) -{ - g_assert (agent != NULL); - g_assert (stream_id == 1); - g_assert (component_id == 1); - g_assert (len == 6); - g_assert (0 == strncmp (buf, "\x80hello", len)); - g_assert (42 == GPOINTER_TO_UINT (data)); - g_main_loop_quit (loop); -} - -int -main (void) -{ - NiceAgent *agent; - NiceAddress addr; - guint stream; - - nice_address_init (&addr); - - loop = g_main_loop_new (NULL, FALSE); - - agent = nice_agent_new (g_main_loop_get_context (loop), NICE_COMPATIBILITY_RFC5245); - nice_address_set_ipv4 (&addr, 0x7f000001); - nice_agent_add_local_address (agent, &addr); - stream = nice_agent_add_stream (agent, 1); - nice_agent_gather_candidates (agent, stream); - - // attach to default main context - nice_agent_attach_recv (agent, stream, NICE_COMPONENT_TYPE_RTP, - g_main_loop_get_context (loop), recv_cb, GUINT_TO_POINTER (42)); - - { - NiceCandidate *candidate; - GSList *candidates, *i; - - candidates = nice_agent_get_local_candidates (agent, 1, 1); - candidate = candidates->data; - - nice_socket_send (candidate->sockptr, &(candidate->addr), 6, "\x80hello"); - for (i = candidates; i; i = i->next) - nice_candidate_free ((NiceCandidate *) i->data); - g_slist_free (candidates); - } - - g_main_loop_run (loop); - - nice_agent_remove_stream (agent, stream); - g_object_unref (agent); - - return 0; -} - |