Skip to content

Instantly share code, notes, and snippets.

@felixSchl
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felixSchl/1a8926689bc363e47a3b to your computer and use it in GitHub Desktop.
Save felixSchl/1a8926689bc363e47a3b to your computer and use it in GitHub Desktop.
Force libnice to not use host candidates
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <agent.h>
#include <winsock2.h>
#define LOCAL_IP "192.168.1.60"
#define TAMPER_SDP
#if _WIN32
bool wsa_init = false;
int inet_init(){
if (wsa_init)
return 0;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) == 0){
wsa_init = true;
return 0;
}
return 1;
}
#endif
static GMainLoop *gloop;
static void* main_thread(void *data);
static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, 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);
typedef struct Context {
gboolean is_controlling;
gboolean candidate_gathering_done;
GMutex gather_mutex;
GMutex connecting_mutex;
NiceAgent* agent;
GCond gather_cond;
char* name;
struct Context* other;
} Context;
Context* context_new(
GMainLoop* loop
, char* name
, gboolean is_controlling
) {
Context* context = malloc(sizeof(Context));
g_cond_init(&context->gather_cond);
g_mutex_init(&context->gather_mutex);
g_mutex_init(&context->connecting_mutex);
context->candidate_gathering_done = FALSE;
context->is_controlling = is_controlling;
context->name = name;
context->agent = nice_agent_new(
g_main_loop_get_context(loop)
, NICE_COMPATIBILITY_RFC5245
);
return context;
}
void context_set_other(Context* context, Context* other) {
context->other = other;
};
int main (int argc, char *argv[]) {
GThread *thread_L;
GThread *thread_R;
#if _WIN32
inet_init();
#endif
nice_debug_enable(TRUE);
gloop = g_main_loop_new(NULL, FALSE);
Context* context_L = context_new(gloop, "L", TRUE);
Context* context_R = context_new(gloop, "R", FALSE);
context_set_other(context_L, context_R);
context_set_other(context_R, context_L);
thread_L = g_thread_new("thread (L)", &main_thread, context_L);
thread_R = g_thread_new("thread (R)", &main_thread, context_R);
g_main_loop_run(gloop);
g_thread_join(thread_L);
g_thread_join(thread_R);
g_main_loop_unref(gloop);
return EXIT_SUCCESS;
}
static void* main_thread(void* data) {
guint stream_id;
GMutex gather_mutex;
GCond gather_cond;
gchar *sdp, *sdp64;
NiceAddress* tmp_addr = NULL;
Context* context = data;
char* name = context->name;
fprintf(
stdout
, "%s: is controlling? - %s\n"
, name, (context->is_controlling) ? "YES" : "NO"
);
fflush(stdout);
// Set options /////////////////////////////////////////////////////////////
fprintf(stdout, "%s: setting options...\n", name);
fflush(stdout);
g_object_set(
context->agent
, "ice-tcp", FALSE
, "stun-server", "52.5.57.211"
, "stun-server-port", 3478
, "controlling-mode", context->is_controlling
, NULL
);
fprintf(stdout, "%s: options set!\n", name);
fflush(stdout);
// Set local address ///////////////////////////////////////////////////////
fprintf(stdout, "%s: setting local ip...\n", name);
fflush(stdout);
tmp_addr = nice_address_new();
if (nice_address_set_from_string(tmp_addr, LOCAL_IP)) {
if(!nice_agent_add_local_address(context->agent, tmp_addr)) {
g_error("Failed to set local ip!");
goto end;
}
} else {
int x = GetLastError();
g_error("The local ip is invalid: `%s` (%d)", LOCAL_IP, x);
goto end;
}
fprintf(stdout, "%s: local ip set!\n", name);
fflush(stdout);
// Connect signals /////////////////////////////////////////////////////////
fprintf(stdout, "%s: connecting signals...\n", name);
fflush(stdout);
g_signal_connect(
context->agent
, "candidate-gathering-done"
, G_CALLBACK(cb_candidate_gathering_done)
, context
);
g_signal_connect(
context->agent
, "component-state-changed"
, G_CALLBACK(cb_component_state_changed)
, context
);
fprintf(stdout, "%s: signals connected!\n", name);
fflush(stdout);
// Create streams //////////////////////////////////////////////////////////
fprintf(stdout, "%s: creating stream...\n", name);
fflush(stdout);
stream_id = nice_agent_add_stream(context->agent, 1);
if (stream_id == 0) {
g_error("Failed to add stream", name);
goto end;
}
fprintf(stdout, "%s: stream created!\n", name);
fflush(stdout);
fprintf(stdout, "%s: setting stream name...\n", name);
fflush(stdout);
nice_agent_set_stream_name(context->agent, stream_id, "text");
fprintf(stdout, "%s: stream name set!\n", name);
fflush(stdout);
// Attach receive callback /////////////////////////////////////////////////
fprintf(stdout, "%s: attaching receive callback...\n", name);
fflush(stdout);
nice_agent_attach_recv(
context->agent
, stream_id
, 1
, g_main_loop_get_context(gloop)
, cb_nice_recv
, context
);
fprintf(stdout, "%s: receive callback attached!\n", name);
fflush(stdout);
// Gather candidates ///////////////////////////////////////////////////////
fprintf(stdout, "%s: gathering candidates...\n", name);
fflush(stdout);
if (!nice_agent_gather_candidates(context->agent, stream_id)) {
g_error("Failed to start candidate gathering");
goto end;
}
g_mutex_lock(&context->gather_mutex);
while (!context->candidate_gathering_done) {
g_cond_wait(&context->gather_cond, &context->gather_mutex);
}
g_mutex_unlock(&context->gather_mutex);
fprintf(stdout, "%s: candidate gathering done!\n", name);
fflush(stdout);
// Create SDP //////////////////////////////////////////////////////////////
sdp = nice_agent_generate_local_sdp (context->agent);
fprintf(stdout, "%s: generated SDP from agent: \n%s\n", name, sdp);
fflush(stdout);
char tmp_sdp[4096] = "";
#ifdef TAMPER_SDP
char line_buffer[1024] = "";
int line_buffer_offset = 0;
int i = 0;
for (i = 0; i < strlen(sdp); i++) {
if (sdp[i] == '\n') {
if (!strstr(line_buffer, "typ host")) {
strcat(tmp_sdp, "\n");
strcat(tmp_sdp, line_buffer);
}
strcpy(line_buffer, "");
line_buffer_offset = 0;
} else {
line_buffer[line_buffer_offset] = sdp[i];
line_buffer_offset += 1;
}
}
strcat(tmp_sdp, "\n");
#else
strcpy(tmp_sdp, sdp);
#endif
fprintf(stdout, "%s: modified SDP from agent: \n%s\n", name, tmp_sdp);
fflush(stdout);
/* context->other->agent */
nice_agent_parse_remote_sdp(
context->other->agent
, tmp_sdp
);
while (TRUE) {
usleep(100000);
}
end:
if (sdp) {
g_free(sdp);
}
g_object_unref(context->agent);
return NULL;
}
static void cb_candidate_gathering_done(
NiceAgent *agent
, guint stream_id
, gpointer data
) {
Context* context = data;
g_mutex_lock(&context->gather_mutex);
context->candidate_gathering_done = TRUE;
g_cond_signal(&context->gather_cond);
g_mutex_unlock(&context->gather_mutex);
}
static void cb_component_state_changed(
NiceAgent *agent
, guint stream_id
, guint component_id
, guint state
, gpointer data
) {
Context* context = data;
fprintf(
stdout
, "%s: state-change for stream %d / component %d: %s\n"
, context->name
, stream_id
, component_id
, nice_component_state_to_string(state)
);
fflush(stdout);
}
static void cb_nice_recv(
NiceAgent *agent
, guint stream_id
, guint component_id
, guint len
, gchar *buf
, gpointer data
) {
Context* context = data;
fprintf(stdout, "%s: Received data: %.*s\n", context->name, len, buf);
fflush(stdout);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment