Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_sip.c @ febef1ea

History | View | Annotate | Download (88.3 KB)

1
/*! \file   janus_sip.c
2
 * \author Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU General Public License v3
4
 * \brief  Janus SIP plugin
5
 * \details  This is a simple SIP plugin for Janus, allowing WebRTC peers
6
 * to register at a SIP server (e.g., Asterisk) and call SIP user agents
7
 * through the gateway. Specifically, when attaching to the plugin peers
8
 * are requested to provide their SIP server credentials, i.e., the address
9
 * of the SIP server and their username/secret. This results in the plugin
10
 * registering at the SIP server and acting as a SIP client on behalf of
11
 * the web peer. Most of the SIP states and lifetime are masked by the plugin,
12
 * and only the relevant events (e.g., INVITEs and BYEs) and functionality
13
 * (call, hangup) are made available to the web peer: peers can call
14
 * extensions at the SIP server or wait for incoming INVITEs, and during
15
 * a call they can send DTMF tones.
16
 * 
17
 * The concept behind this plugin is to allow different web pages associated
18
 * to the same peer, and hence the same SIP user, to attach to the plugin
19
 * at the same time and yet just do a SIP REGISTER once. The same should
20
 * apply for calls: while an incoming call would be notified to all the
21
 * web UIs associated to the peer, only one would be able to pick up and
22
 * answer, in pretty much the same way as SIP forking works but without the
23
 * need to fork in the same place. This specific functionality, though, has
24
 * not been implemented as of yet.
25
 * 
26
 * \todo Only Asterisk and Kamailio have been tested as a SIP server, and
27
 * specifically only with basic audio calls: this plugin needs some work
28
 * to make it more stable and reliable.
29
 * 
30
 * \ingroup plugins
31
 * \ref plugins
32
 */
33

    
34
#include "plugin.h"
35

    
36
#include <ifaddrs.h>
37
#include <net/if.h>
38

    
39
#include <jansson.h>
40

    
41
#include <sofia-sip/msg_header.h>
42
#include <sofia-sip/nua.h>
43
#include <sofia-sip/sdp.h>
44
#include <sofia-sip/sip_status.h>
45

    
46
#include "../debug.h"
47
#include "../apierror.h"
48
#include "../config.h"
49
#include "../mutex.h"
50
#include "../rtp.h"
51
#include "../rtcp.h"
52
#include "../utils.h"
53

    
54

    
55
/* Plugin information */
56
#define JANUS_SIP_VERSION                        4
57
#define JANUS_SIP_VERSION_STRING        "0.0.4"
58
#define JANUS_SIP_DESCRIPTION                "This is a simple SIP plugin for Janus, allowing WebRTC peers to register at a SIP server and call SIP user agents through the gateway."
59
#define JANUS_SIP_NAME                                "JANUS SIP plugin"
60
#define JANUS_SIP_AUTHOR                        "Meetecho s.r.l."
61
#define JANUS_SIP_PACKAGE                        "janus.plugin.sip"
62

    
63
/* Plugin methods */
64
janus_plugin *create(void);
65
int janus_sip_init(janus_callbacks *callback, const char *config_path);
66
void janus_sip_destroy(void);
67
int janus_sip_get_api_compatibility(void);
68
int janus_sip_get_version(void);
69
const char *janus_sip_get_version_string(void);
70
const char *janus_sip_get_description(void);
71
const char *janus_sip_get_name(void);
72
const char *janus_sip_get_author(void);
73
const char *janus_sip_get_package(void);
74
void janus_sip_create_session(janus_plugin_session *handle, int *error);
75
struct janus_plugin_result *janus_sip_handle_message(janus_plugin_session *handle, char *transaction, char *message, char *sdp_type, char *sdp);
76
void janus_sip_setup_media(janus_plugin_session *handle);
77
void janus_sip_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len);
78
void janus_sip_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len);
79
void janus_sip_hangup_media(janus_plugin_session *handle);
80
void janus_sip_destroy_session(janus_plugin_session *handle, int *error);
81
char *janus_sip_query_session(janus_plugin_session *handle);
82

    
83
/* Plugin setup */
84
static janus_plugin janus_sip_plugin =
85
        {
86
                .init = janus_sip_init,
87
                .destroy = janus_sip_destroy,
88

    
89
                .get_api_compatibility = janus_sip_get_api_compatibility,
90
                .get_version = janus_sip_get_version,
91
                .get_version_string = janus_sip_get_version_string,
92
                .get_description = janus_sip_get_description,
93
                .get_name = janus_sip_get_name,
94
                .get_author = janus_sip_get_author,
95
                .get_package = janus_sip_get_package,
96
                
97
                .create_session = janus_sip_create_session,
98
                .handle_message = janus_sip_handle_message,
99
                .setup_media = janus_sip_setup_media,
100
                .incoming_rtp = janus_sip_incoming_rtp,
101
                .incoming_rtcp = janus_sip_incoming_rtcp,
102
                .hangup_media = janus_sip_hangup_media,
103
                .destroy_session = janus_sip_destroy_session,
104
                .query_session = janus_sip_query_session,
105
        }; 
106

    
107
/* Plugin creator */
108
janus_plugin *create(void) {
109
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_SIP_NAME);
110
        return &janus_sip_plugin;
111
}
112

    
113

    
114
/* Useful stuff */
115
static gint initialized = 0, stopping = 0;
116
static janus_callbacks *gateway = NULL;
117
static char *local_ip = NULL;
118

    
119
static GThread *handler_thread;
120
static GThread *watchdog;
121
static void *janus_sip_handler(void *data);
122

    
123
typedef struct janus_sip_message {
124
        janus_plugin_session *handle;
125
        char *transaction;
126
        char *message;
127
        char *sdp_type;
128
        char *sdp;
129
} janus_sip_message;
130
static GAsyncQueue *messages = NULL;
131

    
132
void janus_sip_message_free(janus_sip_message *msg);
133
void janus_sip_message_free(janus_sip_message *msg) {
134
        if(!msg)
135
                return;
136

    
137
        msg->handle = NULL;
138

    
139
        g_free(msg->transaction);
140
        msg->transaction = NULL;
141
        g_free(msg->message);
142
        msg->message = NULL;
143
        g_free(msg->sdp_type);
144
        msg->sdp_type = NULL;
145
        g_free(msg->sdp);
146
        msg->sdp = NULL;
147

    
148
        g_free(msg);
149
}
150

    
151

    
152
typedef enum janus_sip_status {
153
        janus_sip_status_failed = -1,
154
        janus_sip_status_unregistered = 0,
155
        janus_sip_status_registering,
156
        janus_sip_status_registered,
157
        janus_sip_status_inviting,
158
        janus_sip_status_invited,
159
        janus_sip_status_incall,
160
        janus_sip_status_closing,
161
        janus_sip_status_unregistering,
162
} janus_sip_status;
163
const char *janus_sip_status_string(janus_sip_status status);
164
const char *janus_sip_status_string(janus_sip_status status) {
165
        switch(status) {
166
                case janus_sip_status_failed:
167
                        return "failed";
168
                case janus_sip_status_unregistered:
169
                        return "unregistered";
170
                case janus_sip_status_registering:
171
                        return "registering";
172
                case janus_sip_status_registered:
173
                        return "registered";
174
                case janus_sip_status_inviting:
175
                        return "inviting";
176
                case janus_sip_status_invited:
177
                        return "invited";
178
                case janus_sip_status_incall:
179
                        return "incall";
180
                case janus_sip_status_closing:
181
                        return "closing";
182
                case janus_sip_status_unregistering:
183
                        return "unregistering";
184
                default:
185
                        break;
186
        }
187
        return "unknown";
188
}
189

    
190

    
191
/* Sofia stuff */
192
typedef struct ssip_s ssip_t;
193
typedef struct ssip_oper_s ssip_oper_t;
194

    
195
typedef struct janus_sip_account {
196
        char *identity;
197
        char *username;
198
        char *secret;
199
        int sip_port;
200
        char *proxy;
201
} janus_sip_account;
202

    
203
typedef struct janus_sip_media {
204
        char *remote_ip;
205
        int ready:1;
206
        int has_audio:1;
207
        int audio_rtp_fd, audio_rtcp_fd;
208
        int local_audio_rtp_port, remote_audio_rtp_port;
209
        int local_audio_rtcp_port, remote_audio_rtcp_port;
210
        guint32 audio_ssrc, audio_ssrc_peer;
211
        int has_video:1;
212
        int video_rtp_fd, video_rtcp_fd;
213
        int local_video_rtp_port, remote_video_rtp_port;
214
        int local_video_rtcp_port, remote_video_rtcp_port;
215
        guint32 video_ssrc, video_ssrc_peer;
216
} janus_sip_media;
217

    
218
typedef struct janus_sip_session {
219
        janus_plugin_session *handle;
220
        ssip_t *stack;
221
        janus_sip_account account;
222
        janus_sip_status status;
223
        janus_sip_media media;
224
        char *callee;
225
        guint64 destroyed;        /* Time at which this session was marked as destroyed */
226
        janus_mutex mutex;
227
} janus_sip_session;
228
static GHashTable *sessions;
229
static GList *old_sessions;
230
static janus_mutex sessions_mutex;
231

    
232

    
233
#undef SU_ROOT_MAGIC_T
234
#define SU_ROOT_MAGIC_T        ssip_t
235
#undef NUA_MAGIC_T
236
#define NUA_MAGIC_T                ssip_t
237
#undef NUA_HMAGIC_T
238
#define NUA_HMAGIC_T        ssip_oper_t
239

    
240
struct ssip_s {
241
        su_home_t s_home[1];
242
        su_root_t *s_root;
243
        nua_t *s_nua;
244
        nua_handle_t *s_nh_r, *s_nh_i;
245
        janus_sip_session *session;
246
};
247

    
248

    
249
/* Sofia Event thread */
250
gpointer janus_sip_sofia_thread(gpointer user_data);
251
/* Sofia callbacks */
252
void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]);
253
/* SDP parsing */
254
void janus_sip_sdp_process(janus_sip_session *session, sdp_session_t *sdp);
255
/* Media */
256
static int janus_sip_allocate_local_ports(janus_sip_session *session);
257
static void *janus_sip_relay_thread(void *data);
258

    
259

    
260
/* Interface/IP ignore list */
261
GList *janus_sip_ignore_list = NULL;
262
janus_mutex ignore_list_mutex;
263
void janus_sip_ignore_interface(const char *ip);
264
gboolean janus_sip_is_ignored(const char *ip);
265

    
266
void janus_sip_ignore_interface(const char *ip) {
267
        if(ip == NULL)
268
                return;
269
        /* Is this an IP or an interface? */
270
        janus_mutex_lock(&ignore_list_mutex);
271
        janus_sip_ignore_list = g_list_append(janus_sip_ignore_list, (gpointer)ip);
272
        janus_mutex_unlock(&ignore_list_mutex);
273
}
274

    
275
gboolean janus_sip_is_ignored(const char *ip) {
276
        if(ip == NULL || janus_sip_ignore_list == NULL)
277
                return FALSE;
278
        janus_mutex_lock(&ignore_list_mutex);
279
        GList *temp = janus_sip_ignore_list;
280
        while(temp) {
281
                const char *ignored = (const char *)temp->data;
282
                if(ignored != NULL && strstr(ip, ignored)) {
283
                        janus_mutex_unlock(&ignore_list_mutex);
284
                        return TRUE;
285
                }
286
                temp = temp->next;
287
        }
288
        janus_mutex_unlock(&ignore_list_mutex);
289
        return FALSE;
290
}
291

    
292

    
293
/* Error codes */
294
#define JANUS_SIP_ERROR_UNKNOWN_ERROR                499
295
#define JANUS_SIP_ERROR_NO_MESSAGE                        440
296
#define JANUS_SIP_ERROR_INVALID_JSON                441
297
#define JANUS_SIP_ERROR_INVALID_REQUEST                442
298
#define JANUS_SIP_ERROR_MISSING_ELEMENT                443
299
#define JANUS_SIP_ERROR_INVALID_ELEMENT                444
300
#define JANUS_SIP_ERROR_ALREADY_REGISTERED        445
301
#define JANUS_SIP_ERROR_INVALID_ADDRESS                446
302
#define JANUS_SIP_ERROR_WRONG_STATE                        447
303
#define JANUS_SIP_ERROR_MISSING_SDP                        448
304
#define JANUS_SIP_ERROR_LIBSOFIA_ERROR                449
305
#define JANUS_SIP_ERROR_IO_ERROR                        450
306

    
307

    
308
/* SIP watchdog/garbage collector (sort of) */
309
void *janus_sip_watchdog(void *data);
310
void *janus_sip_watchdog(void *data) {
311
        JANUS_LOG(LOG_INFO, "SIP watchdog started\n");
312
        gint64 now = 0;
313
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
314
                janus_mutex_lock(&sessions_mutex);
315
                /* Iterate on all the sessions */
316
                now = janus_get_monotonic_time();
317
                if(old_sessions != NULL) {
318
                        GList *sl = old_sessions;
319
                        JANUS_LOG(LOG_VERB, "Checking %d old sessions\n", g_list_length(old_sessions));
320
                        while(sl) {
321
                                janus_sip_session *session = (janus_sip_session *)sl->data;
322
                                if(!session) {
323
                                        sl = sl->next;
324
                                        continue;
325
                                }
326
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
327
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
328
                                        GList *rm = sl->next;
329
                                        old_sessions = g_list_delete_link(old_sessions, sl);
330
                                        sl = rm;
331
                                        session->handle = NULL;
332
                                        g_free(session);
333
                                        session = NULL;
334
                                        continue;
335
                                }
336
                                sl = sl->next;
337
                        }
338
                }
339
                janus_mutex_unlock(&sessions_mutex);
340
                g_usleep(2000000);
341
        }
342
        JANUS_LOG(LOG_INFO, "SIP watchdog stopped\n");
343
        return NULL;
344
}
345

    
346

    
347
/* Plugin implementation */
348
int janus_sip_init(janus_callbacks *callback, const char *config_path) {
349
        if(g_atomic_int_get(&stopping)) {
350
                /* Still stopping from before */
351
                return -1;
352
        }
353
        if(callback == NULL || config_path == NULL) {
354
                /* Invalid arguments */
355
                return -1;
356
        }
357

    
358
        /* Read configuration */
359
        char filename[255];
360
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_SIP_PACKAGE);
361
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
362
        janus_config *config = janus_config_parse(filename);
363
        if(config != NULL)
364
                janus_config_print(config);
365
        janus_config_item *item = janus_config_get_item_drilldown(config, "general", "c_address");
366
        if(item != NULL && item->value != NULL) {
367
                local_ip = g_strdup(item->value);
368
                JANUS_LOG(LOG_VERB, "Going to use %s as a c-line in the SDPs\n", local_ip);
369
        }
370
        item = janus_config_get_item_drilldown(config, "general", "autodetect_ignore");
371
        if(item && item->value) {
372
                gchar **list = g_strsplit(item->value, ",", -1);
373
                gchar *index = list[0];
374
                if(index != NULL) {
375
                        int i=0;
376
                        while(index != NULL) {
377
                                if(strlen(index) > 0) {
378
                                        JANUS_LOG(LOG_VERB, "Adding '%s' to the c-line ignore list...\n", index);
379
                                        janus_sip_ignore_interface(g_strdup(index));
380
                                }
381
                                i++;
382
                                index = list[i];
383
                        }
384
                }
385
                g_strfreev(list);
386
                list = NULL;
387
        }
388

    
389
        /* This plugin actually has nothing to configure... */
390
        janus_config_destroy(config);
391
        config = NULL;
392
        
393
        if(local_ip == NULL) {
394
                /* What is the local public IP? */
395
                JANUS_LOG(LOG_VERB, "Autodetecting through available interfaces...\n");
396
                /* Try to autodetect, but ignore those in the ignore list */
397
                struct ifaddrs *ifaddr, *ifa;
398
                int family, s, n;
399
                char host[NI_MAXHOST];
400
                if(getifaddrs(&ifaddr) == -1) {
401
                        JANUS_LOG(LOG_ERR, "Error getting list of interfaces...");
402
                } else {
403
                        for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
404
                                if(ifa->ifa_addr == NULL)
405
                                        continue;
406
                                family = ifa->ifa_addr->sa_family;
407
                                if(family != AF_INET && family != AF_INET6)
408
                                        continue;
409
                                /* FIXME We skip IPv6 addresses for now */
410
                                if(family == AF_INET6)
411
                                        continue;
412
                                /* Check the interface name first: we can ignore that as well */
413
                                if(ifa->ifa_name != NULL && janus_sip_is_ignored(ifa->ifa_name))
414
                                        continue;
415
                                s = getnameinfo(ifa->ifa_addr,
416
                                                (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
417
                                                host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
418
                                if(s != 0) {
419
                                        JANUS_LOG(LOG_ERR, "getnameinfo() failed: %s\n", gai_strerror(s));
420
                                        continue;
421
                                }
422
                                /* Skip localhost */
423
                                if(!strcmp(host, "127.0.0.1") || !strcmp(host, "::1") || !strcmp(host, "0.0.0.0"))
424
                                        continue;
425
                                /* Check if this IP address is in the ignore list, now */
426
                                if(janus_sip_is_ignored(host))
427
                                        continue;
428
                                /* FIXME Ok, add use this interface (we're sticking with the first we get) */
429
                                local_ip = g_strdup(host);
430
                                break;
431
                        }
432
                        freeifaddrs(ifaddr);
433
                }
434
                if(local_ip == NULL) {
435
                        JANUS_LOG(LOG_VERB, "Couldn't find any address! using 127.0.0.1 for c-lines... (which is NOT going to work out of your machine)\n");
436
                        local_ip = g_strdup("127.0.0.1");
437
                } else {
438
                        JANUS_LOG(LOG_VERB, "Going to use %s as a c-line in the SDPs\n", local_ip);
439
                }
440
        }
441

    
442
        /* Setup sofia */
443
        su_init();
444

    
445
        sessions = g_hash_table_new(NULL, NULL);
446
        janus_mutex_init(&sessions_mutex);
447
        messages = g_async_queue_new_full((GDestroyNotify) janus_sip_message_free);
448
        /* This is the callback we'll need to invoke to contact the gateway */
449
        gateway = callback;
450

    
451
        g_atomic_int_set(&initialized, 1);
452

    
453
        GError *error = NULL;
454
        /* Start the sessions watchdog */
455
        watchdog = g_thread_try_new("etest watchdog", &janus_sip_watchdog, NULL, &error);
456
        if(error != NULL) {
457
                g_atomic_int_set(&initialized, 0);
458
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SIP watchdog thread...\n", error->code, error->message ? error->message : "??");
459
                return -1;
460
        }
461
        /* Launch the thread that will handle incoming messages */
462
        handler_thread = g_thread_try_new("janus sip handler", janus_sip_handler, NULL, &error);
463
        if(error != NULL) {
464
                g_atomic_int_set(&initialized, 0);
465
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SIP handler thread...\n", error->code, error->message ? error->message : "??");
466
                return -1;
467
        }
468
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_SIP_NAME);
469
        return 0;
470
}
471

    
472
void janus_sip_destroy(void) {
473
        if(!g_atomic_int_get(&initialized))
474
                return;
475
        g_atomic_int_set(&stopping, 1);
476
        if(handler_thread != NULL) {
477
                g_thread_join(handler_thread);
478
                handler_thread = NULL;
479
        }
480
        if(watchdog != NULL) {
481
                g_thread_join(watchdog);
482
                watchdog = NULL;
483
        }
484
        /* FIXME We should destroy the sessions cleanly */
485
        janus_mutex_lock(&sessions_mutex);
486
        g_hash_table_destroy(sessions);
487
        janus_mutex_unlock(&sessions_mutex);
488
        g_async_queue_unref(messages);
489
        messages = NULL;
490
        sessions = NULL;
491
        g_atomic_int_set(&initialized, 0);
492
        g_atomic_int_set(&stopping, 0);
493
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_SIP_NAME);
494
}
495

    
496
int janus_sip_get_api_compatibility(void) {
497
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
498
        return JANUS_PLUGIN_API_VERSION;
499
}
500

    
501
int janus_sip_get_version(void) {
502
        return JANUS_SIP_VERSION;
503
}
504

    
505
const char *janus_sip_get_version_string(void) {
506
        return JANUS_SIP_VERSION_STRING;
507
}
508

    
509
const char *janus_sip_get_description(void) {
510
        return JANUS_SIP_DESCRIPTION;
511
}
512

    
513
const char *janus_sip_get_name(void) {
514
        return JANUS_SIP_NAME;
515
}
516

    
517
const char *janus_sip_get_author(void) {
518
        return JANUS_SIP_AUTHOR;
519
}
520

    
521
const char *janus_sip_get_package(void) {
522
        return JANUS_SIP_PACKAGE;
523
}
524

    
525
void janus_sip_create_session(janus_plugin_session *handle, int *error) {
526
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
527
                *error = -1;
528
                return;
529
        }        
530
        janus_sip_session *session = (janus_sip_session *)calloc(1, sizeof(janus_sip_session));
531
        if(session == NULL) {
532
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
533
                *error = -2;
534
                return;
535
        }
536
        session->handle = handle;
537
        session->account.identity = NULL;
538
        session->account.username = NULL;
539
        session->account.secret = NULL;
540
        session->account.sip_port = 0;
541
        session->account.proxy = NULL;
542
        session->stack = calloc(1, sizeof(ssip_t));
543
        if(session->stack == NULL) {
544
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
545
                *error = -2;
546
                g_free(session);
547
                return;
548
        }
549
        session->stack->session = session;
550
        session->stack->s_nua = NULL;
551
        session->stack->s_nh_r = NULL;
552
        session->stack->s_nh_i = NULL;
553
        session->stack->s_root = NULL;
554
        session->callee = NULL;
555
        session->media.remote_ip = NULL;
556
        session->media.ready = 0;
557
        session->media.has_audio = 0;
558
        session->media.audio_rtp_fd = 0;
559
        session->media.audio_rtcp_fd= 0;
560
        session->media.local_audio_rtp_port = 0;
561
        session->media.remote_audio_rtp_port = 0;
562
        session->media.local_audio_rtcp_port = 0;
563
        session->media.remote_audio_rtcp_port = 0;
564
        session->media.audio_ssrc = 0;
565
        session->media.audio_ssrc_peer = 0;
566
        session->media.has_video = 0;
567
        session->media.video_rtp_fd = 0;
568
        session->media.video_rtcp_fd= 0;
569
        session->media.local_video_rtp_port = 0;
570
        session->media.remote_video_rtp_port = 0;
571
        session->media.local_video_rtcp_port = 0;
572
        session->media.remote_video_rtcp_port = 0;
573
        session->media.video_ssrc = 0;
574
        session->media.video_ssrc_peer = 0;
575
        session->destroyed = 0;
576
        su_home_init(session->stack->s_home);
577
        janus_mutex_init(&session->mutex);
578
        handle->plugin_handle = session;
579

    
580
        janus_mutex_lock(&sessions_mutex);
581
        g_hash_table_insert(sessions, handle, session);
582
        janus_mutex_unlock(&sessions_mutex);
583

    
584
        return;
585
}
586

    
587
void janus_sip_destroy_session(janus_plugin_session *handle, int *error) {
588
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
589
                *error = -1;
590
                return;
591
        }        
592
        janus_sip_session *session = (janus_sip_session *)handle->plugin_handle; 
593
        if(!session) {
594
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
595
                *error = -2;
596
                return;
597
        }
598
        if(session->destroyed) {
599
                JANUS_LOG(LOG_VERB, "Session already destroyed...\n");
600
                return;
601
        }
602
        janus_mutex_lock(&sessions_mutex);
603
        g_hash_table_remove(sessions, handle);
604
        janus_mutex_unlock(&sessions_mutex);
605
        janus_sip_hangup_media(handle);
606
        JANUS_LOG(LOG_VERB, "Destroying SIP session (%s)...\n", session->account.username ? session->account.username : "unregistered user");
607
        /* Shutdown the NUA */
608
        nua_shutdown(session->stack->s_nua);
609
        /* Cleaning up and removing the session is done in a lazy way */
610
        session->destroyed = janus_get_monotonic_time();
611
        janus_mutex_lock(&sessions_mutex);
612
        old_sessions = g_list_append(old_sessions, session);
613
        janus_mutex_unlock(&sessions_mutex);
614
        return;
615
}
616

    
617
char *janus_sip_query_session(janus_plugin_session *handle) {
618
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
619
                return NULL;
620
        }        
621
        janus_sip_session *session = (janus_sip_session *)handle->plugin_handle;
622
        if(!session) {
623
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
624
                return NULL;
625
        }
626
        /* Provide some generic info, e.g., if we're in a call and with whom */
627
        json_t *info = json_object();
628
        json_object_set_new(info, "username", session->account.username ? json_string(session->account.username) : NULL);
629
        json_object_set_new(info, "identity", session->account.identity ? json_string(session->account.identity) : NULL);
630
        json_object_set_new(info, "status", json_string(janus_sip_status_string(session->status)));
631
        if(session->callee)
632
                json_object_set_new(info, "callee", json_string(session->callee ? session->callee : "??"));
633
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
634
        char *info_text = json_dumps(info, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
635
        json_decref(info);
636
        return info_text;
637
}
638

    
639
struct janus_plugin_result *janus_sip_handle_message(janus_plugin_session *handle, char *transaction, char *message, char *sdp_type, char *sdp) {
640
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
641
                return janus_plugin_result_new(JANUS_PLUGIN_ERROR, g_atomic_int_get(&stopping) ? "Shutting down" : "Plugin not initialized");
642
        JANUS_LOG(LOG_VERB, "%s\n", message);
643
        janus_sip_message *msg = calloc(1, sizeof(janus_sip_message));
644
        if(msg == NULL) {
645
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
646
                return janus_plugin_result_new(JANUS_PLUGIN_ERROR, "Memory error");
647
        }
648
        msg->handle = handle;
649
        msg->transaction = transaction;
650
        msg->message = message;
651
        msg->sdp_type = sdp_type;
652
        msg->sdp = sdp;
653
        g_async_queue_push(messages, msg);
654

    
655
        /* All the requests to this plugin are handled asynchronously */
656
        return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL);
657
}
658

    
659
void janus_sip_setup_media(janus_plugin_session *handle) {
660
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
661
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
662
                return;
663
        janus_sip_session *session = (janus_sip_session *)handle->plugin_handle;        
664
        if(!session) {
665
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
666
                return;
667
        }
668
        if(session->destroyed)
669
                return;
670
        /* TODO Only relay RTP/RTCP when we get this event */
671
}
672

    
673
void janus_sip_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
674
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
675
                return;
676
        if(gateway) {
677
                /* Honour the audio/video active flags */
678
                janus_sip_session *session = (janus_sip_session *)handle->plugin_handle;        
679
                if(!session || session->destroyed) {
680
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
681
                        return;
682
                }
683
                if(session->status != janus_sip_status_incall)
684
                        return;
685
                /* Forward to our SIP peer */
686
                if(video) {
687
                        if(session->media.video_ssrc == 0) {
688
                                rtp_header *header = (rtp_header *)buf;
689
                                session->media.video_ssrc = ntohl(header->ssrc);
690
                                JANUS_LOG(LOG_VERB, "Got SIP video SSRC: %"SCNu32"\n", session->media.video_ssrc);
691
                        }
692
                        if(session->media.has_video && session->media.video_rtp_fd) {
693
                                send(session->media.video_rtp_fd, buf, len, 0);
694
                        }
695
                } else {
696
                        if(session->media.audio_ssrc == 0) {
697
                                rtp_header *header = (rtp_header *)buf;
698
                                session->media.audio_ssrc = ntohl(header->ssrc);
699
                                JANUS_LOG(LOG_VERB, "Got SIP audio SSRC: %"SCNu32"\n", session->media.audio_ssrc);
700
                        }
701
                        if(session->media.has_audio && session->media.audio_rtp_fd) {
702
                                send(session->media.audio_rtp_fd, buf, len, 0);
703
                        }
704
                }
705
        }
706
}
707

    
708
void janus_sip_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
709
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
710
                return;
711
        if(gateway) {
712
                janus_sip_session *session = (janus_sip_session *)handle->plugin_handle;        
713
                if(!session || session->destroyed) {
714
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
715
                        return;
716
                }
717
                if(session->status != janus_sip_status_incall)
718
                        return;
719
                /* Fix SSRCs as the gateway does */
720
                JANUS_LOG(LOG_HUGE, "[SIP] Fixing SSRCs (local %u, peer %u)\n",
721
                        video ? session->media.video_ssrc : session->media.audio_ssrc,
722
                        video ? session->media.video_ssrc_peer : session->media.audio_ssrc_peer);
723
                janus_rtcp_fix_ssrc((char *)buf, len, 1,
724
                        video ? session->media.video_ssrc : session->media.audio_ssrc,
725
                        video ? session->media.video_ssrc_peer : session->media.audio_ssrc_peer);
726
                /* Forward to our SIP peer */
727
                if(video) {
728
                        if(session->media.has_video && session->media.video_rtcp_fd) {
729
                                send(session->media.video_rtcp_fd, buf, len, 0);
730
                        }
731
                } else {
732
                        if(session->media.has_audio && session->media.audio_rtcp_fd) {
733
                                send(session->media.audio_rtcp_fd, buf, len, 0);
734
                        }
735
                }
736
        }
737
}
738

    
739
void janus_sip_hangup_media(janus_plugin_session *handle) {
740
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
741
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
742
                return;
743
        janus_sip_session *session = (janus_sip_session *)handle->plugin_handle;        
744
        if(!session) {
745
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
746
                return;
747
        }
748
        if(session->destroyed)
749
                return;
750
        if(session->status < janus_sip_status_inviting || session->status > janus_sip_status_incall)
751
                return;
752
        /* FIXME Simulate a "hangup" coming from the browser */
753
        janus_sip_message *msg = calloc(1, sizeof(janus_sip_message));
754
        if(msg == NULL) {
755
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
756
                return;
757
        }
758
        msg->handle = handle;
759
        msg->message = g_strdup("{\"request\":\"hangup\"}");
760
        msg->transaction = NULL;
761
        msg->sdp_type = NULL;
762
        msg->sdp = NULL;
763
        g_async_queue_push(messages, msg);
764
}
765

    
766
/* Thread to handle incoming messages */
767
static void *janus_sip_handler(void *data) {
768
        JANUS_LOG(LOG_VERB, "Joining SIP handler thread\n");
769
        janus_sip_message *msg = NULL;
770
        int error_code = 0;
771
        char *error_cause = calloc(512, sizeof(char));        /* FIXME 512 should be enough, but anyway... */
772
        if(error_cause == NULL) {
773
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
774
                return NULL;
775
        }
776
        json_t *root = NULL;
777
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
778
                if(!messages || (msg = g_async_queue_try_pop(messages)) == NULL) {
779
                        usleep(50000);
780
                        continue;
781
                }
782
                janus_sip_session *session = (janus_sip_session *)msg->handle->plugin_handle;
783
                if(!session) {
784
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
785
                        janus_sip_message_free(msg);
786
                        continue;
787
                }
788
                if(session->destroyed) {
789
                        janus_sip_message_free(msg);
790
                        continue;
791
                }
792
                /* Handle request */
793
                error_code = 0;
794
                root = NULL;
795
                JANUS_LOG(LOG_VERB, "Handling message: %s\n", msg->message);
796
                if(msg->message == NULL) {
797
                        JANUS_LOG(LOG_ERR, "No message??\n");
798
                        error_code = JANUS_SIP_ERROR_NO_MESSAGE;
799
                        g_snprintf(error_cause, 512, "%s", "No message??");
800
                        goto error;
801
                }
802
                json_error_t error;
803
                root = json_loads(msg->message, 0, &error);
804
                if(!root) {
805
                        JANUS_LOG(LOG_ERR, "JSON error: on line %d: %s\n", error.line, error.text);
806
                        error_code = JANUS_SIP_ERROR_INVALID_JSON;
807
                        g_snprintf(error_cause, 512, "JSON error: on line %d: %s", error.line, error.text);
808
                        goto error;
809
                }
810
                if(!json_is_object(root)) {
811
                        JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
812
                        error_code = JANUS_SIP_ERROR_INVALID_JSON;
813
                        g_snprintf(error_cause, 512, "JSON error: not an object");
814
                        goto error;
815
                }
816
                json_t *request = json_object_get(root, "request");
817
                if(!request) {
818
                        JANUS_LOG(LOG_ERR, "Missing element (request)\n");
819
                        error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
820
                        g_snprintf(error_cause, 512, "Missing element (request)");
821
                        goto error;
822
                }
823
                if(!json_is_string(request)) {
824
                        JANUS_LOG(LOG_ERR, "Invalid element (request should be a string)\n");
825
                        error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
826
                        g_snprintf(error_cause, 512, "Invalid element (request should be a string)");
827
                        goto error;
828
                }
829
                const char *request_text = json_string_value(request);
830
                json_t *result = NULL;
831
                char *sdp_type = NULL, *sdp = NULL;
832
                if(!strcasecmp(request_text, "register")) {
833
                        /* Send a REGISTER */
834
                        if(session->status > janus_sip_status_unregistered) {
835
                                JANUS_LOG(LOG_ERR, "Already registered (%s)\n", session->account.username);
836
                                error_code = JANUS_SIP_ERROR_ALREADY_REGISTERED;
837
                                g_snprintf(error_cause, 512, "Already registered (%s)", session->account.username);
838
                                goto error;
839
                        }
840
                        gboolean guest = FALSE;
841
                        json_t *type = json_object_get(root, "type");
842
                        if(type != NULL) {
843
                                if(!type) {
844
                                        JANUS_LOG(LOG_ERR, "Missing element (type)\n");
845
                                        error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
846
                                        g_snprintf(error_cause, 512, "Missing element (type)");
847
                                        goto error;
848
                                }
849
                                if(!json_is_string(type)) {
850
                                        JANUS_LOG(LOG_ERR, "Invalid element (type should be a string)\n");
851
                                        error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
852
                                        g_snprintf(error_cause, 512, "Invalid element (type should be a string)");
853
                                        goto error;
854
                                }
855
                                const char *type_text = json_string_value(type);
856
                                if(!strcmp(type_text, "guest")) {
857
                                        JANUS_LOG(LOG_INFO, "Registering as a guest\n");
858
                                        guest = TRUE;
859
                                } else {
860
                                        JANUS_LOG(LOG_WARN, "Unknown type '%s', ignoring...\n", type_text);
861
                                }
862
                        }
863
                        /* Parse address */
864
                        json_t *proxy = json_object_get(root, "proxy");
865
                        if(!proxy) {
866
                                JANUS_LOG(LOG_ERR, "Missing element (proxy)\n");
867
                                error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
868
                                g_snprintf(error_cause, 512, "Missing element (proxy)");
869
                                goto error;
870
                        }
871
                        if(!json_is_string(proxy)) {
872
                                JANUS_LOG(LOG_ERR, "Invalid element (proxy should be a string)\n");
873
                                error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
874
                                g_snprintf(error_cause, 512, "Invalid element (proxy should be a string)");
875
                                goto error;
876
                        }
877
                        const char *proxy_text = json_string_value(proxy);
878
                        if(strstr(proxy_text, "sip:") != proxy_text) {
879
                                JANUS_LOG(LOG_ERR, "Invalid proxy address %s\n", proxy_text);
880
                                error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
881
                                g_snprintf(error_cause, 512, "Invalid proxy address %s\n", proxy_text);
882
                                goto error;
883
                        }
884
                        const char *domain_part = proxy_text+4;        /* Skip sip: part */
885
                        char proxy_ip[256];
886
                        uint16_t proxy_port = 0;
887
                        if(strstr(domain_part, ":") == NULL) {
888
                                strncpy(proxy_ip, domain_part, strlen(domain_part) < 255 ? strlen(domain_part) : 255);
889
                                proxy_ip[strlen(domain_part) < 255 ? strlen(domain_part) : 255] = '\0';
890
                                proxy_port = 5060;
891
                        } else {
892
                                gchar **domain = g_strsplit(domain_part, ":", -1);
893
                                if(domain[0] == NULL || domain[1] == NULL) {
894
                                        g_strfreev(domain);
895
                                        JANUS_LOG(LOG_ERR, "Invalid proxy address %s\n", domain_part);
896
                                        error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
897
                                        g_snprintf(error_cause, 512, "Invalid proxy address %s\n", domain_part);
898
                                        goto error;
899
                                }
900
                                strncpy(proxy_ip, domain[0], strlen(domain[0]) < 255 ? strlen(domain[0]) : 255);
901
                                proxy_ip[strlen(domain[0]) < 255 ? strlen(domain[0]) : 255] = '\0';
902
                                proxy_port = atoi(domain[1]);
903
                                g_strfreev(domain);
904
                        }
905
                        /* Now the user part, if needed */
906
                        json_t *username = json_object_get(root, "username");
907
                        if(!guest && !username) {
908
                                /* The username is mandatory if we're not registering as guests */
909
                                JANUS_LOG(LOG_ERR, "Missing element (username)\n");
910
                                error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
911
                                g_snprintf(error_cause, 512, "Missing element (username)");
912
                                goto error;
913
                        }
914
                        const char *username_text = NULL;
915
                        char user_id[256];
916
                        char user_ip[256];
917
                        uint16_t user_port = 0;
918
                        if(username) {
919
                                if(!json_is_string(username)) {
920
                                        JANUS_LOG(LOG_ERR, "Invalid element (username should be a string)\n");
921
                                        error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
922
                                        g_snprintf(error_cause, 512, "Invalid element (username should be a string)");
923
                                        goto error;
924
                                }
925
                                /* Parse address */
926
                                username_text = username ? json_string_value(username) : NULL;
927
                                if(strstr(username_text, "sip:") != username_text && !strstr(username_text, "@")) {
928
                                        JANUS_LOG(LOG_ERR, "Invalid user address %s\n", username_text);
929
                                        error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
930
                                        g_snprintf(error_cause, 512, "Invalid user address %s\n", username_text);
931
                                        goto error;
932
                                }
933
                                gchar **parts = g_strsplit(username_text+4, "@", -1);
934
                                if(parts[0] == NULL || parts[1] == NULL) {
935
                                        g_strfreev(parts);
936
                                        JANUS_LOG(LOG_ERR, "Invalid user address %s\n", username_text);
937
                                        error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
938
                                        g_snprintf(error_cause, 512, "Invalid user address %s\n", username_text);
939
                                        goto error;
940
                                }
941
                                strncpy(user_id, parts[0], strlen(parts[0]) < 255 ? strlen(parts[0]) : 255);
942
                                user_id[strlen(parts[0]) < 255 ? strlen(parts[0]) : 255] = '\0';
943
                                if(strstr(parts[1], ":") == NULL) {
944
                                        strncpy(user_ip, parts[1], strlen(parts[1]) < 255 ? strlen(parts[1]) : 255);
945
                                        user_ip[strlen(parts[1]) < 255 ? strlen(parts[1]) : 255] = '\0';
946
                                        user_port = 5060;
947
                                } else {
948
                                        gchar **domain = g_strsplit(parts[1], ":", -1);
949
                                        if(domain[0] == NULL || domain[1] == NULL) {
950
                                                g_strfreev(domain);
951
                                                JANUS_LOG(LOG_ERR, "Invalid user address %s\n", username_text);
952
                                                error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
953
                                                g_snprintf(error_cause, 512, "Invalid user address %s\n", username_text);
954
                                                goto error;
955
                                        }
956
                                        strncpy(user_ip, domain[0], strlen(domain[0]) < 255 ? strlen(domain[0]) : 255);
957
                                        user_ip[strlen(domain[0]) < 255 ? strlen(domain[0]) : 255] = '\0';
958
                                        user_port = atoi(domain[1]);
959
                                        g_strfreev(domain);
960
                                }
961
                                g_strfreev(parts);
962
                                if(user_port == 0) {
963
                                        JANUS_LOG(LOG_ERR, "Invalid user address %s\n", username_text);
964
                                        error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
965
                                        g_snprintf(error_cause, 512, "Invalid user address %s\n", username_text);
966
                                        goto error;
967
                                }
968
                        }
969
                        if(guest) {
970
                                /* Not needed, we can stop here: just pick a random username if it wasn't provided and say we're registered */
971
                                if(!username) {
972
                                        char username[255];
973
                                        g_snprintf(username, 255, "janus-sip-%"SCNu32"", g_random_int());
974
                                        session->account.username = g_strdup(username);
975
                                } else {
976
                                        session->account.username = g_strdup(user_id);
977
                                }
978
                                JANUS_LOG(LOG_INFO, "Guest will have username %s\n", session->account.username);
979
                                session->status = janus_sip_status_registering;
980
                                if(session->stack->s_nua == NULL) {
981
                                        /* Start the thread first */
982
                                        GError *error = NULL;
983
                                        g_thread_try_new("worker", janus_sip_sofia_thread, session, &error);
984
                                        if(error != NULL) {
985
                                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SIP Sofia thread...\n", error->code, error->message ? error->message : "??");
986
                                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
987
                                                g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the SIP Sofia thread", error->code, error->message ? error->message : "??");
988
                                                goto error;
989
                                        }
990
                                        long int timeout = 0;
991
                                        while(session->stack->s_nua == NULL) {
992
                                                g_usleep(100000);
993
                                                timeout += 100000;
994
                                                if(timeout >= 2000000) {
995
                                                        break;
996
                                                }
997
                                        }
998
                                        if(timeout >= 2000000) {
999
                                                JANUS_LOG(LOG_ERR, "Two seconds passed and still no NUA, problems with the thread?\n");
1000
                                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1001
                                                g_snprintf(error_cause, 512, "Two seconds passed and still no NUA, problems with the thread?");
1002
                                                goto error;
1003
                                        }
1004
                                }
1005
                                if(session->stack->s_nh_r != NULL)
1006
                                        nua_handle_destroy(session->stack->s_nh_r);
1007
                                session->stack->s_nh_r = nua_handle(session->stack->s_nua, session, TAG_END());
1008
                                if(session->stack->s_nh_r == NULL) {
1009
                                        JANUS_LOG(LOG_ERR, "NUA Handle for REGISTER still null??\n");
1010
                                        error_code = JANUS_SIP_ERROR_LIBSOFIA_ERROR;
1011
                                        g_snprintf(error_cause, 512, "Invalid NUA Handle");
1012
                                        goto error;
1013
                                }
1014
                                session->status = janus_sip_status_registered;
1015
                                result = json_object();
1016
                                json_object_set_new(result, "event", json_string("registered"));
1017
                                json_object_set_new(result, "username", json_string(session->account.username));
1018
                        } else {
1019
                                json_t *secret = json_object_get(root, "secret");
1020
                                if(!secret) {
1021
                                        JANUS_LOG(LOG_ERR, "Missing element (secret)\n");
1022
                                        error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
1023
                                        g_snprintf(error_cause, 512, "Missing element (secret)");
1024
                                        goto error;
1025
                                }
1026
                                if(!json_is_string(secret)) {
1027
                                        JANUS_LOG(LOG_ERR, "Invalid element (secret should be a string)\n");
1028
                                        error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
1029
                                        g_snprintf(error_cause, 512, "Invalid element (secret should be a string)");
1030
                                        goto error;
1031
                                }
1032
                                const char *secret_text = json_string_value(secret);
1033
                                /* Got the values, try registering now */
1034
                                char registrar[256];
1035
                                g_snprintf(registrar, 256, "sip:%s:%d", user_ip, user_port); 
1036
                                JANUS_LOG(LOG_VERB, "Registering user sip:%s@%s:%d (secret %s) @ %s through sip:%s:%d\n",
1037
                                        user_id, user_ip, user_port, secret_text, registrar, proxy_ip, proxy_port);
1038
                                if(session->account.identity != NULL)
1039
                                        g_free(session->account.identity);
1040
                                if(session->account.username != NULL)
1041
                                        g_free(session->account.username);
1042
                                if(session->account.secret != NULL)
1043
                                        g_free(session->account.secret);
1044
                                if(session->account.proxy != NULL)
1045
                                        g_free(session->account.proxy);
1046
                                session->account.identity = g_strdup(username_text);
1047
                                session->account.username = g_strdup(user_id);
1048
                                session->account.secret = g_strdup(secret_text);
1049
                                session->account.proxy = g_strdup(proxy_text);
1050
                                if(session->account.identity == NULL || session->account.username == NULL || session->account.secret == NULL || session->account.proxy == NULL) {
1051
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1052
                                        error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1053
                                        g_snprintf(error_cause, 512, "Memory error");
1054
                                        goto error;
1055
                                }
1056
                                session->status = janus_sip_status_registering;
1057
                                if(session->stack->s_nua == NULL) {
1058
                                        /* Start the thread first */
1059
                                        GError *error = NULL;
1060
                                        g_thread_try_new("worker", janus_sip_sofia_thread, session, &error);
1061
                                        if(error != NULL) {
1062
                                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SIP Sofia thread...\n", error->code, error->message ? error->message : "??");
1063
                                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1064
                                                g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the SIP Sofia thread", error->code, error->message ? error->message : "??");
1065
                                                goto error;
1066
                                        }
1067
                                        long int timeout = 0;
1068
                                        while(session->stack->s_nua == NULL) {
1069
                                                g_usleep(100000);
1070
                                                timeout += 100000;
1071
                                                if(timeout >= 2000000) {
1072
                                                        break;
1073
                                                }
1074
                                        }
1075
                                        if(timeout >= 2000000) {
1076
                                                JANUS_LOG(LOG_ERR, "Two seconds passed and still no NUA, problems with the thread?\n");
1077
                                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1078
                                                g_snprintf(error_cause, 512, "Two seconds passed and still no NUA, problems with the thread?");
1079
                                                goto error;
1080
                                        }
1081
                                }
1082
                                if(session->stack->s_nh_r != NULL)
1083
                                        nua_handle_destroy(session->stack->s_nh_r);
1084
                                session->stack->s_nh_r = nua_handle(session->stack->s_nua, session, TAG_END());
1085
                                if(session->stack->s_nh_r == NULL) {
1086
                                        JANUS_LOG(LOG_ERR, "NUA Handle for REGISTER still null??\n");
1087
                                        error_code = JANUS_SIP_ERROR_LIBSOFIA_ERROR;
1088
                                        g_snprintf(error_cause, 512, "Invalid NUA Handle");
1089
                                        goto error;
1090
                                }
1091
                                JANUS_LOG(LOG_VERB, "%s --> %s\n", username_text, proxy_text);
1092
                                nua_register(session->stack->s_nh_r,
1093
                                        NUTAG_M_DISPLAY(g_strdup(session->account.username)),
1094
                                        NUTAG_M_USERNAME(g_strdup(session->account.username)),
1095
                                        SIPTAG_FROM_STR(g_strdup(username_text)),
1096
                                        SIPTAG_TO_STR(g_strdup(username_text)),
1097
                                        NUTAG_REGISTRAR(g_strdup(registrar)),
1098
                                        NUTAG_PROXY(g_strdup(proxy_text)),
1099
                                        TAG_END());
1100
                                result = json_object();
1101
                                json_object_set_new(result, "event", json_string("registering"));
1102
                        }
1103
                } else if(!strcasecmp(request_text, "call")) {
1104
                        /* Call another peer */
1105
                        if(session->status >= janus_sip_status_inviting) {
1106
                                JANUS_LOG(LOG_ERR, "Wrong state (already in a call? status=%s)\n", janus_sip_status_string(session->status));
1107
                                error_code = JANUS_SIP_ERROR_WRONG_STATE;
1108
                                g_snprintf(error_cause, 512, "Wrong state (already in a call? status=%s)", janus_sip_status_string(session->status));
1109
                                goto error;
1110
                        }
1111
                        json_t *uri = json_object_get(root, "uri");
1112
                        if(!uri) {
1113
                                JANUS_LOG(LOG_ERR, "Missing element (uri)\n");
1114
                                error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
1115
                                g_snprintf(error_cause, 512, "Missing element (uri)");
1116
                                goto error;
1117
                        }
1118
                        if(!json_is_string(uri)) {
1119
                                JANUS_LOG(LOG_ERR, "Invalid element (uri should be a string)\n");
1120
                                error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
1121
                                g_snprintf(error_cause, 512, "Invalid element (uri should be a string)");
1122
                                goto error;
1123
                        }
1124
                        /* Parse address */
1125
                        const char *uri_text = json_string_value(uri);
1126
                        if(strstr(uri_text, "sip:") != uri_text && !strstr(uri_text, "@")) {
1127
                                JANUS_LOG(LOG_ERR, "Invalid user address %s\n", uri_text);
1128
                                error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
1129
                                g_snprintf(error_cause, 512, "Invalid user address %s\n", uri_text);
1130
                                goto error;
1131
                        }
1132
                        char user_id[256];
1133
                        char user_ip[256];
1134
                        uint16_t user_port = 0;
1135
                        gchar **parts = g_strsplit(uri_text+4, "@", -1);
1136
                        if(parts[0] == NULL || parts[1] == NULL) {
1137
                                g_strfreev(parts);
1138
                                JANUS_LOG(LOG_ERR, "Invalid user address %s\n", uri_text);
1139
                                error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
1140
                                g_snprintf(error_cause, 512, "Invalid user address %s\n", uri_text);
1141
                                goto error;
1142
                        }
1143
                        strncpy(user_id, parts[0], strlen(parts[0]) < 255 ? strlen(parts[0]) : 255);
1144
                        user_id[strlen(parts[0]) < 255 ? strlen(parts[0]) : 255] = '\0';
1145
                        if(strstr(parts[1], ":") == NULL) {
1146
                                strncpy(user_ip, parts[1], strlen(parts[1]) < 255 ? strlen(parts[1]) : 255);
1147
                                user_ip[strlen(parts[1]) < 255 ? strlen(parts[1]) : 255] = '\0';
1148
                                user_port = 5060;
1149
                        } else {
1150
                                gchar **domain = g_strsplit(parts[1], ":", -1);
1151
                                if(domain[0] == NULL || domain[1] == NULL) {
1152
                                        g_strfreev(domain);
1153
                                        JANUS_LOG(LOG_ERR, "Invalid user address %s\n", uri_text);
1154
                                        error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
1155
                                        g_snprintf(error_cause, 512, "Invalid user address %s\n", uri_text);
1156
                                        goto error;
1157
                                }
1158
                                strncpy(user_ip, domain[0], strlen(domain[0]) < 255 ? strlen(domain[0]) : 255);
1159
                                user_ip[strlen(domain[0]) < 255 ? strlen(domain[0]) : 255] = '\0';
1160
                                user_port = atoi(domain[1]);
1161
                                g_strfreev(domain);
1162
                        }
1163
                        g_strfreev(parts);
1164
                        if(user_port == 0) {
1165
                                JANUS_LOG(LOG_ERR, "Invalid user address %s\n", uri_text);
1166
                                error_code = JANUS_SIP_ERROR_INVALID_ADDRESS;
1167
                                g_snprintf(error_cause, 512, "Invalid user address %s\n", uri_text);
1168
                                goto error;
1169
                        }
1170
                        /* Any SDP to handle? if not, something's wrong */
1171
                        if(!msg->sdp) {
1172
                                JANUS_LOG(LOG_ERR, "Missing SDP\n");
1173
                                error_code = JANUS_SIP_ERROR_MISSING_SDP;
1174
                                g_snprintf(error_cause, 512, "Missing SDP");
1175
                                goto error;
1176
                        }
1177
                        JANUS_LOG(LOG_VERB, "%s is calling %s\n", session->account.username, uri_text);
1178
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
1179
                        /* Allocate RTP ports and merge them with the anonymized SDP */
1180
                        if(strstr(msg->sdp, "m=audio")) {
1181
                                JANUS_LOG(LOG_VERB, "Going to negotiate audio...\n");
1182
                                session->media.has_audio = 1;        /* FIXME Maybe we need a better way to signal this */
1183
                        }
1184
                        if(strstr(msg->sdp, "m=video")) {
1185
                                JANUS_LOG(LOG_VERB, "Going to negotiate video...\n");
1186
                                session->media.has_video = 1;        /* FIXME Maybe we need a better way to signal this */
1187
                        }
1188
                        if(janus_sip_allocate_local_ports(session) < 0) {
1189
                                JANUS_LOG(LOG_ERR, "Could not allocate RTP/RTCP ports\n");
1190
                                error_code = JANUS_SIP_ERROR_IO_ERROR;
1191
                                g_snprintf(error_cause, 512, "Could not allocate RTP/RTCP ports");
1192
                                goto error;
1193
                        }
1194
                        char *sdp = g_strdup(msg->sdp);
1195
                        if(sdp == NULL) {
1196
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1197
                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1198
                                g_snprintf(error_cause, 512, "Memory error");
1199
                                goto error;
1200
                        }
1201
                        sdp = janus_string_replace(sdp, "RTP/SAVPF", "RTP/AVP");
1202
                        sdp = janus_string_replace(sdp, "1.1.1.1", local_ip);
1203
                        if(session->media.has_audio) {
1204
                                JANUS_LOG(LOG_VERB, "Setting local audio port: %d\n", session->media.local_audio_rtp_port);
1205
                                char mline[20];
1206
                                g_snprintf(mline, 20, "m=audio %d", session->media.local_audio_rtp_port);
1207
                                sdp = janus_string_replace(sdp, "m=audio 1", mline);
1208
                        }
1209
                        if(session->media.has_video) {
1210
                                JANUS_LOG(LOG_VERB, "Setting local video port: %d\n", session->media.local_video_rtp_port);
1211
                                char mline[20];
1212
                                g_snprintf(mline, 20, "m=video %d", session->media.local_video_rtp_port);
1213
                                sdp = janus_string_replace(sdp, "m=video 1", mline);
1214
                        }
1215
                        /* Send INVITE */
1216
                        if(session->stack->s_nh_i != NULL)
1217
                                nua_handle_destroy(session->stack->s_nh_i);
1218
                        session->stack->s_nh_i = nua_handle(session->stack->s_nua, session, TAG_END());
1219
                        if(session->stack->s_nh_i == NULL) {
1220
                                JANUS_LOG(LOG_WARN, "NUA Handle for INVITE still null??\n");
1221
                                error_code = JANUS_SIP_ERROR_LIBSOFIA_ERROR;
1222
                                g_snprintf(error_cause, 512, "Invalid NUA Handle");
1223
                                goto error;
1224
                        }
1225
                        session->status = janus_sip_status_inviting;
1226
                        nua_invite(session->stack->s_nh_i,
1227
                                SIPTAG_TO_STR(g_strdup(uri_text)),
1228
                                SOATAG_USER_SDP_STR(g_strdup(sdp)),
1229
                                NUTAG_PROXY(g_strdup(session->account.proxy)),
1230
                                TAG_END());
1231
                        g_free(sdp);
1232
                        session->callee = g_strdup(uri_text);
1233
                        /* Send an ack back */
1234
                        result = json_object();
1235
                        json_object_set_new(result, "event", json_string("calling"));
1236
                } else if(!strcasecmp(request_text, "accept")) {
1237
                        if(session->status != janus_sip_status_invited) {
1238
                                JANUS_LOG(LOG_ERR, "Wrong state (not invited? status=%s)\n", janus_sip_status_string(session->status));
1239
                                error_code = JANUS_SIP_ERROR_WRONG_STATE;
1240
                                g_snprintf(error_cause, 512, "Wrong state (not invited? status=%s)", janus_sip_status_string(session->status));
1241
                                goto error;
1242
                        }
1243
                        if(session->callee == NULL) {
1244
                                JANUS_LOG(LOG_ERR, "Wrong state (no caller?)\n");
1245
                                error_code = JANUS_SIP_ERROR_WRONG_STATE;
1246
                                g_snprintf(error_cause, 512, "Wrong state (no caller?)");
1247
                                goto error;
1248
                        }
1249
                        /* Any SDP to handle? if not, something's wrong */
1250
                        if(!msg->sdp) {
1251
                                JANUS_LOG(LOG_ERR, "Missing SDP\n");
1252
                                error_code = JANUS_SIP_ERROR_MISSING_SDP;
1253
                                g_snprintf(error_cause, 512, "Missing SDP");
1254
                                goto error;
1255
                        }
1256
                        /* Accept a call from another peer */
1257
                        JANUS_LOG(LOG_VERB, "We're accepting the call from %s\n", session->callee);
1258
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
1259
                        /* Allocate RTP ports and merge them with the anonymized SDP */
1260
                        if(strstr(msg->sdp, "m=audio")) {
1261
                                JANUS_LOG(LOG_VERB, "Going to negotiate audio...\n");
1262
                                session->media.has_audio = 1;        /* FIXME Maybe we need a better way to signal this */
1263
                        }
1264
                        if(strstr(msg->sdp, "m=video")) {
1265
                                JANUS_LOG(LOG_VERB, "Going to negotiate video...\n");
1266
                                session->media.has_video = 1;        /* FIXME Maybe we need a better way to signal this */
1267
                        }
1268
                        if(janus_sip_allocate_local_ports(session) < 0) {
1269
                                JANUS_LOG(LOG_ERR, "Could not allocate RTP/RTCP ports\n");
1270
                                error_code = JANUS_SIP_ERROR_IO_ERROR;
1271
                                g_snprintf(error_cause, 512, "Could not allocate RTP/RTCP ports");
1272
                                goto error;
1273
                        }
1274
                        char *sdp = g_strdup(msg->sdp);
1275
                        if(sdp == NULL) {
1276
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1277
                                error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
1278
                                g_snprintf(error_cause, 512, "Memory error");
1279
                                goto error;
1280
                        }
1281
                        sdp = janus_string_replace(sdp, "RTP/SAVPF", "RTP/AVP");
1282
                        sdp = janus_string_replace(sdp, "1.1.1.1", local_ip);
1283
                        if(session->media.has_audio) {
1284
                                JANUS_LOG(LOG_VERB, "Setting local audio port: %d\n", session->media.local_audio_rtp_port);
1285
                                char mline[20];
1286
                                g_snprintf(mline, 20, "m=audio %d", session->media.local_audio_rtp_port);
1287
                                sdp = janus_string_replace(sdp, "m=audio 1", mline);
1288
                        }
1289
                        if(session->media.has_video) {
1290
                                JANUS_LOG(LOG_VERB, "Setting local video port: %d\n", session->media.local_video_rtp_port);
1291
                                char mline[20];
1292
                                g_snprintf(mline, 20, "m=video %d", session->media.local_video_rtp_port);
1293
                                sdp = janus_string_replace(sdp, "m=video 1", mline);
1294
                        }
1295
                        /* Send 200 OK */
1296
                        session->status = janus_sip_status_incall;
1297
                        if(session->stack->s_nh_i == NULL) {
1298
                                JANUS_LOG(LOG_WARN, "NUA Handle for 200 OK still null??\n");
1299
                        }
1300
                        nua_respond(session->stack->s_nh_i,
1301
                                200, sip_status_phrase(200),
1302
                                SIPTAG_TO_STR(g_strdup(session->callee)),
1303
                                SOATAG_USER_SDP_STR(g_strdup(sdp)),
1304
                                TAG_END());
1305
                        g_free(sdp);
1306
                        /* Send an ack back */
1307
                        result = json_object();
1308
                        json_object_set_new(result, "event", json_string("accepted"));
1309
                        /* Start the media */
1310
                        session->media.ready = 1;        /* FIXME Maybe we need a better way to signal this */
1311
                        GError *error = NULL;
1312
                        g_thread_try_new("janus rtp handler", janus_sip_relay_thread, session, &error);
1313
                        if(error != NULL) {
1314
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
1315
                        }
1316
                } else if(!strcasecmp(request_text, "decline")) {
1317
                        /* Reject an incoming call */
1318
                        if(session->status != janus_sip_status_invited) {
1319
                                JANUS_LOG(LOG_ERR, "Wrong state (not invited? status=%s)\n", janus_sip_status_string(session->status));
1320
                                /* Ignore */
1321
                                json_decref(root);
1322
                                continue;
1323
                                //~ g_snprintf(error_cause, 512, "Wrong state (not in a call?)");
1324
                                //~ goto error;
1325
                        }
1326
                        if(session->callee == NULL) {
1327
                                JANUS_LOG(LOG_ERR, "Wrong state (no callee?)\n");
1328
                                error_code = JANUS_SIP_ERROR_WRONG_STATE;
1329
                                g_snprintf(error_cause, 512, "Wrong state (no callee?)");
1330
                                goto error;
1331
                        }
1332
                        session->status = janus_sip_status_registered;        /* FIXME */
1333
                        if(session->stack->s_nh_i == NULL) {
1334
                                JANUS_LOG(LOG_WARN, "NUA Handle for 200 OK still null??\n");
1335
                        }
1336
                        nua_respond(session->stack->s_nh_i, 603, sip_status_phrase(603), TAG_END());
1337
                        g_free(session->callee);
1338
                        session->callee = NULL;
1339
                        /* Notify the operation */
1340
                        result = json_object();
1341
                        json_object_set_new(result, "event", json_string("ack"));
1342
                } else if(!strcasecmp(request_text, "hangup")) {
1343
                        /* Hangup an ongoing call */
1344
                        if(session->status < janus_sip_status_inviting || session->status > janus_sip_status_incall) {
1345
                                JANUS_LOG(LOG_ERR, "Wrong state (not in a call? status=%s)\n", janus_sip_status_string(session->status));
1346
                                /* Ignore */
1347
                                json_decref(root);
1348
                                continue;
1349
                                //~ g_snprintf(error_cause, 512, "Wrong state (not in a call?)");
1350
                                //~ goto error;
1351
                        }
1352
                        if(session->callee == NULL) {
1353
                                JANUS_LOG(LOG_ERR, "Wrong state (no callee?)\n");
1354
                                error_code = JANUS_SIP_ERROR_WRONG_STATE;
1355
                                g_snprintf(error_cause, 512, "Wrong state (no callee?)");
1356
                                goto error;
1357
                        }
1358
                        session->status = janus_sip_status_closing;
1359
                        nua_bye(session->stack->s_nh_i,
1360
                                SIPTAG_TO_STR(g_strdup(session->callee)),
1361
                                TAG_END());
1362
                        g_free(session->callee);
1363
                        session->callee = NULL;
1364
                        /* Notify the operation */
1365
                        result = json_object();
1366
                        json_object_set_new(result, "event", json_string("hangingup"));
1367
                } else {
1368
                        JANUS_LOG(LOG_ERR, "Unknown request (%s)\n", request_text);
1369
                        error_code = JANUS_SIP_ERROR_INVALID_REQUEST;
1370
                        g_snprintf(error_cause, 512, "Unknown request (%s)", request_text);
1371
                        goto error;
1372
                }
1373

    
1374
                json_decref(root);
1375
                /* Prepare JSON event */
1376
                json_t *event = json_object();
1377
                json_object_set_new(event, "sip", json_string("event"));
1378
                if(result != NULL)
1379
                        json_object_set(event, "result", result);
1380
                char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1381
                json_decref(event);
1382
                if(result != NULL)
1383
                        json_decref(result);
1384
                JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
1385
                int ret = gateway->push_event(msg->handle, &janus_sip_plugin, msg->transaction, event_text, sdp_type, sdp);
1386
                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1387
                g_free(event_text);
1388
                if(sdp)
1389
                        g_free(sdp);
1390
                janus_sip_message_free(msg);
1391
                continue;
1392
                
1393
error:
1394
                {
1395
                        if(root != NULL)
1396
                                json_decref(root);
1397
                        /* Prepare JSON error event */
1398
                        json_t *event = json_object();
1399
                        json_object_set_new(event, "sip", json_string("event"));
1400
                        json_object_set_new(event, "error_code", json_integer(error_code));
1401
                        json_object_set_new(event, "error", json_string(error_cause));
1402
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1403
                        json_decref(event);
1404
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
1405
                        int ret = gateway->push_event(msg->handle, &janus_sip_plugin, msg->transaction, event_text, NULL, NULL);
1406
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1407
                        g_free(event_text);
1408
                        janus_sip_message_free(msg);
1409
                }
1410
        }
1411
        g_free(error_cause);
1412
        JANUS_LOG(LOG_VERB, "Leaving SIP handler thread\n");
1413
        return NULL;
1414
}
1415

    
1416

    
1417
/* Sofia callbacks */
1418
void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[])
1419
{
1420
        janus_sip_session *session = (janus_sip_session *)magic;
1421
        ssip_t *ssip = session->stack;
1422
    switch (event) {
1423
        /* Status or Error Indications */
1424
                case nua_i_active:
1425
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1426
                        break;
1427
                case nua_i_error:
1428
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1429
                        break;
1430
                case nua_i_fork:
1431
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1432
                        break;
1433
                case nua_i_media_error:
1434
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1435
                        break;
1436
                case nua_i_subscription:
1437
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1438
                        break;
1439
                case nua_i_state:
1440
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1441
                        break;
1442
                case nua_i_terminated:
1443
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1444
                        break;
1445
        /* SIP requests */
1446
                case nua_i_ack:
1447
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1448
                        break;
1449
                case nua_i_outbound:
1450
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1451
                        break;
1452
                case nua_i_bye: {
1453
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1454
                        /* Call ended, notify the browser */
1455
                        session->status = janus_sip_status_registered;        /* FIXME What about a 'closing' state? */
1456
                        char reason[100];
1457
                        memset(reason, 0, 100);
1458
                        g_snprintf(reason, 100, "%d %s", status, phrase);
1459
                        json_t *call = json_object();
1460
                        json_object_set_new(call, "sip", json_string("event"));
1461
                        json_t *calling = json_object();
1462
                        json_object_set_new(calling, "event", json_string("hangup"));
1463
                        json_object_set_new(calling, "username", json_string(session->callee));
1464
                        json_object_set_new(calling, "reason", json_string(reason));
1465
                        json_object_set_new(call, "result", calling);
1466
                        char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1467
                        json_decref(call);
1468
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", call_text);
1469
                        int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, NULL, NULL);
1470
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1471
                        g_free(call_text);
1472
                        /* Get rid of any PeerConnection that may have been set up in the meanwhile */
1473
                        gateway->close_pc(session->handle);
1474
                        break;
1475
                }
1476
                case nua_i_cancel: {
1477
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1478
                        /* FIXME Check state? */
1479
                        session->status = janus_sip_status_registered;        /* FIXME What about a 'closing' state? */
1480
                        /* Notify the browser */
1481
                        json_t *call = json_object();
1482
                        json_object_set_new(call, "sip", json_string("event"));
1483
                        json_t *calling = json_object();
1484
                        json_object_set_new(calling, "event", json_string("hangup"));
1485
                        json_object_set_new(calling, "username", json_string(session->callee));
1486
                        json_object_set_new(calling, "reason", json_string("Remote cancel"));
1487
                        json_object_set_new(call, "result", calling);
1488
                        char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1489
                        json_decref(call);
1490
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", call_text);
1491
                        int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, NULL, NULL);
1492
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1493
                        g_free(call_text);
1494
                        /* Get rid of any PeerConnection that may have been set up in the meanwhile */
1495
                        gateway->close_pc(session->handle);
1496
                        break;
1497
                }
1498
                case nua_i_chat:
1499
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1500
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1501
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1502
                        break;
1503
                case nua_i_info:
1504
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1505
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1506
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1507
                        break;
1508
                case nua_i_invite: {
1509
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1510
                        sdp_parser_t *parser = sdp_parse(ssip->s_home, sip->sip_payload->pl_data, sip->sip_payload->pl_len, 0);
1511
                        if (!sdp_session(parser)) {
1512
                                JANUS_LOG(LOG_ERR, "\tError parsing SDP!\n");
1513
                                nua_respond(nh, 488, sip_status_phrase(488), TAG_END());
1514
                                break;
1515
                        }
1516
                        if(session->status >= janus_sip_status_inviting) {
1517
                                /* Busy */
1518
                                JANUS_LOG(LOG_VERB, "\tAlready in a call (busy, status=%s)\n", janus_sip_status_string(session->status));
1519
                                nua_respond(nh, 486, sip_status_phrase(486), TAG_END());
1520
                                break;
1521
                        }
1522
                        const char *caller = sip->sip_from->a_url->url_user;
1523
                        session->callee = g_strdup(url_as_string(session->stack->s_home, sip->sip_from->a_url));
1524
                        session->status = janus_sip_status_invited;
1525
                        /* Parse SDP */
1526
                        char *fixed_sdp = g_strdup(sip->sip_payload->pl_data);
1527
                        if(fixed_sdp == NULL) {
1528
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1529
                                nua_respond(nh, 500, sip_status_phrase(500), TAG_END());
1530
                                break;
1531
                        }
1532
                        JANUS_LOG(LOG_VERB, "Someone is inviting us in a call:\n%s", sip->sip_payload->pl_data);
1533
                        sdp_session_t *sdp = sdp_session(parser);
1534
                        janus_sip_sdp_process(session, sdp);
1535
                        /* Send SDP to the browser */
1536
                        json_t *call = json_object();
1537
                        json_object_set_new(call, "sip", json_string("event"));
1538
                        json_t *calling = json_object();
1539
                        json_object_set_new(calling, "event", json_string("incomingcall"));
1540
                        json_object_set_new(calling, "username", json_string(caller));
1541
                        json_object_set_new(call, "result", calling);
1542
                        char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1543
                        json_decref(call);
1544
                        JANUS_LOG(LOG_VERB, "Pushing event to peer: %s\n", call_text);
1545
                        int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, "offer", sip->sip_payload->pl_data);
1546
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1547
                        g_free(call_text);
1548
                        /* Send a Ringing back */
1549
                        nua_respond(nh, 180, sip_status_phrase(180), TAG_END());
1550
                        session->stack->s_nh_i = nh;
1551
                        break;
1552
                }
1553
                case nua_i_message:
1554
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1555
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1556
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1557
                        break;
1558
                case nua_i_method:
1559
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1560
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1561
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1562
                        break;
1563
                case nua_i_notify:
1564
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1565
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1566
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1567
                        break;
1568
                case nua_i_options:
1569
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1570
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1571
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1572
                        break;
1573
                case nua_i_prack:
1574
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1575
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1576
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1577
                        break;
1578
                case nua_i_publish:
1579
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1580
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1581
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1582
                        break;
1583
                case nua_i_refer:
1584
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1585
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1586
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1587
                        break;
1588
                case nua_i_register:
1589
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1590
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1591
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1592
                        break;
1593
                case nua_i_subscribe:
1594
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1595
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1596
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1597
                        break;
1598
                case nua_i_update:
1599
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1600
                        /* FIXME Should we handle this message? for now we reply with a 405 Method Not Implemented */
1601
                        nua_respond(nh, 405, sip_status_phrase(405), TAG_END());
1602
                        break;
1603
        /* Responses */
1604
                case nua_r_get_params:
1605
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1606
                        break;
1607
                case nua_r_set_params:
1608
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1609
                        break;
1610
                case nua_r_notifier:
1611
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1612
                        break;
1613
                case nua_r_shutdown:
1614
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1615
                        if (status < 200 && stopping < 3) {
1616
                                /* shutdown in progress -> return */
1617
                                break;
1618
                        }
1619
                        /* end the event loop. su_root_run() will return */
1620
                        su_root_break(ssip->s_root);
1621
                        break;
1622
                case nua_r_terminate:
1623
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1624
                        break;
1625
        /* SIP responses */
1626
                case nua_r_bye:
1627
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1628
                        /* Call ended, notify the browser */
1629
                        session->status = janus_sip_status_registered;
1630
                        char reason[100];
1631
                        memset(reason, 0, 100);
1632
                        g_snprintf(reason, 100, "%d %s", status, phrase);
1633
                        json_t *call = json_object();
1634
                        json_object_set_new(call, "sip", json_string("event"));
1635
                        json_t *calling = json_object();
1636
                        json_object_set_new(calling, "event", json_string("hangup"));
1637
                        json_object_set_new(calling, "username", json_string(session->callee));
1638
                        json_object_set_new(calling, "reason", json_string("Bye"));
1639
                        json_object_set_new(call, "result", calling);
1640
                        char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1641
                        json_decref(call);
1642
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", call_text);
1643
                        int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, NULL, NULL);
1644
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1645
                        g_free(call_text);
1646
                        /* Get rid of any PeerConnection that may have been set up in the meanwhile */
1647
                        gateway->close_pc(session->handle);
1648
                        break;
1649
                case nua_r_cancel:
1650
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1651
                        break;
1652
                case nua_r_info:
1653
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1654
                        break;
1655
                case nua_r_invite: {
1656
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1657
                        if(status < 200) {
1658
                                /* Not ready yet (FIXME May this be pranswer?? we don't handle it yet...) */
1659
                                break;
1660
                        } else if(status == 401) {
1661
                                 /* Get scheme/realm from 401 error */
1662
                                sip_www_authenticate_t const* www_auth = sip->sip_www_authenticate;
1663
                                char const* scheme = www_auth->au_scheme;
1664
                                const char* realm = msg_params_find(www_auth->au_params, "realm=");
1665
                                char auth[100];
1666
                                memset(auth, 0, 100);
1667
                                g_snprintf(auth, 100, "%s:%s:%s:%s", scheme, realm,
1668
                                        session->account.username ? session->account.username : "null",
1669
                                        session->account.secret ? session->account.secret : "null");
1670
                                JANUS_LOG(LOG_VERB, "\t%s\n", auth);
1671
                                /* Authenticate */
1672
                                nua_authenticate(nh,
1673
                                        NUTAG_AUTH(auth),
1674
                                        TAG_END());
1675
                                break;
1676
                        } else if(status == 407) {
1677
                                 /* Get scheme/realm from 407 error, proxy-auth */
1678
                                sip_proxy_authenticate_t const* proxy_auth = sip->sip_proxy_authenticate;
1679
                                char const* scheme = proxy_auth->au_scheme;
1680
                                const char* realm = msg_params_find(proxy_auth->au_params, "realm=");
1681
                                char auth[100];
1682
                                memset(auth, 0, 100);
1683
                                g_snprintf(auth, 100, "%s:%s:%s:%s", scheme, realm,
1684
                                        session->account.username ? session->account.username : "null",
1685
                                        session->account.secret ? session->account.secret : "null");
1686
                                JANUS_LOG(LOG_VERB, "\t%s\n", auth);
1687
                                /* Authenticate */
1688
                                nua_authenticate(nh,
1689
                                        NUTAG_AUTH(auth),
1690
                                        TAG_END());
1691
                                break;
1692
                        } else if(status >= 400) {
1693
                                /* Something went wrong, notify the browser */
1694
                                session->status = janus_sip_status_registered;
1695
                                char reason[100];
1696
                                memset(reason, 0, 100);
1697
                                g_snprintf(reason, 100, "%d %s", status, phrase);
1698
                                json_t *call = json_object();
1699
                                json_object_set_new(call, "sip", json_string("event"));
1700
                                json_t *calling = json_object();
1701
                                json_object_set_new(calling, "event", json_string("hangup"));
1702
                                json_object_set_new(calling, "username", json_string(session->callee));
1703
                                json_object_set_new(calling, "reason", json_string(reason));
1704
                                json_object_set_new(call, "result", calling);
1705
                                char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1706
                                json_decref(call);
1707
                                JANUS_LOG(LOG_VERB, "Pushing event: %s\n", call_text);
1708
                                int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, NULL, NULL);
1709
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1710
                                g_free(call_text);
1711
                                /* Get rid of any PeerConnection that may have been set up in the meanwhile */
1712
                                gateway->close_pc(session->handle);
1713
                                break;
1714
                        }
1715
                        ssip_t *ssip = session->stack;
1716
                        sdp_parser_t *parser = sdp_parse(ssip->s_home, sip->sip_payload->pl_data, sip->sip_payload->pl_len, 0);
1717
                        if (!sdp_session(parser)) {
1718
                                JANUS_LOG(LOG_ERR, "\tError parsing SDP!\n");
1719
                                nua_respond(nh, 488, sip_status_phrase(488), TAG_END());
1720
                                break;
1721
                        }
1722
                        JANUS_LOG(LOG_VERB, "Peer accepted our call:\n%s", sip->sip_payload->pl_data);
1723
                        session->status = janus_sip_status_incall;
1724
                        char *fixed_sdp = g_strdup(sip->sip_payload->pl_data);
1725
                        if(fixed_sdp == NULL) {
1726
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1727
                                nua_respond(nh, 500, sip_status_phrase(500), TAG_END());
1728
                                break;
1729
                        }
1730
                        sdp_session_t *sdp = sdp_session(parser);
1731
                        janus_sip_sdp_process(session, sdp);
1732
                        session->media.ready = 1;        /* FIXME Maybe we need a better way to signal this */
1733
                        GError *error = NULL;
1734
                        g_thread_try_new("janus rtp handler", janus_sip_relay_thread, session, &error);
1735
                        if(error != NULL) {
1736
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
1737
                        }
1738
                        /* Send SDP to the browser */
1739
                        session->status = janus_sip_status_incall;
1740
                        json_t *call = json_object();
1741
                        json_object_set_new(call, "sip", json_string("event"));
1742
                        json_t *calling = json_object();
1743
                        json_object_set_new(calling, "event", json_string("accepted"));
1744
                        json_object_set_new(calling, "username", json_string(session->callee));
1745
                        json_object_set_new(call, "result", calling);
1746
                        char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1747
                        json_decref(call);
1748
                        JANUS_LOG(LOG_VERB, "Pushing event to peer: %s\n", call_text);
1749
                        int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, "answer", fixed_sdp);
1750
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1751
                        g_free(call_text);
1752
                        break;
1753
                }
1754
                case nua_r_message:
1755
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1756
                        break;
1757
                case nua_r_notify:
1758
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1759
                        break;
1760
                case nua_r_options:
1761
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1762
                        break;
1763
                case nua_r_prack:
1764
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1765
                        break;
1766
                case nua_r_publish:
1767
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1768
                        break;
1769
                case nua_r_refer:
1770
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1771
                        break;
1772
                case nua_r_register: {
1773
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1774
                        if(status == 200) {
1775
                                if(session->status < janus_sip_status_registered)
1776
                                        session->status = janus_sip_status_registered;
1777
                                JANUS_LOG(LOG_VERB, "Successfully registered\n");
1778
                                /* Notify the browser */
1779
                                json_t *call = json_object();
1780
                                json_object_set_new(call, "sip", json_string("event"));
1781
                                json_t *calling = json_object();
1782
                                json_object_set_new(calling, "event", json_string("registered"));
1783
                                json_object_set_new(calling, "username", json_string(session->account.username));
1784
                                json_object_set_new(call, "result", calling);
1785
                                char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1786
                                json_decref(call);
1787
                                JANUS_LOG(LOG_VERB, "Pushing event: %s\n", call_text);
1788
                                int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, call_text, NULL, NULL);
1789
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1790
                                g_free(call_text);
1791
                        } else if(status == 401) {
1792
                                /* Get scheme/realm from 401 error */
1793
                                sip_www_authenticate_t const* www_auth = sip->sip_www_authenticate;
1794
                                char const* scheme = www_auth->au_scheme;
1795
                                const char* realm = msg_params_find(www_auth->au_params, "realm=");
1796
                                char auth[100];
1797
                                memset(auth, 0, 100);
1798
                                g_snprintf(auth, 100, "%s:%s:%s:%s", scheme, realm, session->account.username, session->account.secret);
1799
                                JANUS_LOG(LOG_VERB, "\t%s\n", auth);
1800
                                /* Authenticate */
1801
                                nua_authenticate(nh,
1802
                                        NUTAG_AUTH(auth),
1803
                                        TAG_END());
1804
                        } else if(status >= 400) {
1805
                                /* Authentication failed? */
1806
                                session->status = janus_sip_status_failed;
1807
                                /* Tell the browser... */
1808
                                json_t *event = json_object();
1809
                                json_object_set_new(event, "sip", json_string("event"));
1810
                                char error_cause[256];
1811
                                g_snprintf(error_cause, 512, "Registration failed: %d %s", status, phrase ? phrase : "??");
1812
                                json_object_set_new(event, "error", json_string(error_cause));
1813
                                char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1814
                                json_decref(event);
1815
                                JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
1816
                                int ret = gateway->push_event(session->handle, &janus_sip_plugin, NULL, event_text, NULL, NULL);
1817
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1818
                                g_free(event_text);
1819
                        }
1820
                        break;
1821
                }
1822
                case nua_r_subscribe:
1823
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1824
                        break;
1825
                case nua_r_unpublish:
1826
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1827
                        break;
1828
                case nua_r_unregister:
1829
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1830
                        break;
1831
                case nua_r_unsubscribe:
1832
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1833
                        break;
1834
                case nua_r_update:
1835
                        JANUS_LOG(LOG_VERB, "[%s]: %d %s\n", nua_event_name(event), status, phrase ? phrase : "??");
1836
                        break;
1837
                default:
1838
                        /* unknown event -> print out error message */
1839
                        JANUS_LOG(LOG_ERR, "Unknown event %d (%s)\n", event, nua_event_name(event));
1840
                        break;
1841
        }
1842
}
1843

    
1844
void janus_sip_sdp_process(janus_sip_session *session, sdp_session_t *sdp) {
1845
        if(!session || !sdp)
1846
                return;
1847
        /* c= */
1848
        if(sdp->sdp_connection && sdp->sdp_connection->c_address) {
1849
                if(session->media.remote_ip != NULL)
1850
                        g_free(session->media.remote_ip);
1851
                session->media.remote_ip = g_strdup(sdp->sdp_connection->c_address);
1852
                JANUS_LOG(LOG_VERB, "  >> Media connection:\n");
1853
                JANUS_LOG(LOG_VERB, "       %s\n", session->media.remote_ip);
1854
        }
1855
        JANUS_LOG(LOG_VERB, "  >> Media lines:\n");
1856
        sdp_media_t *m = sdp->sdp_media;
1857
        while(m) {
1858
                if(m->m_type == sdp_media_audio) {
1859
                        JANUS_LOG(LOG_VERB, "       Audio: %lu\n", m->m_port);
1860
                        if(m->m_port) {
1861
                                session->media.has_audio = 1;
1862
                                session->media.remote_audio_rtp_port = m->m_port;
1863
                                session->media.remote_audio_rtcp_port = m->m_port+1;        /* FIXME We're assuming RTCP is on the next port */
1864
                        }
1865
                } else if(m->m_type == sdp_media_video) {
1866
                        JANUS_LOG(LOG_VERB, "       Video: %lu\n", m->m_port);
1867
                        if(m->m_port) {
1868
                                session->media.has_video = 1;
1869
                                session->media.remote_video_rtp_port = m->m_port;
1870
                                session->media.remote_video_rtcp_port = m->m_port+1;        /* FIXME We're assuming RTCP is on the next port */
1871
                        }
1872
                } else {
1873
                        JANUS_LOG(LOG_WARN, "       Unsupported media line (not audio/video)\n");
1874
                        m = m->m_next;
1875
                        continue;
1876
                }
1877
                JANUS_LOG(LOG_VERB, "       Media connections:\n");
1878
                if(m->m_connections) {
1879
                        sdp_connection_t *c = m->m_connections;
1880
                        while(c) {
1881
                                if(c->c_address) {
1882
                                        if(session->media.remote_ip != NULL)
1883
                                                g_free(session->media.remote_ip);
1884
                                        session->media.remote_ip = g_strdup(c->c_address);
1885
                                        JANUS_LOG(LOG_VERB, "         [%s]\n", session->media.remote_ip);
1886
                                }
1887
                                c = c->c_next;
1888
                        }
1889
                }
1890
                JANUS_LOG(LOG_VERB, "       Media RTP maps:\n");
1891
                sdp_rtpmap_t *r = m->m_rtpmaps;
1892
                while(r) {
1893
                        JANUS_LOG(LOG_VERB, "         [%u] %s\n", r->rm_pt, r->rm_encoding);
1894
                        r = r->rm_next;
1895
                }
1896
                JANUS_LOG(LOG_VERB, "       Media attributes:\n");
1897
                sdp_attribute_t *a = m->m_attributes;
1898
                while(a) {
1899
                        if(a->a_name) {
1900
                                if(!strcasecmp(a->a_name, "rtpmap")) {
1901
                                        JANUS_LOG(LOG_VERB, "         RTP Map:     %s\n", a->a_value);
1902
                                }
1903
                        }
1904
                        a = a->a_next;
1905
                }
1906
                m = m->m_next;
1907
        }
1908
}
1909

    
1910
/* Bind local RTP/RTCP sockets */
1911
static int janus_sip_allocate_local_ports(janus_sip_session *session) {
1912
        if(session == NULL) {
1913
                JANUS_LOG(LOG_ERR, "Invalid session\n");
1914
                return -1;
1915
        }
1916
        //~ /* Reset status */
1917
        //~ session->media.ready = 0;
1918
        //~ session->media.has_audio = 0;
1919
        //~ session->media.audio_rtp_fd = 0;
1920
        //~ session->media.audio_rtcp_fd= 0;
1921
        //~ session->media.local_audio_rtp_port = 0;
1922
        //~ session->media.remote_audio_rtp_port = 0;
1923
        //~ session->media.local_audio_rtcp_port = 0;
1924
        //~ session->media.remote_audio_rtcp_port = 0;
1925
        //~ session->media.has_video = 0;
1926
        //~ session->media.video_rtp_fd = 0;
1927
        //~ session->media.video_rtcp_fd= 0;
1928
        //~ session->media.local_video_rtp_port = 0;
1929
        //~ session->media.remote_video_rtp_port = 0;
1930
        //~ session->media.local_video_rtcp_port = 0;
1931
        //~ session->media.remote_video_rtcp_port = 0;
1932
        /* Start */
1933
        int attempts = 100;        /* FIXME Don't retry forever */
1934
        if(session->media.has_audio) {
1935
                JANUS_LOG(LOG_VERB, "Allocating audio ports:\n");
1936
                struct sockaddr_in audio_rtp_address, audio_rtcp_address;
1937
                int yes = 1;        /* For setsockopt() SO_REUSEADDR */
1938
                while(session->media.local_audio_rtp_port == 0 || session->media.local_audio_rtcp_port == 0) {
1939
                        if(attempts == 0)        /* Too many failures */
1940
                                return -1;
1941
                        if(session->media.audio_rtp_fd == 0) {
1942
                                yes = 1;
1943
                                session->media.audio_rtp_fd = socket(AF_INET, SOCK_DGRAM, 0);
1944
                                setsockopt(session->media.audio_rtp_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
1945
                        }
1946
                        if(session->media.audio_rtcp_fd == 0) {
1947
                                yes = 1;
1948
                                session->media.audio_rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0);
1949
                                setsockopt(session->media.audio_rtcp_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
1950
                        }
1951
                        int rtp_port = g_random_int_range(10000, 60000);        /* FIXME Should this be configurable? */
1952
                        if(rtp_port % 2)
1953
                                rtp_port++;        /* Pick an even port for RTP */
1954
                        audio_rtp_address.sin_family = AF_INET;
1955
                        audio_rtp_address.sin_port = htons(rtp_port);
1956
                        audio_rtp_address.sin_addr.s_addr = INADDR_ANY;
1957
                        if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), sizeof(struct sockaddr)) < 0) {
1958
                                JANUS_LOG(LOG_ERR, "Bind failed for audio RTP (port %d), trying a different one...\n", rtp_port);
1959
                                attempts--;
1960
                                continue;
1961
                        }
1962
                        JANUS_LOG(LOG_VERB, "Audio RTP listener bound to port %d\n", rtp_port);
1963
                        int rtcp_port = rtp_port+1;
1964
                        audio_rtcp_address.sin_family = AF_INET;
1965
                        audio_rtcp_address.sin_port = htons(rtcp_port);
1966
                        audio_rtcp_address.sin_addr.s_addr = INADDR_ANY;
1967
                        if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), sizeof(struct sockaddr)) < 0) {
1968
                                JANUS_LOG(LOG_ERR, "Bind failed for audio RTCP (port %d), trying a different one...\n", rtcp_port);
1969
                                /* RTP socket is not valid anymore, reset it */
1970
                                close(session->media.audio_rtp_fd);
1971
                                session->media.audio_rtp_fd = 0;
1972
                                attempts--;
1973
                                continue;
1974
                        }
1975
                        JANUS_LOG(LOG_VERB, "Audio RTCP listener bound to port %d\n", rtcp_port);
1976
                        session->media.local_audio_rtp_port = rtp_port;
1977
                        session->media.local_audio_rtcp_port = rtcp_port;
1978
                }
1979
        }
1980
        if(session->media.has_video) {
1981
                JANUS_LOG(LOG_VERB, "Allocating video ports:\n");
1982
                struct sockaddr_in video_rtp_address, video_rtcp_address;
1983
                int yes = 1;        /* For setsockopt() SO_REUSEADDR */
1984
                while(session->media.local_video_rtp_port == 0 || session->media.local_video_rtcp_port == 0) {
1985
                        if(attempts == 0)        /* Too many failures */
1986
                                return -1;
1987
                        if(session->media.video_rtp_fd == 0) {
1988
                                yes = 1;
1989
                                session->media.video_rtp_fd = socket(AF_INET, SOCK_DGRAM, 0);
1990
                                setsockopt(session->media.video_rtp_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
1991
                        }
1992
                        if(session->media.video_rtcp_fd == 0) {
1993
                                yes = 1;
1994
                                session->media.video_rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0);
1995
                                setsockopt(session->media.video_rtcp_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
1996
                        }
1997
                        int rtp_port = g_random_int_range(10000, 60000);        /* FIXME Should this be configurable? */
1998
                        if(rtp_port % 2)
1999
                                rtp_port++;        /* Pick an even port for RTP */
2000
                        video_rtp_address.sin_family = AF_INET;
2001
                        video_rtp_address.sin_port = htons(rtp_port);
2002
                        video_rtp_address.sin_addr.s_addr = INADDR_ANY;
2003
                        if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), sizeof(struct sockaddr)) < 0) {
2004
                                JANUS_LOG(LOG_ERR, "Bind failed for video RTP (port %d), trying a different one...\n", rtp_port);
2005
                                attempts--;
2006
                                continue;
2007
                        }
2008
                        JANUS_LOG(LOG_VERB, "Audio RTP listener bound to port %d\n", rtp_port);
2009
                        int rtcp_port = rtp_port+1;
2010
                        video_rtcp_address.sin_family = AF_INET;
2011
                        video_rtcp_address.sin_port = htons(rtcp_port);
2012
                        video_rtcp_address.sin_addr.s_addr = INADDR_ANY;
2013
                        if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), sizeof(struct sockaddr)) < 0) {
2014
                                JANUS_LOG(LOG_ERR, "Bind failed for video RTCP (port %d), trying a different one...\n", rtcp_port);
2015
                                /* RTP socket is not valid anymore, reset it */
2016
                                close(session->media.video_rtp_fd);
2017
                                session->media.video_rtp_fd = 0;
2018
                                attempts--;
2019
                                continue;
2020
                        }
2021
                        JANUS_LOG(LOG_VERB, "Audio RTCP listener bound to port %d\n", rtcp_port);
2022
                        session->media.local_video_rtp_port = rtp_port;
2023
                        session->media.local_video_rtcp_port = rtcp_port;
2024
                }
2025
        }
2026
        return 0;
2027
}
2028

    
2029
/* Thread to relay RTP/RTCP frames coming from the SIP peer */
2030
static void *janus_sip_relay_thread(void *data) {
2031
        janus_sip_session *session = (janus_sip_session *)data;
2032
        if(!session || !session->account.username || !session->callee) {
2033
                g_thread_unref(g_thread_self());
2034
                return NULL;
2035
        }
2036
        JANUS_LOG(LOG_VERB, "Starting relay thread (%s <--> %s)\n", session->account.username, session->callee);
2037
        /* Socket stuff */
2038
        int maxfd = 0;
2039
        if(session->media.audio_rtp_fd > maxfd)
2040
                maxfd = session->media.audio_rtp_fd;
2041
        if(session->media.audio_rtcp_fd > maxfd)
2042
                maxfd = session->media.audio_rtcp_fd;
2043
        if(session->media.video_rtp_fd > maxfd)
2044
                maxfd = session->media.video_rtp_fd;
2045
        if(session->media.video_rtcp_fd > maxfd)
2046
                maxfd = session->media.video_rtcp_fd;
2047
        //~ /* Wait for the remote information */
2048
        //~ while(!session->media.ready) {
2049
                //~ 
2050
        //~ }
2051
        /* Connect peers (FIXME This pretty much sucks right now) */
2052
        if(session->media.remote_audio_rtp_port) {
2053
                struct sockaddr_in server_addr;
2054
                server_addr.sin_family = AF_INET;
2055
                if((inet_aton(session->media.remote_ip, &server_addr.sin_addr)) <= 0) {        /* Not a numeric IP... */
2056
                        struct hostent *host = gethostbyname(session->media.remote_ip);        /* ...resolve name */
2057
                        if(!host) {
2058
                                JANUS_LOG(LOG_ERR, "Couldn't get host (%s)\n", session->media.remote_ip);
2059
                        } else {
2060
                                server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
2061
                        }
2062
                }
2063
                server_addr.sin_port = htons(session->media.remote_audio_rtp_port);
2064
                memset(&(server_addr.sin_zero), '\0', 8);
2065
                if(connect(session->media.audio_rtp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2066
                        JANUS_LOG(LOG_ERR, "Couldn't connect audio RTP? (%s:%d)\n", session->media.remote_ip, session->media.remote_audio_rtp_port);
2067
                        JANUS_LOG(LOG_ERR, "  -- %d (%s)\n", errno, strerror(errno));
2068
                }
2069
        }
2070
        if(session->media.remote_audio_rtcp_port) {
2071
                struct sockaddr_in server_addr;
2072
                server_addr.sin_family = AF_INET;
2073
                if((inet_aton(session->media.remote_ip, &server_addr.sin_addr)) <= 0) {        /* Not a numeric IP... */
2074
                        struct hostent *host = gethostbyname(session->media.remote_ip);        /* ...resolve name */
2075
                        if(!host) {
2076
                                JANUS_LOG(LOG_ERR, "Couldn't get host (%s)\n", session->media.remote_ip);
2077
                        } else {
2078
                                server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
2079
                        }
2080
                }
2081
                server_addr.sin_port = htons(session->media.remote_audio_rtcp_port);
2082
                memset(&(server_addr.sin_zero), '\0', 8);
2083
                if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2084
                        JANUS_LOG(LOG_ERR, "Couldn't connect audio RTCP? (%s:%d)\n", session->media.remote_ip, session->media.remote_audio_rtcp_port);
2085
                        JANUS_LOG(LOG_ERR, "  -- %d (%s)\n", errno, strerror(errno));
2086
                }
2087
        }
2088
        if(session->media.remote_video_rtp_port) {
2089
                struct sockaddr_in server_addr;
2090
                server_addr.sin_family = AF_INET;
2091
                if((inet_aton(session->media.remote_ip, &server_addr.sin_addr)) <= 0) {        /* Not a numeric IP... */
2092
                        struct hostent *host = gethostbyname(session->media.remote_ip);        /* ...resolve name */
2093
                        if(!host) {
2094
                                JANUS_LOG(LOG_ERR, "Couldn't get host (%s)\n", session->media.remote_ip);
2095
                        } else {
2096
                                server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
2097
                        }
2098
                }
2099
                server_addr.sin_port = htons(session->media.remote_video_rtp_port);
2100
                memset(&(server_addr.sin_zero), '\0', 8);
2101
                if(connect(session->media.video_rtp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2102
                        JANUS_LOG(LOG_ERR, "Couldn't connect video RTP? (%s:%d)\n", session->media.remote_ip, session->media.remote_video_rtp_port);
2103
                        JANUS_LOG(LOG_ERR, "  -- %d (%s)\n", errno, strerror(errno));
2104
                }
2105
        }
2106
        if(session->media.remote_video_rtcp_port) {
2107
                struct sockaddr_in server_addr;
2108
                server_addr.sin_family = AF_INET;
2109
                if((inet_aton(session->media.remote_ip, &server_addr.sin_addr)) <= 0) {        /* Not a numeric IP... */
2110
                        struct hostent *host = gethostbyname(session->media.remote_ip);        /* ...resolve name */
2111
                        if(!host) {
2112
                                JANUS_LOG(LOG_ERR, "Couldn't get host (%s)\n", session->media.remote_ip);
2113
                        } else {
2114
                                server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
2115
                        }
2116
                }
2117
                server_addr.sin_port = htons(session->media.remote_video_rtcp_port);
2118
                memset(&(server_addr.sin_zero), '\0', 8);
2119
                if(connect(session->media.video_rtcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2120
                        JANUS_LOG(LOG_ERR, "Couldn't connect video RTCP? (%s:%d)\n", session->media.remote_ip, session->media.remote_video_rtcp_port);
2121
                        JANUS_LOG(LOG_ERR, "  -- %d (%s)\n", errno, strerror(errno));
2122
                }
2123
        }
2124

    
2125
        if(!session->callee) {
2126
                JANUS_LOG(LOG_VERB, "Leaving thread, no callee...\n");
2127
                g_thread_unref(g_thread_self());
2128
                return NULL; 
2129
        }
2130
        /* Loop */
2131
        socklen_t addrlen;
2132
        struct sockaddr_in remote;
2133
        int resfd = 0, bytes = 0;
2134
        struct timeval timeout;
2135
        fd_set readfds;
2136
        FD_ZERO(&readfds);
2137
        char buffer[1500];
2138
        memset(buffer, 0, 1500);
2139
        while(session != NULL && !session->destroyed &&
2140
                        session->status > janus_sip_status_registered &&
2141
                        session->status < janus_sip_status_closing) {        /* FIXME We need a per-call watchdog as well */
2142
                /* Wait for some data */
2143
                if(session->media.audio_rtp_fd > 0)
2144
                        FD_SET(session->media.audio_rtp_fd, &readfds);
2145
                if(session->media.audio_rtcp_fd > 0)
2146
                        FD_SET(session->media.audio_rtcp_fd, &readfds);
2147
                if(session->media.video_rtp_fd > 0)
2148
                        FD_SET(session->media.video_rtp_fd, &readfds);
2149
                if(session->media.video_rtcp_fd > 0)
2150
                        FD_SET(session->media.video_rtcp_fd, &readfds);
2151
                timeout.tv_sec = 1;
2152
                timeout.tv_usec = 0;
2153
                resfd = select(maxfd+1, &readfds, NULL, NULL, &timeout);
2154
                if(resfd < 0)
2155
                        break;
2156
                if(session == NULL || session->destroyed ||
2157
                                session->status <= janus_sip_status_registered ||
2158
                                session->status >= janus_sip_status_closing)
2159
                        break;
2160
                if(session->media.audio_rtp_fd && FD_ISSET(session->media.audio_rtp_fd, &readfds)) {
2161
                        /* Got something audio (RTP) */
2162
                        addrlen = sizeof(remote);
2163
                        bytes = recvfrom(session->media.audio_rtp_fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen);
2164
                        //~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the audio RTP channel...\n", bytes);
2165
                        //~ rtp_header_t *rtp = (rtp_header_t *)buffer;
2166
                        //~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
2167
                                //~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
2168
                        if(session->media.audio_ssrc_peer == 0) {
2169
                                rtp_header *header = (rtp_header *)buffer;
2170
                                session->media.audio_ssrc_peer = ntohl(header->ssrc);
2171
                                JANUS_LOG(LOG_VERB, "Got SIP peer audio SSRC: %"SCNu32"\n", session->media.audio_ssrc_peer);
2172
                        }
2173
                        /* Relay to browser */
2174
                        gateway->relay_rtp(session->handle, 0, buffer, bytes);
2175
                        continue;
2176
                }
2177
                if(session->media.audio_rtcp_fd && FD_ISSET(session->media.audio_rtcp_fd, &readfds)) {
2178
                        /* Got something audio (RTCP) */
2179
                        addrlen = sizeof(remote);
2180
                        bytes = recvfrom(session->media.audio_rtcp_fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen);
2181
                        //~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the audio RTCP channel...\n", bytes);
2182
                        //~ rtp_header_t *rtp = (rtp_header_t *)buffer;
2183
                        //~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
2184
                                //~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
2185
                        /* Relay to browser */
2186
                        gateway->relay_rtcp(session->handle, 0, buffer, bytes);
2187
                        continue;
2188
                }
2189
                if(session->media.video_rtp_fd && FD_ISSET(session->media.video_rtp_fd, &readfds)) {
2190
                        /* Got something video (RTP) */
2191
                        addrlen = sizeof(remote);
2192
                        bytes = recvfrom(session->media.video_rtp_fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen);
2193
                        //~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the video RTP channel...\n", bytes);
2194
                        //~ rtp_header_t *rtp = (rtp_header_t *)buffer;
2195
                        //~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
2196
                                //~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
2197
                        if(session->media.video_ssrc_peer == 0) {
2198
                                rtp_header *header = (rtp_header *)buffer;
2199
                                session->media.video_ssrc_peer = ntohl(header->ssrc);
2200
                                JANUS_LOG(LOG_VERB, "Got SIP peer video SSRC: %"SCNu32"\n", session->media.video_ssrc_peer);
2201
                        }
2202
                        /* Relay to browser */
2203
                        gateway->relay_rtp(session->handle, 1, buffer, bytes);
2204
                        continue;
2205
                }
2206
                if(session->media.video_rtcp_fd && FD_ISSET(session->media.video_rtcp_fd, &readfds)) {
2207
                        /* Got something video (RTCP) */
2208
                        addrlen = sizeof(remote);
2209
                        bytes = recvfrom(session->media.video_rtcp_fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen);
2210
                        //~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the video RTCP channel...\n", bytes);
2211
                        //~ rtp_header_t *rtp = (rtp_header_t *)buffer;
2212
                        //~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
2213
                                //~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
2214
                        /* Relay to browser */
2215
                        gateway->relay_rtcp(session->handle, 1, buffer, bytes);
2216
                        continue;
2217
                }
2218
        }
2219
        JANUS_LOG(LOG_VERB, "Leaving SIP relay thread\n");
2220
        g_thread_unref(g_thread_self());
2221
        return NULL;
2222
}
2223

    
2224

    
2225
/* Sofia Event thread */
2226
gpointer janus_sip_sofia_thread(gpointer user_data) {
2227
        janus_sip_session *session = (janus_sip_session *)user_data;
2228
        if(session == NULL || session->account.username == NULL || session->stack == NULL) {
2229
                g_thread_unref(g_thread_self());
2230
                return NULL;
2231
        }
2232
        JANUS_LOG(LOG_VERB, "Joining sofia loop thread (%s)...\n", session->account.username);
2233
        session->stack->s_root = su_root_create(session->stack);
2234
        char tag_url[100];
2235
        memset(tag_url, 0, 100);
2236
        g_snprintf(tag_url, 100, "sip:%s@0.0.0.0:0", session->account.username);
2237
        JANUS_LOG(LOG_VERB, "Setting up sofia stack (%s)\n", tag_url);
2238
        session->stack->s_nua = nua_create(session->stack->s_root,
2239
                                janus_sip_sofia_callback,
2240
                                session,
2241
                                SIPTAG_FROM_STR(g_strdup(tag_url)),
2242
                                NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
2243
                                //~ NUTAG_OUTBOUND("outbound natify use-rport"),        /* To use the same port used in Contact */
2244
                                // sofia-sip default supported: timer and 100rel
2245
                                // disable 100rel, There are known issues (asserts and segfaults) when 100rel is enabled from freeswitch config comments
2246
                                SIPTAG_SUPPORTED_STR("timer"),
2247
                                TAG_NULL());
2248
        nua_set_params(session->stack->s_nua, TAG_NULL());
2249
        su_root_run(session->stack->s_root);
2250
        /* When we get here, we're done */
2251
        nua_destroy(session->stack->s_nua);
2252
        su_root_destroy(session->stack->s_root);
2253
        session->stack->s_root = NULL;
2254
        su_home_deinit(session->stack->s_home);
2255
        su_deinit();
2256
        //~ stop = 1;
2257
        JANUS_LOG(LOG_VERB, "Leaving sofia loop thread...\n");
2258
        g_thread_unref(g_thread_self());
2259
        return NULL;
2260
}