Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
libnice
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
libnice
Commits
bd3bb038
Commit
bd3bb038
authored
Feb 01, 2013
by
Youness Alaoui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a simple example to showcase the API thanks to Bryce Allen
parent
05b9f0af
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
447 additions
and
1 deletion
+447
-1
Makefile.am
Makefile.am
+2
-1
configure.ac
configure.ac
+1
-0
examples/Makefile.am
examples/Makefile.am
+26
-0
examples/simple-example.c
examples/simple-example.c
+418
-0
No files found.
Makefile.am
View file @
bd3bb038
...
@@ -16,7 +16,8 @@ SUBDIRS = \
...
@@ -16,7 +16,8 @@ SUBDIRS = \
nice
\
nice
\
gst
\
gst
\
docs
\
docs
\
tests
tests
\
examples
DISTCHECK_CONFIGURE_FLAGS
=
--disable-assert
-enable-gtk-doc
DISTCHECK_CONFIGURE_FLAGS
=
--disable-assert
-enable-gtk-doc
...
...
configure.ac
View file @
bd3bb038
...
@@ -27,6 +27,7 @@ AC_CONFIG_FILES([
...
@@ -27,6 +27,7 @@ AC_CONFIG_FILES([
docs/reference/Makefile
docs/reference/Makefile
docs/reference/libnice/Makefile
docs/reference/libnice/Makefile
tests/Makefile
tests/Makefile
examples/Makefile
])
])
# Set the libtool C/A/R version info
# Set the libtool C/A/R version info
...
...
examples/Makefile.am
0 → 100644
View file @
bd3bb038
#
# Makefile.am for the Nice Glib ICE library
#
# (C) 2006, 2007 Collabora Ltd.
# (C) 2006, 2007 Nokia Corporation. All rights reserved.
#
# Licensed under MPL 1.1/LGPL 2.1. See file COPYING.
include
$(top_srcdir)/common.mk
AM_CFLAGS
=
\
-I
$(top_srcdir)
\
-I
$(top_srcdir)
/agent
\
-I
$(top_srcdir)
/random
\
-I
$(top_srcdir)
/socket
\
-I
$(top_srcdir)
/stun
\
$(ERROR_CFLAGS)
\
$(GLIB_CFLAGS)
\
$(GUPNP_CFLAGS)
bin_PROGRAMS
=
simple-example
simple_example_SOURCES
=
simple-example.c
simple_example_LDADD
=
$(top_builddir)
/agent/libagent.la
\
$(top_builddir)
/socket/libsocket.la
\
$(GLIB_LIBS)
$(GUPNP_LIBS)
examples/simple-example.c
0 → 100644
View file @
bd3bb038
/*
* Copyright 2013 University of Chicago
* Contact: Bryce Allen
* Copyright 2013 Collabora Ltd.
* Contact: Youness Alaoui
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Example using libnice to negotiate a UDP connection between two clients,
* possibly on the same network or behind different NATs and/or stateful
* firewalls.
*
* Build:
* gcc -o nicetest nicetest.c `pkg-config --cflags --libs nice`
*
* Run two clients, one controlling and one controlled:
* nicetest 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
* nicetest 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <agent.h>
static
GMainLoop
*
gloop
;
static
GIOChannel
*
io_stdin
;
static
guint
stream_id
;
static
const
gchar
*
candidate_type_name
[]
=
{
"host"
,
"srflx"
,
"prflx"
,
"relay"
};
static
const
gchar
*
state_name
[]
=
{
"disconnected"
,
"gathering"
,
"connecting"
,
"connected"
,
"ready"
,
"failed"
};
static
int
print_local_data
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
);
static
int
parse_remote_data
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
char
*
line
);
static
void
cb_candidate_gathering_done
(
NiceAgent
*
agent
,
guint
stream_id
,
gpointer
data
);
static
void
cb_new_selected_pair
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
gchar
*
lfoundation
,
gchar
*
rfoundation
,
gpointer
data
);
static
void
cb_component_state_changed
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
guint
state
,
gpointer
data
);
static
void
cb_nice_recv
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
guint
len
,
gchar
*
buf
,
gpointer
data
);
static
gboolean
stdin_remote_info_cb
(
GIOChannel
*
source
,
GIOCondition
cond
,
gpointer
data
);
static
gboolean
stdin_send_data_cb
(
GIOChannel
*
source
,
GIOCondition
cond
,
gpointer
data
);
int
main
(
int
argc
,
char
*
argv
[])
{
NiceAgent
*
agent
;
gchar
*
stun_addr
=
NULL
;
guint
stun_port
;
gboolean
controlling
;
// Parse arguments
if
(
argc
>
4
||
argc
<
2
||
argv
[
1
][
1
]
!=
'\0'
)
{
fprintf
(
stderr
,
"Usage: %s 0|1 stun_addr [stun_port]
\n
"
,
argv
[
0
]);
return
EXIT_FAILURE
;
}
controlling
=
argv
[
1
][
0
]
-
'0'
;
if
(
controlling
!=
0
&&
controlling
!=
1
)
{
fprintf
(
stderr
,
"Usage: %s 0|1 stun_addr [stun_port]
\n
"
,
argv
[
0
]);
return
EXIT_FAILURE
;
}
if
(
argc
>
2
)
{
stun_addr
=
argv
[
2
];
if
(
argc
>
3
)
stun_port
=
atoi
(
argv
[
3
]);
else
stun_port
=
3478
;
g_debug
(
"Using stun server '[%s]:%u'
\n
"
,
stun_addr
,
stun_port
);
}
g_type_init
();
gloop
=
g_main_loop_new
(
NULL
,
FALSE
);
io_stdin
=
g_io_channel_unix_new
(
fileno
(
stdin
));
// Create the nice agent
agent
=
nice_agent_new
(
g_main_loop_get_context
(
gloop
),
NICE_COMPATIBILITY_RFC5245
);
if
(
agent
==
NULL
)
g_error
(
"Failed to create agent"
);
// Set the STUN settings and controlling mode
if
(
stun_addr
)
{
g_object_set
(
G_OBJECT
(
agent
),
"stun-server"
,
stun_addr
,
NULL
);
g_object_set
(
G_OBJECT
(
agent
),
"stun-server-port"
,
stun_port
,
NULL
);
}
g_object_set
(
G_OBJECT
(
agent
),
"controlling-mode"
,
controlling
,
NULL
);
// Connect to the signals
g_signal_connect
(
G_OBJECT
(
agent
),
"candidate-gathering-done"
,
G_CALLBACK
(
cb_candidate_gathering_done
),
NULL
);
g_signal_connect
(
G_OBJECT
(
agent
),
"new-selected-pair"
,
G_CALLBACK
(
cb_new_selected_pair
),
NULL
);
g_signal_connect
(
G_OBJECT
(
agent
),
"component-state-changed"
,
G_CALLBACK
(
cb_component_state_changed
),
NULL
);
// Create a new stream with one component
stream_id
=
nice_agent_add_stream
(
agent
,
1
);
if
(
stream_id
==
0
)
g_error
(
"Failed to add stream"
);
// Attach to the component to receive the data
// Without this call, candidates cannot be gathered
nice_agent_attach_recv
(
agent
,
stream_id
,
1
,
g_main_loop_get_context
(
gloop
),
cb_nice_recv
,
NULL
);
// Start gathering local candidates
if
(
!
nice_agent_gather_candidates
(
agent
,
stream_id
))
g_error
(
"Failed to start candidate gathering"
);
g_debug
(
"waiting for candidate-gathering-done signal..."
);
// Run the mainloop. Everything else will happen asynchronously
// when the candidates are done gathering.
g_main_loop_run
(
gloop
);
g_main_loop_unref
(
gloop
);
g_object_unref
(
agent
);
g_io_channel_unref
(
io_stdin
);
return
EXIT_SUCCESS
;
}
static
void
cb_candidate_gathering_done
(
NiceAgent
*
agent
,
guint
stream_id
,
gpointer
data
)
{
g_debug
(
"SIGNAL candidate gathering done
\n
"
);
// Candidate gathering is done. Send our local candidates on stdout
printf
(
"Copy this line to remote client:
\n
"
);
printf
(
"
\n
"
);
print_local_data
(
agent
,
stream_id
,
1
);
printf
(
"
\n
"
);
// Listen on stdin for the remote candidate list
printf
(
"Enter remote data (single line, no wrapping):
\n
"
);
g_io_add_watch
(
io_stdin
,
G_IO_IN
,
stdin_remote_info_cb
,
agent
);
printf
(
"> "
);
fflush
(
stdout
);
}
static
gboolean
stdin_remote_info_cb
(
GIOChannel
*
source
,
GIOCondition
cond
,
gpointer
data
)
{
NiceAgent
*
agent
=
data
;
gchar
*
line
=
NULL
;
int
rval
;
gboolean
ret
=
TRUE
;
if
(
g_io_channel_read_line
(
source
,
&
line
,
NULL
,
NULL
,
NULL
)
==
G_IO_STATUS_NORMAL
)
{
// Parse remote candidate list and set it on the agent
rval
=
parse_remote_data
(
agent
,
stream_id
,
1
,
line
);
if
(
rval
==
EXIT_SUCCESS
)
{
// Return FALSE so we stop listening to stdin since we parsed the
// candidates correctly
ret
=
FALSE
;
g_debug
(
"waiting for state READY or FAILED signal..."
);
}
else
{
fprintf
(
stderr
,
"ERROR: failed to parse remote data
\n
"
);
printf
(
"Enter remote data (single line, no wrapping):
\n
"
);
printf
(
"> "
);
fflush
(
stdout
);
}
g_free
(
line
);
}
return
ret
;
}
static
void
cb_component_state_changed
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
guint
state
,
gpointer
data
)
{
g_debug
(
"SIGNAL: state changed %d %d %s[%d]
\n
"
,
stream_id
,
component_id
,
state_name
[
state
],
state
);
if
(
state
==
NICE_COMPONENT_STATE_READY
)
{
NiceCandidate
*
local
,
*
remote
;
// Get current selected candidate pair and print IP address used
if
(
nice_agent_get_selected_pair
(
agent
,
stream_id
,
component_id
,
&
local
,
&
remote
))
{
gchar
ipaddr
[
INET6_ADDRSTRLEN
];
nice_address_to_string
(
&
local
->
addr
,
ipaddr
);
printf
(
"
\n
Negotiation complete: ([%s]:%d,"
,
ipaddr
,
nice_address_get_port
(
&
local
->
addr
));
nice_address_to_string
(
&
remote
->
addr
,
ipaddr
);
printf
(
" [%s]:%d)
\n
"
,
ipaddr
,
nice_address_get_port
(
&
remote
->
addr
));
}
// Listen to stdin and send data written to it
printf
(
"
\n
Send lines to remote (Ctrl-D to quit):
\n
"
);
g_io_add_watch
(
io_stdin
,
G_IO_IN
,
stdin_send_data_cb
,
agent
);
printf
(
"> "
);
fflush
(
stdout
);
}
else
if
(
state
==
NICE_COMPONENT_STATE_FAILED
)
{
g_main_loop_quit
(
gloop
);
}
}
static
gboolean
stdin_send_data_cb
(
GIOChannel
*
source
,
GIOCondition
cond
,
gpointer
data
)
{
NiceAgent
*
agent
=
data
;
gchar
*
line
=
NULL
;
if
(
g_io_channel_read_line
(
source
,
&
line
,
NULL
,
NULL
,
NULL
)
==
G_IO_STATUS_NORMAL
)
{
nice_agent_send
(
agent
,
stream_id
,
1
,
strlen
(
line
),
line
);
g_free
(
line
);
printf
(
"> "
);
fflush
(
stdout
);
}
return
TRUE
;
}
static
void
cb_new_selected_pair
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
gchar
*
lfoundation
,
gchar
*
rfoundation
,
gpointer
data
)
{
g_debug
(
"SIGNAL: selected pair %s %s"
,
lfoundation
,
rfoundation
);
}
static
void
cb_nice_recv
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
guint
len
,
gchar
*
buf
,
gpointer
data
)
{
printf
(
"%.*s"
,
len
,
buf
);
fflush
(
stdout
);
}
static
NiceCandidate
*
parse_candidate
(
char
*
scand
,
guint
stream_id
)
{
NiceCandidate
*
cand
=
NULL
;
NiceCandidateType
ntype
;
gchar
**
tokens
=
NULL
;
guint
i
;
tokens
=
g_strsplit
(
scand
,
","
,
5
);
for
(
i
=
0
;
tokens
&&
tokens
[
i
];
i
++
);
if
(
i
!=
5
)
goto
end
;
for
(
i
=
0
;
i
<
G_N_ELEMENTS
(
candidate_type_name
);
i
++
)
{
if
(
strcmp
(
tokens
[
4
],
candidate_type_name
[
i
])
==
0
)
{
ntype
=
i
;
break
;
}
}
if
(
i
==
G_N_ELEMENTS
(
candidate_type_name
))
goto
end
;
cand
=
nice_candidate_new
(
ntype
);
cand
->
component_id
=
1
;
cand
->
stream_id
=
stream_id
;
cand
->
transport
=
NICE_CANDIDATE_TRANSPORT_UDP
;
strncpy
(
cand
->
foundation
,
tokens
[
0
],
NICE_CANDIDATE_MAX_FOUNDATION
);
cand
->
priority
=
atoi
(
tokens
[
1
]);
if
(
!
nice_address_set_from_string
(
&
cand
->
addr
,
tokens
[
2
]))
{
g_message
(
"failed to parse addr: %s"
,
tokens
[
2
]);
nice_candidate_free
(
cand
);
cand
=
NULL
;
goto
end
;
}
nice_address_set_port
(
&
cand
->
addr
,
atoi
(
tokens
[
3
]));
end:
g_strfreev
(
tokens
);
return
cand
;
}
static
int
print_local_data
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
)
{
int
result
=
EXIT_FAILURE
;
gchar
*
local_ufrag
=
NULL
;
gchar
*
local_password
=
NULL
;
gchar
ipaddr
[
INET6_ADDRSTRLEN
];
GSList
*
cands
=
NULL
,
*
item
;
if
(
!
nice_agent_get_local_credentials
(
agent
,
stream_id
,
&
local_ufrag
,
&
local_password
))
goto
end
;
cands
=
nice_agent_get_local_candidates
(
agent
,
stream_id
,
component_id
);
if
(
cands
==
NULL
)
goto
end
;
printf
(
"%s %s"
,
local_ufrag
,
local_password
);
for
(
item
=
cands
;
item
;
item
=
item
->
next
)
{
NiceCandidate
*
c
=
(
NiceCandidate
*
)
item
->
data
;
nice_address_to_string
(
&
c
->
addr
,
ipaddr
);
// (foundation),(prio),(addr),(port),(type)
printf
(
" %s,%u,%s,%u,%s"
,
c
->
foundation
,
c
->
priority
,
ipaddr
,
nice_address_get_port
(
&
c
->
addr
),
candidate_type_name
[
c
->
type
]);
}
printf
(
"
\n
"
);
result
=
EXIT_SUCCESS
;
end:
if
(
local_ufrag
)
g_free
(
local_ufrag
);
if
(
local_password
)
g_free
(
local_password
);
if
(
cands
)
g_slist_free_full
(
cands
,
(
GDestroyNotify
)
&
nice_candidate_free
);
return
result
;
}
static
int
parse_remote_data
(
NiceAgent
*
agent
,
guint
stream_id
,
guint
component_id
,
char
*
line
)
{
GSList
*
remote_candidates
=
NULL
;
gchar
**
line_argv
=
NULL
;
const
gchar
*
ufrag
=
NULL
;
const
gchar
*
passwd
=
NULL
;
int
result
=
EXIT_FAILURE
;
int
i
;
line_argv
=
g_strsplit_set
(
line
,
"
\t\n
"
,
0
);
for
(
i
=
0
;
line_argv
&&
line_argv
[
i
];
i
++
)
{
if
(
strlen
(
line_argv
[
i
])
==
0
)
continue
;
// first two args are remote ufrag and password
if
(
!
ufrag
)
{
ufrag
=
line_argv
[
i
];
}
else
if
(
!
passwd
)
{
passwd
=
line_argv
[
i
];
}
else
{
// Remaining args are serialized canidates (at least one is required)
NiceCandidate
*
c
=
parse_candidate
(
line_argv
[
i
],
stream_id
);
if
(
c
==
NULL
)
{
g_message
(
"failed to parse candidate: %s"
,
line_argv
[
i
]);
goto
end
;
}
remote_candidates
=
g_slist_prepend
(
remote_candidates
,
c
);
}
}
if
(
ufrag
==
NULL
||
passwd
==
NULL
||
remote_candidates
==
NULL
)
{
g_message
(
"line must have at least ufrag, password, and one candidate"
);
goto
end
;
}
if
(
!
nice_agent_set_remote_credentials
(
agent
,
stream_id
,
ufrag
,
passwd
))
{
g_message
(
"failed to set remote credentials"
);
goto
end
;
}
// Note: this will trigger the start of negotiation.
if
(
nice_agent_set_remote_candidates
(
agent
,
stream_id
,
component_id
,
remote_candidates
)
<
1
)
{
g_message
(
"failed to set remote candidates"
);
goto
end
;
}
result
=
EXIT_SUCCESS
;
end:
if
(
line_argv
!=
NULL
)
g_strfreev
(
line_argv
);
if
(
remote_candidates
!=
NULL
)
g_slist_free_full
(
remote_candidates
,
(
GDestroyNotify
)
&
nice_candidate_free
);
return
result
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment