Commit 8472d54e authored by Dafydd Harries's avatar Dafydd Harries

add ICE server skeleton

darcs-hash:20070121144746-c9803-0f0319ec897e42d47d17d3b796378a526aa3b7b2.gz
parent 54833dbe
......@@ -13,3 +13,23 @@ libnice_la_LIBADD = \
libnice_la_LDFLAGS = -Wl,--version-script,$(srcdir)/libnice.ver
noinst_PROGRAMS = ice-test-server
AM_CFLAGS = -Wall -Werror \
-I $(top_srcdir)/agent \
-I $(top_srcdir)/udp \
-I $(top_srcdir)/stun \
$(GLIB_CFLAGS)
ice_test_server_SOURCES = ice-test-server.c \
$(top_srcdir)/agent/readline.h \
$(top_srcdir)/agent/readline.c \
$(top_srcdir)/agent/util.h \
$(top_srcdir)/agent/util.c
ice_test_server_LDADD = \
$(top_builddir)/agent/libagent.la \
$(top_builddir)/udp/libudp.la \
$(top_builddir)/stun/libstun.la \
$(GLIB_LIBS)
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <glib.h>
#include <agent.h>
#include <udp.h>
#include <stun.h>
#include <readline.h>
#include <util.h>
/* create an agent and give it one fixed local IP address */
static gboolean
make_agent (
gchar *ip,
UDPSocketManager *mgr,
Agent **ret_agent,
UDPSocket **ret_sock)
{
Agent *agent;
Address *addr_local;
Event *event;
UDPSocket *sock;
struct sockaddr_in sin;
agent = ice_agent_new ();
addr_local = address_new_ipv4_from_string (ip);
ice_agent_add_local_address (agent, addr_local);
address_free (addr_local);
ice_agent_add_stream (agent, MEDIA_TYPE_AUDIO);
event = ice_agent_pop_event (agent);
g_assert (event != NULL);
g_assert (event->type == EVENT_REQUEST_PORT);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
sock = g_slice_new0 (UDPSocket);
if (!udp_socket_manager_alloc_socket (mgr, sock, &sin))
{
ice_agent_free (agent);
return FALSE;
}
g_debug ("allocated socket %d port %d for candidate %d",
sock->fileno, ntohs (sock->addr.sin_port),
event->request_port.candidate_id);
ice_agent_set_candidate_port (agent, event->request_port.candidate_id,
ntohs (sock->addr.sin_port));
event_free (event);
event = ice_agent_pop_event (agent);
g_assert (event != NULL);
g_assert (event->type == EVENT_LOCAL_CANDIDATES_READY);
event = ice_agent_pop_event (agent);
g_assert (event == NULL);
*ret_agent = agent;
*ret_sock = sock;
return TRUE;
}
static void
handle_udp_read (UDPSocket *sock)
{
struct sockaddr_in from;
gchar buf[1024];
guint len;
g_debug ("got UDP data");
len = udp_socket_recv (sock, &from, 1024, buf);
if (len == 0)
return;
if ((buf[0] & 0xc0) == 0x80)
{
/* looks like RTP */
g_debug ("got media");
}
else
{
/* maybe STUN */
StunMessage *msg;
g_debug ("got STUN");
msg = stun_message_unpack (len, buf);
if (msg == NULL)
return;
if (msg->type == STUN_MESSAGE_BINDING_REQUEST)
{
StunMessage *response;
guint len;
gchar *packed;
response = stun_message_new (STUN_MESSAGE_BINDING_RESPONSE);
response->attributes = g_malloc0 (2 * sizeof (StunAttribute));
response->attributes[0] = stun_attribute_mapped_address_new (
ntohl (from.sin_addr.s_addr), ntohs (from.sin_port));
len = stun_message_pack (response, &packed);
udp_socket_send (sock, &from, len, packed);
g_free (packed);
stun_message_free (response);
}
stun_message_free (msg);
}
}
static gboolean
handle_tcp_read (guint fileno)
{
//Candidate *candidate;
gchar *line;
line = readline (fileno);
if (line == NULL)
return FALSE;
return TRUE;
}
static void
handle_connection (guint fileno, const struct sockaddr_in *sin, gpointer data)
{
Agent *agent;
UDPSocketManager mgr;
UDPSocket *sock;
GSList *sockets = NULL;
gchar ip_str[INET_ADDRSTRLEN];
fd_set fds;
guint max_fd;
gchar *candidate_str;
inet_ntop (AF_INET, &(sin->sin_addr), ip_str, INET_ADDRSTRLEN);
g_debug ("got connection from %s:%d", ip_str, ntohs (sin->sin_port));
udp_socket_manager_init (&mgr);
if (!make_agent ((gchar *) data, &mgr, &agent, &sock))
return;
sockets = g_slist_append (sockets, sock);
candidate_str = candidate_to_string (
(Candidate *) agent->local_candidates->data);
send (fileno, candidate_str, strlen (candidate_str), 0);
send (fileno, "\n", 1, 0);
g_free (candidate_str);
/* event loop */
FD_ZERO (&fds);
FD_SET (fileno, &fds);
FD_SET (sock->fileno, &fds);
max_fd = MAX (fileno, sock->fileno) + 1;
g_debug ("fileno = %d", fileno);
for (;;)
{
fd_set tmp = fds;
guint ret;
guint i;
ret = select (max_fd, &tmp, NULL, NULL, 0);
for (i = 0; i < max_fd; i++)
{
if (!FD_ISSET (i, &tmp))
continue;
if (i == fileno)
{
/* TCP data */
g_debug ("got TCP data");
if (!handle_tcp_read (fileno))
goto EOF;
}
else if (i == sock->fileno)
{
/* UDP data */
handle_udp_read (sock);
}
}
}
EOF:
g_debug ("connection closed");
while (sockets != NULL)
{
GSList *tmp;
UDPSocket *sock = (UDPSocket *) sockets->data;
tmp = sockets;
sockets = sockets->next;
g_slist_free_1 (tmp);
udp_socket_close (sock);
g_slice_free (UDPSocket, sock);
}
g_slist_free (sockets);
udp_socket_manager_close (&mgr);
}
static gboolean
tcp_listen_loop (
guint port,
void (*handler) (guint sock, const struct sockaddr_in *sin, gpointer data),
gpointer data)
{
guint sock;
struct sockaddr_in sin;
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
g_print ("socket() failed: %s\n", g_strerror (errno));
return FALSE;
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons (port);
if (bind (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
g_print ("bind() failed: %s\n", g_strerror (errno));
return 1;
}
if (listen (sock, 5) < 0)
{
g_print("listen() failed: %s\n", g_strerror (errno));
return FALSE;
}
for (;;)
{
gint conn;
struct sockaddr_in from;
guint from_len = sizeof (from);
conn = accept (sock, (struct sockaddr *) &from, &from_len);
if (conn < 0)
{
g_print ("accept() failed: %s\n", g_strerror (errno));
return FALSE;
}
handler (conn, &from, data);
close (conn);
}
return TRUE;
}
int
main(int argc, char **argv)
{
if (argc != 2)
{
g_print ("usage: %s interface\n", argv[0]);
return 1;
}
if (!tcp_listen_loop (7899, handle_connection, argv[1]))
return 1;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment