~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject/pjnath/src/pjturn-srv/allocation.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: allocation.c 3553 2011-05-05 06:14:19Z nanang $ */
2
 
/* 
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19
 
 */
20
 
#include "turn.h"
21
 
#include "auth.h"
22
 
 
23
 
 
24
 
#define THIS_FILE   "allocation.c"
25
 
 
26
 
 
27
 
enum {
28
 
    TIMER_ID_NONE,
29
 
    TIMER_ID_TIMEOUT,
30
 
    TIMER_ID_DESTROY
31
 
};
32
 
 
33
 
#define DESTROY_DELAY       {0, 500}
34
 
#define PEER_TABLE_SIZE     32
35
 
 
36
 
#define MAX_CLIENT_BANDWIDTH    128  /* In Kbps */
37
 
#define DEFA_CLIENT_BANDWIDTH   64
38
 
 
39
 
#define MIN_LIFETIME            30
40
 
#define MAX_LIFETIME            600
41
 
#define DEF_LIFETIME            300
42
 
 
43
 
 
44
 
/* Parsed Allocation request. */
45
 
typedef struct alloc_request
46
 
{
47
 
    unsigned            tp_type;                    /* Requested transport  */
48
 
    char                addr[PJ_INET6_ADDRSTRLEN];  /* Requested IP         */
49
 
    unsigned            bandwidth;                  /* Requested bandwidth  */
50
 
    unsigned            lifetime;                   /* Lifetime.            */
51
 
    unsigned            rpp_bits;                   /* A bits               */
52
 
    unsigned            rpp_port;                   /* Requested port       */
53
 
} alloc_request;
54
 
 
55
 
 
56
 
 
57
 
/* Prototypes */
58
 
static void destroy_allocation(pj_turn_allocation *alloc);
59
 
static pj_status_t create_relay(pj_turn_srv *srv,
60
 
                                pj_turn_allocation *alloc,
61
 
                                const pj_stun_msg *msg,
62
 
                                const alloc_request *req,
63
 
                                pj_turn_relay_res *relay);
64
 
static void destroy_relay(pj_turn_relay_res *relay);
65
 
static void on_rx_from_peer(pj_ioqueue_key_t *key, 
66
 
                            pj_ioqueue_op_key_t *op_key, 
67
 
                            pj_ssize_t bytes_read);
68
 
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
69
 
                                    void *token,
70
 
                                    const void *pkt,
71
 
                                    pj_size_t pkt_size,
72
 
                                    const pj_sockaddr_t *dst_addr,
73
 
                                    unsigned addr_len);
74
 
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
75
 
                                      const pj_uint8_t *pkt,
76
 
                                      unsigned pkt_len,
77
 
                                      const pj_stun_rx_data *rdata,
78
 
                                      void *token,
79
 
                                      const pj_sockaddr_t *src_addr,
80
 
                                      unsigned src_addr_len);
81
 
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
82
 
                                         const pj_uint8_t *pkt,
83
 
                                         unsigned pkt_len,
84
 
                                         const pj_stun_msg *msg,
85
 
                                         void *token,
86
 
                                         const pj_sockaddr_t *src_addr,
87
 
                                         unsigned src_addr_len);
88
 
 
89
 
/* Log allocation error */
90
 
static void alloc_err(pj_turn_allocation *alloc, const char *title,
91
 
                      pj_status_t status)
92
 
{
93
 
    char errmsg[PJ_ERR_MSG_SIZE];
94
 
 
95
 
    pj_strerror(status, errmsg, sizeof(errmsg));
96
 
    PJ_LOG(4,(alloc->obj_name, "%s for client %s: %s",
97
 
              title, alloc->info, errmsg));
98
 
}
99
 
 
100
 
 
101
 
/* Parse ALLOCATE request */
102
 
static pj_status_t parse_allocate_req(alloc_request *cfg,
103
 
                                      pj_stun_session *sess,
104
 
                                      const pj_stun_rx_data *rdata,
105
 
                                      const pj_sockaddr_t *src_addr,
106
 
                                      unsigned src_addr_len)
107
 
{
108
 
    const pj_stun_msg *req = rdata->msg;
109
 
    pj_stun_bandwidth_attr *attr_bw;
110
 
    pj_stun_req_transport_attr *attr_req_tp;
111
 
    pj_stun_res_token_attr *attr_res_token;
112
 
    pj_stun_lifetime_attr *attr_lifetime;
113
 
 
114
 
    pj_bzero(cfg, sizeof(*cfg));
115
 
 
116
 
    /* Get BANDWIDTH attribute, if any. */
117
 
    attr_bw = (pj_stun_uint_attr*)
118
 
              pj_stun_msg_find_attr(req, PJ_STUN_ATTR_BANDWIDTH, 0);
119
 
    if (attr_bw) {
120
 
        cfg->bandwidth = attr_bw->value;
121
 
    } else {
122
 
        cfg->bandwidth = DEFA_CLIENT_BANDWIDTH;
123
 
    }
124
 
 
125
 
    /* Check if we can satisfy the bandwidth */
126
 
    if (cfg->bandwidth > MAX_CLIENT_BANDWIDTH) {
127
 
        pj_stun_session_respond(sess, rdata, 
128
 
                                PJ_STUN_SC_ALLOCATION_QUOTA_REACHED,
129
 
                                "Invalid bandwidth", NULL, PJ_TRUE,
130
 
                                src_addr, src_addr_len);
131
 
        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ALLOCATION_QUOTA_REACHED);
132
 
    }
133
 
 
134
 
    /* MUST have REQUESTED-TRANSPORT attribute */
135
 
    attr_req_tp = (pj_stun_uint_attr*)
136
 
                  pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_TRANSPORT, 0);
137
 
    if (attr_req_tp == NULL) {
138
 
        pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
139
 
                                "Missing REQUESTED-TRANSPORT attribute", 
140
 
                                NULL, PJ_TRUE, src_addr, src_addr_len);
141
 
        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
142
 
    }
143
 
 
144
 
    cfg->tp_type = PJ_STUN_GET_RT_PROTO(attr_req_tp->value);
145
 
 
146
 
    /* Can only support UDP for now */
147
 
    if (cfg->tp_type != PJ_TURN_TP_UDP) {
148
 
        pj_stun_session_respond(sess, rdata, PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO,
149
 
                                NULL, NULL, PJ_TRUE, src_addr, src_addr_len);
150
 
        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO);
151
 
    }
152
 
 
153
 
    /* Get RESERVATION-TOKEN attribute, if any */
154
 
    attr_res_token = (pj_stun_res_token_attr*)
155
 
                     pj_stun_msg_find_attr(req, PJ_STUN_ATTR_RESERVATION_TOKEN,
156
 
                                           0);
157
 
    if (attr_res_token) {
158
 
        /* We don't support RESERVATION-TOKEN for now */
159
 
        pj_stun_session_respond(sess, rdata, 
160
 
                                PJ_STUN_SC_BAD_REQUEST,
161
 
                                "RESERVATION-TOKEN is not supported", NULL, 
162
 
                                PJ_TRUE, src_addr, src_addr_len);
163
 
        return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
164
 
    }
165
 
 
166
 
    /* Get LIFETIME attribute */
167
 
    attr_lifetime = (pj_stun_uint_attr*)
168
 
                    pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
169
 
    if (attr_lifetime) {
170
 
        cfg->lifetime = attr_lifetime->value;
171
 
        if (cfg->lifetime < MIN_LIFETIME) {
172
 
            pj_stun_session_respond(sess, rdata, PJ_STUN_SC_BAD_REQUEST,
173
 
                                    "LIFETIME too short", NULL, 
174
 
                                    PJ_TRUE, src_addr, src_addr_len);
175
 
            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_BAD_REQUEST);
176
 
        }
177
 
        if (cfg->lifetime > MAX_LIFETIME)
178
 
            cfg->lifetime = MAX_LIFETIME;
179
 
    } else {
180
 
        cfg->lifetime = DEF_LIFETIME;
181
 
    }
182
 
 
183
 
    return PJ_SUCCESS;
184
 
}
185
 
 
186
 
 
187
 
/* Respond to ALLOCATE request */
188
 
static pj_status_t send_allocate_response(pj_turn_allocation *alloc,
189
 
                                          pj_stun_session *srv_sess,
190
 
                                          pj_turn_transport *transport,
191
 
                                          const pj_stun_rx_data *rdata)
192
 
{
193
 
    pj_stun_tx_data *tdata;
194
 
    pj_status_t status;
195
 
 
196
 
    /* Respond the original ALLOCATE request */
197
 
    status = pj_stun_session_create_res(srv_sess, rdata, 0, NULL, &tdata);
198
 
    if (status != PJ_SUCCESS)
199
 
        return status;
200
 
 
201
 
    /* Add XOR-RELAYED-ADDRESS attribute */
202
 
    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
203
 
                                  PJ_STUN_ATTR_XOR_RELAYED_ADDR, PJ_TRUE,
204
 
                                  &alloc->relay.hkey.addr,
205
 
                                  pj_sockaddr_get_len(&alloc->relay.hkey.addr));
206
 
 
207
 
    /* Add LIFETIME. */
208
 
    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
209
 
                              PJ_STUN_ATTR_LIFETIME, 
210
 
                              (unsigned)alloc->relay.lifetime);
211
 
 
212
 
    /* Add BANDWIDTH */
213
 
    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
214
 
                              PJ_STUN_ATTR_BANDWIDTH,
215
 
                              alloc->bandwidth);
216
 
 
217
 
    /* Add RESERVATION-TOKEN */
218
 
    PJ_TODO(ADD_RESERVATION_TOKEN);
219
 
 
220
 
    /* Add XOR-MAPPED-ADDRESS */
221
 
    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
222
 
                                  PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
223
 
                                  &alloc->hkey.clt_addr,
224
 
                                  pj_sockaddr_get_len(&alloc->hkey.clt_addr));
225
 
    
226
 
    /* Send the response */
227
 
    return pj_stun_session_send_msg(srv_sess, transport, PJ_TRUE,
228
 
                                    PJ_FALSE, &alloc->hkey.clt_addr, 
229
 
                                    pj_sockaddr_get_len(&alloc->hkey.clt_addr),
230
 
                                    tdata);
231
 
}
232
 
 
233
 
 
234
 
/*
235
 
 * Init credential for the allocation. We use static credential, meaning that
236
 
 * the user's password must not change during allocation.
237
 
 */
238
 
static pj_status_t init_cred(pj_turn_allocation *alloc, const pj_stun_msg *req)
239
 
{
240
 
    const pj_stun_username_attr *user;
241
 
    const pj_stun_realm_attr *realm;
242
 
    const pj_stun_nonce_attr *nonce;
243
 
    pj_status_t status;
244
 
 
245
 
    realm = (const pj_stun_realm_attr*)
246
 
            pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REALM, 0);
247
 
    PJ_ASSERT_RETURN(realm != NULL, PJ_EBUG);
248
 
 
249
 
    user = (const pj_stun_username_attr*)
250
 
           pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0);
251
 
    PJ_ASSERT_RETURN(user != NULL, PJ_EBUG);
252
 
 
253
 
    nonce = (const pj_stun_nonce_attr*)
254
 
            pj_stun_msg_find_attr(req, PJ_STUN_ATTR_NONCE, 0);
255
 
    PJ_ASSERT_RETURN(nonce != NULL, PJ_EBUG);
256
 
 
257
 
    /* Lookup the password */
258
 
    status = pj_turn_get_password(NULL, NULL, &realm->value, 
259
 
                                  &user->value, alloc->pool, 
260
 
                                  &alloc->cred.data.static_cred.data_type, 
261
 
                                  &alloc->cred.data.static_cred.data);
262
 
    if (status != PJ_SUCCESS)
263
 
        return status;
264
 
 
265
 
    /* Save credential */
266
 
    alloc->cred.type = PJ_STUN_AUTH_CRED_STATIC;
267
 
    pj_strdup(alloc->pool, &alloc->cred.data.static_cred.realm, &realm->value);
268
 
    pj_strdup(alloc->pool, &alloc->cred.data.static_cred.username, &user->value);
269
 
    pj_strdup(alloc->pool, &alloc->cred.data.static_cred.nonce, &nonce->value);
270
 
 
271
 
    return PJ_SUCCESS;
272
 
}
273
 
 
274
 
 
275
 
/*
276
 
 * Create new allocation.
277
 
 */
278
 
PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport,
279
 
                                              const pj_sockaddr_t *src_addr,
280
 
                                              unsigned src_addr_len,
281
 
                                              const pj_stun_rx_data *rdata,
282
 
                                              pj_stun_session *srv_sess,
283
 
                                              pj_turn_allocation **p_alloc)
284
 
{
285
 
    pj_turn_srv *srv = transport->listener->server;
286
 
    const pj_stun_msg *msg = rdata->msg;
287
 
    pj_pool_t *pool;
288
 
    alloc_request req;
289
 
    pj_turn_allocation *alloc;
290
 
    pj_stun_session_cb sess_cb;
291
 
    char str_tmp[80];
292
 
    pj_status_t status;
293
 
 
294
 
    /* Parse ALLOCATE request */
295
 
    status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len);
296
 
    if (status != PJ_SUCCESS)
297
 
        return status;
298
 
 
299
 
    pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);
300
 
 
301
 
    /* Init allocation structure */
302
 
    alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation);
303
 
    alloc->pool = pool;
304
 
    alloc->obj_name = pool->obj_name;
305
 
    alloc->relay.tp.sock = PJ_INVALID_SOCKET;
306
 
    alloc->server = transport->listener->server;
307
 
 
308
 
    alloc->bandwidth = req.bandwidth;
309
 
 
310
 
    /* Set transport */
311
 
    alloc->transport = transport;
312
 
    pj_turn_transport_add_ref(transport, alloc);
313
 
 
314
 
    alloc->hkey.tp_type = transport->listener->tp_type;
315
 
    pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);
316
 
 
317
 
    status = pj_lock_create_recursive_mutex(pool, alloc->obj_name, 
318
 
                                            &alloc->lock);
319
 
    if (status != PJ_SUCCESS) {
320
 
        goto on_error;
321
 
    }
322
 
 
323
 
    /* Create peer hash table */
324
 
    alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);
325
 
 
326
 
    /* Create channel hash table */
327
 
    alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);
328
 
 
329
 
    /* Print info */
330
 
    pj_ansi_strcpy(alloc->info, 
331
 
                   pj_turn_tp_type_name(transport->listener->tp_type));
332
 
    alloc->info[3] = ':';
333
 
    pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3);
334
 
 
335
 
    /* Create STUN session to handle STUN communication with client */
336
 
    pj_bzero(&sess_cb, sizeof(sess_cb));
337
 
    sess_cb.on_send_msg = &stun_on_send_msg;
338
 
    sess_cb.on_rx_request = &stun_on_rx_request;
339
 
    sess_cb.on_rx_indication = &stun_on_rx_indication;
340
 
    status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name,
341
 
                                    &sess_cb, PJ_FALSE, &alloc->sess);
342
 
    if (status != PJ_SUCCESS) {
343
 
        goto on_error;
344
 
    }
345
 
 
346
 
    /* Attach to STUN session */
347
 
    pj_stun_session_set_user_data(alloc->sess, alloc);
348
 
 
349
 
    /* Init authentication credential */
350
 
    status = init_cred(alloc, msg);
351
 
    if (status != PJ_SUCCESS) {
352
 
        goto on_error;
353
 
    }
354
 
 
355
 
    /* Attach authentication credential to STUN session */
356
 
    pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM,
357
 
                                   &alloc->cred);
358
 
 
359
 
    /* Create the relay resource */
360
 
    status = create_relay(srv, alloc, msg, &req, &alloc->relay);
361
 
    if (status != PJ_SUCCESS) {
362
 
        goto on_error;
363
 
    }
364
 
 
365
 
    /* Register this allocation */
366
 
    pj_turn_srv_register_allocation(srv, alloc);
367
 
 
368
 
    /* Respond to ALLOCATE request */
369
 
    status = send_allocate_response(alloc, srv_sess, transport, rdata);
370
 
    if (status != PJ_SUCCESS)
371
 
        goto on_error;
372
 
 
373
 
    /* Done */
374
 
    pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp, 
375
 
                      sizeof(str_tmp), 3);
376
 
    PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s", 
377
 
              alloc->info, pj_turn_tp_type_name(req.tp_type), str_tmp));
378
 
 
379
 
    /* Success */
380
 
    *p_alloc = alloc;
381
 
    return PJ_SUCCESS;
382
 
 
383
 
on_error:
384
 
    /* Send reply to the ALLOCATE request */
385
 
    pj_strerror(status, str_tmp, sizeof(str_tmp));
386
 
    pj_stun_session_respond(srv_sess, rdata, PJ_STUN_SC_BAD_REQUEST, str_tmp, 
387
 
                            transport, PJ_TRUE, src_addr, src_addr_len);
388
 
 
389
 
    /* Cleanup */
390
 
    destroy_allocation(alloc);
391
 
    return status;
392
 
}
393
 
 
394
 
 
395
 
/* Destroy relay resource */
396
 
static void destroy_relay(pj_turn_relay_res *relay)
397
 
{
398
 
    if (relay->timer.id) {
399
 
        pj_timer_heap_cancel(relay->allocation->server->core.timer_heap, 
400
 
                             &relay->timer);
401
 
        relay->timer.id = PJ_FALSE;
402
 
    }
403
 
 
404
 
    if (relay->tp.key) {
405
 
        pj_ioqueue_unregister(relay->tp.key);
406
 
        relay->tp.key = NULL;
407
 
        relay->tp.sock = PJ_INVALID_SOCKET;
408
 
    } else if (relay->tp.sock != PJ_INVALID_SOCKET) {
409
 
        pj_sock_close(relay->tp.sock);
410
 
        relay->tp.sock = PJ_INVALID_SOCKET;
411
 
    }
412
 
 
413
 
    /* Mark as shutdown */
414
 
    relay->lifetime = 0;
415
 
}
416
 
 
417
 
 
418
 
/*
419
 
 * Really destroy allocation.
420
 
 */
421
 
static void destroy_allocation(pj_turn_allocation *alloc)
422
 
{
423
 
    pj_pool_t *pool;
424
 
 
425
 
    /* Unregister this allocation */
426
 
    pj_turn_srv_unregister_allocation(alloc->server, alloc);
427
 
 
428
 
    /* Destroy relay */
429
 
    destroy_relay(&alloc->relay);
430
 
 
431
 
    /* Must lock only after destroying relay otherwise deadlock */
432
 
    if (alloc->lock) {
433
 
        pj_lock_acquire(alloc->lock);
434
 
    }
435
 
 
436
 
    /* Unreference transport */
437
 
    if (alloc->transport) {
438
 
        pj_turn_transport_dec_ref(alloc->transport, alloc);
439
 
        alloc->transport = NULL;
440
 
    }
441
 
 
442
 
    /* Destroy STUN session */
443
 
    if (alloc->sess) {
444
 
        pj_stun_session_destroy(alloc->sess);
445
 
        alloc->sess = NULL;
446
 
    }
447
 
 
448
 
    /* Destroy lock */
449
 
    if (alloc->lock) {
450
 
        pj_lock_release(alloc->lock);
451
 
        pj_lock_destroy(alloc->lock);
452
 
        alloc->lock = NULL;
453
 
    }
454
 
 
455
 
    /* Destroy pool */
456
 
    pool = alloc->pool;
457
 
    if (pool) {
458
 
        alloc->pool = NULL;
459
 
        pj_pool_release(pool);
460
 
    }
461
 
}
462
 
 
463
 
 
464
 
PJ_DECL(void) pj_turn_allocation_destroy(pj_turn_allocation *alloc)
465
 
{
466
 
    destroy_allocation(alloc);
467
 
}
468
 
 
469
 
 
470
 
/*
471
 
 * Handle transport closure.
472
 
 */
473
 
PJ_DEF(void) pj_turn_allocation_on_transport_closed( pj_turn_allocation *alloc,
474
 
                                                     pj_turn_transport *tp)
475
 
{
476
 
    PJ_LOG(5,(alloc->obj_name, "Transport %s unexpectedly closed, destroying "
477
 
              "allocation %s", tp->info, alloc->info));
478
 
    pj_turn_transport_dec_ref(tp, alloc);
479
 
    alloc->transport = NULL;
480
 
    destroy_allocation(alloc);
481
 
}
482
 
 
483
 
 
484
 
/* Initiate shutdown sequence for this allocation and start destroy timer.
485
 
 * Once allocation is marked as shutting down, any packets will be 
486
 
 * rejected/discarded 
487
 
 */
488
 
static void alloc_shutdown(pj_turn_allocation *alloc)
489
 
{
490
 
    pj_time_val destroy_delay = DESTROY_DELAY;
491
 
 
492
 
    /* Work with existing schedule */
493
 
    if (alloc->relay.timer.id == TIMER_ID_TIMEOUT) {
494
 
        /* Cancel existing shutdown timer */
495
 
        pj_timer_heap_cancel(alloc->server->core.timer_heap,
496
 
                             &alloc->relay.timer);
497
 
        alloc->relay.timer.id = TIMER_ID_NONE;
498
 
 
499
 
    } else if (alloc->relay.timer.id == TIMER_ID_DESTROY) {
500
 
        /* We've been scheduled to be destroyed, ignore this
501
 
         * shutdown request.
502
 
         */
503
 
        return;
504
 
    } 
505
 
 
506
 
    pj_assert(alloc->relay.timer.id == TIMER_ID_NONE);
507
 
 
508
 
    /* Shutdown relay socket */
509
 
    destroy_relay(&alloc->relay);
510
 
 
511
 
    /* Don't unregister from hash table because we still need to
512
 
     * handle REFRESH retransmission.
513
 
     */
514
 
 
515
 
    /* Schedule destroy timer */
516
 
    alloc->relay.timer.id = TIMER_ID_DESTROY;
517
 
    pj_timer_heap_schedule(alloc->server->core.timer_heap,
518
 
                           &alloc->relay.timer, &destroy_delay);
519
 
}
520
 
 
521
 
 
522
 
/* Reschedule timeout using current lifetime setting */
523
 
static pj_status_t resched_timeout(pj_turn_allocation *alloc)
524
 
{
525
 
    pj_time_val delay;
526
 
    pj_status_t status;
527
 
 
528
 
    pj_gettimeofday(&alloc->relay.expiry);
529
 
    alloc->relay.expiry.sec += alloc->relay.lifetime;
530
 
 
531
 
    pj_assert(alloc->relay.timer.id != TIMER_ID_DESTROY);
532
 
    if (alloc->relay.timer.id != 0) {
533
 
        pj_timer_heap_cancel(alloc->server->core.timer_heap, 
534
 
                             &alloc->relay.timer);
535
 
        alloc->relay.timer.id = TIMER_ID_NONE;
536
 
    }
537
 
 
538
 
    delay.sec = alloc->relay.lifetime;
539
 
    delay.msec = 0;
540
 
 
541
 
    alloc->relay.timer.id = TIMER_ID_TIMEOUT;
542
 
    status = pj_timer_heap_schedule(alloc->server->core.timer_heap, 
543
 
                                    &alloc->relay.timer, &delay);
544
 
    if (status != PJ_SUCCESS) {
545
 
        alloc->relay.timer.id = TIMER_ID_NONE;
546
 
        return status;
547
 
    }
548
 
 
549
 
    return PJ_SUCCESS;
550
 
}
551
 
 
552
 
 
553
 
/* Timer timeout callback */
554
 
static void relay_timeout_cb(pj_timer_heap_t *heap, pj_timer_entry *e)
555
 
{
556
 
    pj_turn_relay_res *rel;
557
 
    pj_turn_allocation *alloc;
558
 
 
559
 
    PJ_UNUSED_ARG(heap);
560
 
 
561
 
    rel = (pj_turn_relay_res*) e->user_data;
562
 
    alloc = rel->allocation;
563
 
 
564
 
    if (e->id == TIMER_ID_TIMEOUT) {
565
 
 
566
 
        e->id = TIMER_ID_NONE;
567
 
 
568
 
        PJ_LOG(4,(alloc->obj_name, 
569
 
                  "Client %s refresh timed-out, shutting down..", 
570
 
                  alloc->info));
571
 
 
572
 
        alloc_shutdown(alloc);
573
 
 
574
 
    } else if (e->id == TIMER_ID_DESTROY) {
575
 
        e->id = TIMER_ID_NONE;
576
 
 
577
 
        PJ_LOG(4,(alloc->obj_name, "Client %s destroying..", 
578
 
                  alloc->info));
579
 
 
580
 
        destroy_allocation(alloc);
581
 
    }
582
 
}
583
 
 
584
 
 
585
 
/*
586
 
 * Create relay.
587
 
 */
588
 
static pj_status_t create_relay(pj_turn_srv *srv,
589
 
                                pj_turn_allocation *alloc,
590
 
                                const pj_stun_msg *msg,
591
 
                                const alloc_request *req,
592
 
                                pj_turn_relay_res *relay)
593
 
{
594
 
    enum { RETRY = 40 };
595
 
    pj_pool_t *pool = alloc->pool;
596
 
    int retry, retry_max, sock_type;
597
 
    pj_ioqueue_callback icb;
598
 
    int af, namelen;
599
 
    pj_stun_string_attr *sa;
600
 
    pj_status_t status;
601
 
 
602
 
    pj_bzero(relay, sizeof(*relay));
603
 
    
604
 
    relay->allocation = alloc;
605
 
    relay->tp.sock = PJ_INVALID_SOCKET;
606
 
    
607
 
    /* TODO: get the requested address family from somewhere */
608
 
    af = alloc->transport->listener->addr.addr.sa_family;
609
 
 
610
 
    /* Save realm */
611
 
    sa = (pj_stun_string_attr*)
612
 
         pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
613
 
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
614
 
    pj_strdup(pool, &relay->realm, &sa->value);
615
 
 
616
 
    /* Save username */
617
 
    sa = (pj_stun_string_attr*)
618
 
         pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
619
 
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
620
 
    pj_strdup(pool, &relay->user, &sa->value);
621
 
 
622
 
    /* Lifetime and timeout */
623
 
    relay->lifetime = req->lifetime;
624
 
    pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay, 
625
 
                        &relay_timeout_cb);
626
 
    resched_timeout(alloc);
627
 
    
628
 
    /* Transport type */
629
 
    relay->hkey.tp_type = req->tp_type;
630
 
 
631
 
    /* Create the socket */
632
 
    if (req->tp_type == PJ_TURN_TP_UDP) {
633
 
        sock_type = pj_SOCK_DGRAM();
634
 
    } else if (req->tp_type == PJ_TURN_TP_TCP) {
635
 
        sock_type = pj_SOCK_STREAM();
636
 
    } else {
637
 
        pj_assert(!"Unknown transport");
638
 
        return PJ_EINVALIDOP;
639
 
    }
640
 
 
641
 
    status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
642
 
    if (status != PJ_SUCCESS) {
643
 
        pj_bzero(relay, sizeof(*relay));
644
 
        return status;
645
 
    }
646
 
 
647
 
    /* Find suitable port for this allocation */
648
 
    if (req->rpp_port) {
649
 
        retry_max = 1;
650
 
    } else {
651
 
        retry_max = RETRY;
652
 
    }
653
 
 
654
 
    for (retry=0; retry<retry_max; ++retry) {
655
 
        pj_uint16_t port;
656
 
        pj_sockaddr bound_addr;
657
 
 
658
 
        pj_lock_acquire(srv->core.lock);
659
 
 
660
 
        if (req->rpp_port) {
661
 
            port = (pj_uint16_t) req->rpp_port;
662
 
        } else if (req->tp_type == PJ_TURN_TP_UDP) {
663
 
            port = (pj_uint16_t) srv->ports.next_udp++;
664
 
            if (srv->ports.next_udp > srv->ports.max_udp)
665
 
                srv->ports.next_udp = srv->ports.min_udp;
666
 
        } else if (req->tp_type == PJ_TURN_TP_TCP) {
667
 
            port = (pj_uint16_t) srv->ports.next_tcp++;
668
 
            if (srv->ports.next_tcp > srv->ports.max_tcp)
669
 
                srv->ports.next_tcp = srv->ports.min_tcp;
670
 
        } else {
671
 
            pj_assert(!"Invalid transport");
672
 
            port = 0;
673
 
        }
674
 
 
675
 
        pj_lock_release(srv->core.lock);
676
 
 
677
 
        pj_sockaddr_init(af, &bound_addr, NULL, port);
678
 
 
679
 
        status = pj_sock_bind(relay->tp.sock, &bound_addr, 
680
 
                              pj_sockaddr_get_len(&bound_addr));
681
 
        if (status == PJ_SUCCESS)
682
 
            break;
683
 
    }
684
 
 
685
 
    if (status != PJ_SUCCESS) {
686
 
        /* Unable to allocate port */
687
 
        PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d", 
688
 
                  status));
689
 
        pj_sock_close(relay->tp.sock);
690
 
        relay->tp.sock = PJ_INVALID_SOCKET;
691
 
        return status;
692
 
    }
693
 
 
694
 
    /* Init relay key */
695
 
    namelen = sizeof(relay->hkey.addr);
696
 
    status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
697
 
    if (status != PJ_SUCCESS) {
698
 
        PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d", 
699
 
                  status));
700
 
        pj_sock_close(relay->tp.sock);
701
 
        relay->tp.sock = PJ_INVALID_SOCKET;
702
 
        return status;
703
 
    }
704
 
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
705
 
        pj_sockaddr_copy_addr(&relay->hkey.addr, 
706
 
                              &alloc->transport->listener->addr);
707
 
    }
708
 
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
709
 
        pj_sockaddr tmp_addr;
710
 
        pj_gethostip(af, &tmp_addr);
711
 
        pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
712
 
    }
713
 
 
714
 
    /* Init ioqueue */
715
 
    pj_bzero(&icb, sizeof(icb));
716
 
    icb.on_read_complete = &on_rx_from_peer;
717
 
 
718
 
    status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
719
 
                                      relay, &icb, &relay->tp.key);
720
 
    if (status != PJ_SUCCESS) {
721
 
        PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d", 
722
 
                  status));
723
 
        pj_sock_close(relay->tp.sock);
724
 
        relay->tp.sock = PJ_INVALID_SOCKET;
725
 
        return status;
726
 
    }
727
 
 
728
 
    /* Kick off pending read operation */
729
 
    pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
730
 
    on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);
731
 
 
732
 
    /* Done */
733
 
    return PJ_SUCCESS;
734
 
}
735
 
 
736
 
/* Create and send error response */
737
 
static void send_reply_err(pj_turn_allocation *alloc,
738
 
                           const pj_stun_rx_data *rdata,
739
 
                           pj_bool_t cache, 
740
 
                           int code, const char *errmsg)
741
 
{
742
 
    pj_status_t status;
743
 
 
744
 
    status = pj_stun_session_respond(alloc->sess, rdata, code, errmsg, NULL, 
745
 
                                     cache, &alloc->hkey.clt_addr,
746
 
                                     pj_sockaddr_get_len(&alloc->hkey.clt_addr.addr));
747
 
    if (status != PJ_SUCCESS) {
748
 
        alloc_err(alloc, "Error sending STUN error response", status);
749
 
        return;
750
 
    }
751
 
}
752
 
 
753
 
/* Create and send successful response */
754
 
static void send_reply_ok(pj_turn_allocation *alloc,
755
 
                          const pj_stun_rx_data *rdata)
756
 
{
757
 
    pj_status_t status;
758
 
    unsigned interval;
759
 
    pj_stun_tx_data *tdata;
760
 
 
761
 
    status = pj_stun_session_create_res(alloc->sess, rdata, 0, NULL, &tdata);
762
 
    if (status != PJ_SUCCESS) {
763
 
        alloc_err(alloc, "Error creating STUN success response", status);
764
 
        return;
765
 
    }
766
 
 
767
 
    /* Calculate time to expiration */
768
 
    if (alloc->relay.lifetime != 0) {
769
 
        pj_time_val now;
770
 
        pj_gettimeofday(&now);
771
 
        interval = alloc->relay.expiry.sec - now.sec;
772
 
    } else {
773
 
        interval = 0;
774
 
    }
775
 
 
776
 
    /* Add LIFETIME if this is not ChannelBind. */
777
 
    if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){
778
 
        pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
779
 
                                  PJ_STUN_ATTR_LIFETIME, interval);
780
 
 
781
 
        /* Add BANDWIDTH if lifetime is not zero */
782
 
        if (interval != 0) {
783
 
            pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
784
 
                                      PJ_STUN_ATTR_BANDWIDTH,
785
 
                                      alloc->bandwidth);
786
 
        }
787
 
    }
788
 
 
789
 
    status = pj_stun_session_send_msg(alloc->sess, NULL, PJ_TRUE, 
790
 
                                      PJ_FALSE, &alloc->hkey.clt_addr,  
791
 
                                      pj_sockaddr_get_len(&alloc->hkey.clt_addr), 
792
 
                                      tdata);
793
 
    if (status != PJ_SUCCESS) {
794
 
        alloc_err(alloc, "Error sending STUN success response", status);
795
 
        return;
796
 
    }
797
 
}
798
 
 
799
 
 
800
 
/* Create new permission */
801
 
static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
802
 
                                             const pj_sockaddr_t *peer_addr,
803
 
                                             unsigned addr_len)
804
 
{
805
 
    pj_turn_permission *perm;
806
 
 
807
 
    perm = PJ_POOL_ZALLOC_T(alloc->pool, pj_turn_permission);
808
 
    pj_memcpy(&perm->hkey.peer_addr, peer_addr, addr_len);
809
 
    
810
 
    perm->allocation = alloc;
811
 
    perm->channel = PJ_TURN_INVALID_CHANNEL;
812
 
 
813
 
    pj_gettimeofday(&perm->expiry);
814
 
    perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
815
 
 
816
 
    /* Register to hash table (only the address part!) */
817
 
    pj_hash_set(alloc->pool, alloc->peer_table, 
818
 
                pj_sockaddr_get_addr(&perm->hkey.peer_addr), 
819
 
                pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, perm);
820
 
 
821
 
    return perm;
822
 
}
823
 
 
824
 
/* Check if a permission isn't expired. Return NULL if expired. */
825
 
static pj_turn_permission *check_permission_expiry(pj_turn_permission *perm)
826
 
{
827
 
    pj_turn_allocation *alloc = perm->allocation;
828
 
    pj_time_val now;
829
 
 
830
 
    pj_gettimeofday(&now);
831
 
    if (PJ_TIME_VAL_GT(perm->expiry, now)) {
832
 
        /* Permission has not expired */
833
 
        return perm;
834
 
    }
835
 
 
836
 
    /* Remove from permission hash table */
837
 
    pj_hash_set(NULL, alloc->peer_table, 
838
 
                pj_sockaddr_get_addr(&perm->hkey.peer_addr), 
839
 
                pj_sockaddr_get_addr_len(&perm->hkey.peer_addr), 0, NULL);
840
 
 
841
 
    /* Remove from channel hash table, if assigned a channel number */
842
 
    if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
843
 
        pj_hash_set(NULL, alloc->ch_table, &perm->channel, 
844
 
                    sizeof(perm->channel), 0, NULL);
845
 
    }
846
 
 
847
 
    return NULL;
848
 
}
849
 
 
850
 
/* Lookup permission in hash table by the peer address */
851
 
static pj_turn_permission*
852
 
lookup_permission_by_addr(pj_turn_allocation *alloc,
853
 
                          const pj_sockaddr_t *peer_addr,
854
 
                          unsigned addr_len)
855
 
{
856
 
    pj_turn_permission *perm;
857
 
 
858
 
    PJ_UNUSED_ARG(addr_len);
859
 
 
860
 
    /* Lookup in peer hash table */
861
 
    perm = (pj_turn_permission*) 
862
 
           pj_hash_get(alloc->peer_table, 
863
 
                       pj_sockaddr_get_addr(peer_addr),
864
 
                       pj_sockaddr_get_addr_len(peer_addr), 
865
 
                       NULL);
866
 
    return perm ? check_permission_expiry(perm) : NULL;
867
 
}
868
 
 
869
 
/* Lookup permission in hash table by the channel number */
870
 
static pj_turn_permission*
871
 
lookup_permission_by_chnum(pj_turn_allocation *alloc,
872
 
                           unsigned chnum)
873
 
{
874
 
    pj_uint16_t chnum16 = (pj_uint16_t)chnum;
875
 
    pj_turn_permission *perm;
876
 
 
877
 
    /* Lookup in peer hash table */
878
 
    perm = (pj_turn_permission*) pj_hash_get(alloc->ch_table, &chnum16,
879
 
                                            sizeof(chnum16), NULL);
880
 
    return perm ? check_permission_expiry(perm) : NULL;
881
 
}
882
 
 
883
 
/* Update permission because of data from client to peer. 
884
 
 * Return PJ_TRUE is permission is found.
885
 
 */
886
 
static pj_bool_t refresh_permission(pj_turn_permission *perm)
887
 
{
888
 
    pj_gettimeofday(&perm->expiry);
889
 
    if (perm->channel == PJ_TURN_INVALID_CHANNEL)
890
 
        perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
891
 
    else
892
 
        perm->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT;
893
 
    return PJ_TRUE;
894
 
}
895
 
 
896
 
/*
897
 
 * Handle incoming packet from client. This would have been called by
898
 
 * server upon receiving packet from a listener.
899
 
 */
900
 
PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc,
901
 
                                                 pj_turn_pkt *pkt)
902
 
{
903
 
    pj_bool_t is_stun;
904
 
    pj_status_t status;
905
 
 
906
 
    /* Lock this allocation */
907
 
    pj_lock_acquire(alloc->lock);
908
 
 
909
 
    /* Quickly check if this is STUN message */
910
 
    is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0);
911
 
 
912
 
    if (is_stun) {
913
 
        /*
914
 
         * This could be an incoming STUN requests or indications.
915
 
         * Pass this through to the STUN session, which will call
916
 
         * our stun_on_rx_request() or stun_on_rx_indication()
917
 
         * callbacks.
918
 
         *
919
 
         * Note: currently it is necessary to specify the 
920
 
         * PJ_STUN_NO_FINGERPRINT_CHECK otherwise the FINGERPRINT
921
 
         * attribute inside STUN Send Indication message will mess up
922
 
         * with fingerprint checking.
923
 
         */
924
 
        unsigned options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
925
 
        pj_size_t parsed_len = 0;
926
 
 
927
 
        if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
928
 
            options |= PJ_STUN_IS_DATAGRAM;
929
 
 
930
 
        status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len,
931
 
                                           options, NULL, &parsed_len,
932
 
                                           &pkt->src.clt_addr, 
933
 
                                           pkt->src_addr_len);
934
 
 
935
 
        if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
936
 
            pkt->len = 0;
937
 
        } else if (parsed_len > 0) {
938
 
            if (parsed_len == pkt->len) {
939
 
                pkt->len = 0;
940
 
            } else {
941
 
                pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
942
 
                           pkt->len - parsed_len);
943
 
                pkt->len -= parsed_len;
944
 
            }
945
 
        }
946
 
 
947
 
        if (status != PJ_SUCCESS) {
948
 
            alloc_err(alloc, "Error handling STUN packet", status);
949
 
            goto on_return;
950
 
        }
951
 
 
952
 
    } else {
953
 
        /*
954
 
         * This is not a STUN packet, must be ChannelData packet.
955
 
         */
956
 
        pj_turn_channel_data *cd = (pj_turn_channel_data*)pkt->pkt;
957
 
        pj_turn_permission *perm;
958
 
        pj_ssize_t len;
959
 
 
960
 
        pj_assert(sizeof(*cd)==4);
961
 
 
962
 
        /* For UDP check the packet length */
963
 
        if (alloc->transport->listener->tp_type == PJ_TURN_TP_UDP) {
964
 
            if (pkt->len < pj_ntohs(cd->length)+sizeof(*cd)) {
965
 
                PJ_LOG(4,(alloc->obj_name, 
966
 
                          "ChannelData from %s discarded: UDP size error",
967
 
                          alloc->info));
968
 
                goto on_return;
969
 
            }
970
 
        } else {
971
 
            pj_assert(!"Unsupported transport");
972
 
            goto on_return;
973
 
        }
974
 
 
975
 
        perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number));
976
 
        if (!perm) {
977
 
            /* Discard */
978
 
            PJ_LOG(4,(alloc->obj_name, 
979
 
                      "ChannelData from %s discarded: ch#0x%x not found",
980
 
                      alloc->info, pj_ntohs(cd->ch_number)));
981
 
            goto on_return;
982
 
        }
983
 
 
984
 
        /* Relay the data */
985
 
        len = pj_ntohs(cd->length);
986
 
        pj_sock_sendto(alloc->relay.tp.sock, cd+1, &len, 0,
987
 
                       &perm->hkey.peer_addr,
988
 
                       pj_sockaddr_get_len(&perm->hkey.peer_addr));
989
 
 
990
 
        /* Refresh permission */
991
 
        refresh_permission(perm);
992
 
    }
993
 
 
994
 
on_return:
995
 
    /* Release lock */
996
 
    pj_lock_release(alloc->lock);
997
 
}
998
 
 
999
 
 
1000
 
/*
1001
 
 * Handle incoming packet from peer. This function is called by 
1002
 
 * on_rx_from_peer().
1003
 
 */
1004
 
static void handle_peer_pkt(pj_turn_allocation *alloc,
1005
 
                            pj_turn_relay_res *rel,
1006
 
                            char *pkt, pj_size_t len,
1007
 
                            const pj_sockaddr *src_addr)
1008
 
{
1009
 
    pj_turn_permission *perm;
1010
 
 
1011
 
    /* Lookup permission */
1012
 
    perm = lookup_permission_by_addr(alloc, src_addr, 
1013
 
                                     pj_sockaddr_get_len(src_addr));
1014
 
    if (perm == NULL) {
1015
 
        /* No permission, discard data */
1016
 
        return;
1017
 
    }
1018
 
 
1019
 
    /* Send Data Indication or ChannelData, depends on whether
1020
 
     * this permission is attached to a channel number.
1021
 
     */
1022
 
    if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
1023
 
        /* Send ChannelData */
1024
 
        pj_turn_channel_data *cd = (pj_turn_channel_data*)rel->tp.tx_pkt;
1025
 
 
1026
 
        if (len > PJ_TURN_MAX_PKT_LEN) {
1027
 
            char peer_addr[80];
1028
 
            pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3);
1029
 
            PJ_LOG(4,(alloc->obj_name, "Client %s: discarded data from %s "
1030
 
                      "because it's too long (%d bytes)",
1031
 
                      alloc->info, peer_addr, len));
1032
 
            return;
1033
 
        }
1034
 
 
1035
 
        /* Init header */
1036
 
        cd->ch_number = pj_htons(perm->channel);
1037
 
        cd->length = pj_htons((pj_uint16_t)len);
1038
 
 
1039
 
        /* Copy data */
1040
 
        pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
1041
 
 
1042
 
        /* Send to client */
1043
 
        alloc->transport->sendto(alloc->transport, rel->tp.tx_pkt,
1044
 
                                 len+sizeof(pj_turn_channel_data), 0,
1045
 
                                 &alloc->hkey.clt_addr,
1046
 
                                 pj_sockaddr_get_len(&alloc->hkey.clt_addr));
1047
 
    } else {
1048
 
        /* Send Data Indication */
1049
 
        pj_stun_tx_data *tdata;
1050
 
        pj_status_t status;
1051
 
 
1052
 
        status = pj_stun_session_create_ind(alloc->sess, 
1053
 
                                            PJ_STUN_DATA_INDICATION, &tdata);
1054
 
        if (status != PJ_SUCCESS) {
1055
 
            alloc_err(alloc, "Error creating Data indication", status);
1056
 
            return;
1057
 
        }
1058
 
 
1059
 
        pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
1060
 
                                      PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
1061
 
                                      src_addr, pj_sockaddr_get_len(src_addr));
1062
 
        pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
1063
 
                                    PJ_STUN_ATTR_DATA, 
1064
 
                                    (const pj_uint8_t*)pkt, len);
1065
 
 
1066
 
        pj_stun_session_send_msg(alloc->sess, NULL, PJ_FALSE, 
1067
 
                                 PJ_FALSE, &alloc->hkey.clt_addr, 
1068
 
                                 pj_sockaddr_get_len(&alloc->hkey.clt_addr), 
1069
 
                                 tdata);
1070
 
    }
1071
 
}
1072
 
 
1073
 
/*
1074
 
 * ioqueue notification on RX packets from the relay socket.
1075
 
 */
1076
 
static void on_rx_from_peer(pj_ioqueue_key_t *key, 
1077
 
                            pj_ioqueue_op_key_t *op_key, 
1078
 
                            pj_ssize_t bytes_read)
1079
 
{
1080
 
    pj_turn_relay_res *rel;
1081
 
    pj_status_t status;
1082
 
 
1083
 
    rel = (pj_turn_relay_res*) pj_ioqueue_get_user_data(key);
1084
 
 
1085
 
    /* Lock the allocation */
1086
 
    pj_lock_acquire(rel->allocation->lock);
1087
 
 
1088
 
    do {
1089
 
        if (bytes_read > 0) {
1090
 
            handle_peer_pkt(rel->allocation, rel, rel->tp.rx_pkt,
1091
 
                            bytes_read, &rel->tp.src_addr);
1092
 
        }
1093
 
 
1094
 
        /* Read next packet */
1095
 
        bytes_read = sizeof(rel->tp.rx_pkt);
1096
 
        rel->tp.src_addr_len = sizeof(rel->tp.src_addr);
1097
 
        status = pj_ioqueue_recvfrom(key, op_key,
1098
 
                                     rel->tp.rx_pkt, &bytes_read, 0,
1099
 
                                     &rel->tp.src_addr, 
1100
 
                                     &rel->tp.src_addr_len);
1101
 
 
1102
 
        if (status != PJ_EPENDING && status != PJ_SUCCESS)
1103
 
            bytes_read = -status;
1104
 
 
1105
 
    } while (status != PJ_EPENDING && status != PJ_ECANCELLED);
1106
 
 
1107
 
    /* Release allocation lock */
1108
 
    pj_lock_release(rel->allocation->lock);
1109
 
}
1110
 
 
1111
 
/*
1112
 
 * Callback notification from STUN session when it wants to send
1113
 
 * a STUN message towards the client.
1114
 
 */
1115
 
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
1116
 
                                    void *token,
1117
 
                                    const void *pkt,
1118
 
                                    pj_size_t pkt_size,
1119
 
                                    const pj_sockaddr_t *dst_addr,
1120
 
                                    unsigned addr_len)
1121
 
{
1122
 
    pj_turn_allocation *alloc;
1123
 
 
1124
 
    PJ_UNUSED_ARG(token);
1125
 
 
1126
 
    alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1127
 
 
1128
 
    return alloc->transport->sendto(alloc->transport, pkt, pkt_size, 0,
1129
 
                                    dst_addr, addr_len);
1130
 
}
1131
 
 
1132
 
/*
1133
 
 * Callback notification from STUN session when it receives STUN
1134
 
 * requests. This callback was trigger by STUN incoming message
1135
 
 * processing in pj_turn_allocation_on_rx_client_pkt().
1136
 
 */
1137
 
static pj_status_t stun_on_rx_request(pj_stun_session *sess,
1138
 
                                      const pj_uint8_t *pkt,
1139
 
                                      unsigned pkt_len,
1140
 
                                      const pj_stun_rx_data *rdata,
1141
 
                                      void *token,
1142
 
                                      const pj_sockaddr_t *src_addr,
1143
 
                                      unsigned src_addr_len)
1144
 
{
1145
 
    const pj_stun_msg *msg = rdata->msg;
1146
 
    pj_turn_allocation *alloc;
1147
 
 
1148
 
    PJ_UNUSED_ARG(pkt);
1149
 
    PJ_UNUSED_ARG(pkt_len);
1150
 
    PJ_UNUSED_ARG(token);
1151
 
    PJ_UNUSED_ARG(src_addr);
1152
 
    PJ_UNUSED_ARG(src_addr_len);
1153
 
 
1154
 
    alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1155
 
 
1156
 
    /* Refuse to serve any request if we've been shutdown */
1157
 
    if (alloc->relay.lifetime == 0) {
1158
 
        /* Reject with 437 if we're shutting down */
1159
 
        send_reply_err(alloc, rdata, PJ_TRUE, 
1160
 
                       PJ_STUN_SC_ALLOCATION_MISMATCH, NULL);
1161
 
        return PJ_SUCCESS;
1162
 
    }
1163
 
 
1164
 
    if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) {
1165
 
        /* 
1166
 
         * Handle REFRESH request 
1167
 
         */
1168
 
        pj_stun_lifetime_attr *lifetime;
1169
 
        pj_stun_bandwidth_attr *bandwidth;
1170
 
 
1171
 
        /* Get LIFETIME attribute */
1172
 
        lifetime = (pj_stun_lifetime_attr*)
1173
 
                   pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
1174
 
 
1175
 
        /* Get BANDWIDTH attribute */
1176
 
        bandwidth = (pj_stun_bandwidth_attr*)
1177
 
                    pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
1178
 
 
1179
 
        if (lifetime && lifetime->value==0) {
1180
 
            /*
1181
 
             * This is deallocation request.
1182
 
             */
1183
 
            alloc->relay.lifetime = 0;
1184
 
 
1185
 
            /* Respond first */
1186
 
            send_reply_ok(alloc, rdata);
1187
 
 
1188
 
            /* Shutdown allocation */
1189
 
            PJ_LOG(4,(alloc->obj_name, 
1190
 
                      "Client %s request to dealloc, shutting down",
1191
 
                      alloc->info));
1192
 
 
1193
 
            alloc_shutdown(alloc);
1194
 
 
1195
 
        } else {
1196
 
            /*
1197
 
             * This is a refresh request.
1198
 
             */
1199
 
            
1200
 
            /* Update lifetime */
1201
 
            if (lifetime) {
1202
 
                alloc->relay.lifetime = lifetime->value;
1203
 
            }
1204
 
 
1205
 
            /* Update bandwidth */
1206
 
            // TODO:
1207
 
 
1208
 
            /* Update expiration timer */
1209
 
            resched_timeout(alloc);
1210
 
 
1211
 
            /* Send reply */
1212
 
            send_reply_ok(alloc, rdata);
1213
 
        }
1214
 
 
1215
 
    } else if (msg->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
1216
 
        /*
1217
 
         * ChannelBind request.
1218
 
         */
1219
 
        pj_stun_channel_number_attr *ch_attr;
1220
 
        pj_stun_xor_peer_addr_attr *peer_attr;
1221
 
        pj_turn_permission *p1, *p2;
1222
 
 
1223
 
        ch_attr = (pj_stun_channel_number_attr*)
1224
 
                  pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CHANNEL_NUMBER, 0);
1225
 
        peer_attr = (pj_stun_xor_peer_addr_attr*)
1226
 
                    pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1227
 
 
1228
 
        if (!ch_attr || !peer_attr) {
1229
 
            send_reply_err(alloc, rdata, PJ_TRUE, 
1230
 
                           PJ_STUN_SC_BAD_REQUEST, NULL);
1231
 
            return PJ_SUCCESS;
1232
 
        }
1233
 
 
1234
 
        /* Find permission with the channel number */
1235
 
        p1 = lookup_permission_by_chnum(alloc, PJ_STUN_GET_CH_NB(ch_attr->value));
1236
 
 
1237
 
        /* If permission is found, this is supposed to be a channel bind 
1238
 
         * refresh. Make sure it's for the same peer.
1239
 
         */
1240
 
        if (p1) {
1241
 
            if (pj_sockaddr_cmp(&p1->hkey.peer_addr, &peer_attr->sockaddr)) {
1242
 
                /* Address mismatch. Send 400 */
1243
 
                send_reply_err(alloc, rdata, PJ_TRUE, 
1244
 
                               PJ_STUN_SC_BAD_REQUEST, 
1245
 
                               "Peer address mismatch");
1246
 
                return PJ_SUCCESS;
1247
 
            }
1248
 
 
1249
 
            /* Refresh permission */
1250
 
            refresh_permission(p1);
1251
 
 
1252
 
            /* Send response */
1253
 
            send_reply_ok(alloc, rdata);
1254
 
 
1255
 
            /* Done */
1256
 
            return PJ_SUCCESS;
1257
 
        }
1258
 
 
1259
 
        /* If permission is not found, create a new one. Make sure the peer
1260
 
         * has not alreadyy assigned with a channel number.
1261
 
         */
1262
 
        p2 = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1263
 
                                       pj_sockaddr_get_len(&peer_attr->sockaddr));
1264
 
        if (p2 && p2->channel != PJ_TURN_INVALID_CHANNEL) {
1265
 
            send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, 
1266
 
                           "Peer address already assigned a channel number");
1267
 
            return PJ_SUCCESS;
1268
 
        }
1269
 
 
1270
 
        /* Create permission if it doesn't exist */
1271
 
        if (!p2) {
1272
 
            p2 = create_permission(alloc, &peer_attr->sockaddr,
1273
 
                                   pj_sockaddr_get_len(&peer_attr->sockaddr));
1274
 
            if (!p2)
1275
 
                return PJ_SUCCESS;
1276
 
        }
1277
 
 
1278
 
        /* Assign channel number to permission */
1279
 
        p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
1280
 
 
1281
 
        /* Register to hash table */
1282
 
        pj_assert(sizeof(p2->channel==2));
1283
 
        pj_hash_set(alloc->pool, alloc->ch_table, &p2->channel, 
1284
 
                    sizeof(p2->channel), 0, p2);
1285
 
 
1286
 
        /* Update */
1287
 
        refresh_permission(p2);
1288
 
 
1289
 
        /* Reply */
1290
 
        send_reply_ok(alloc, rdata);
1291
 
 
1292
 
        return PJ_SUCCESS;
1293
 
 
1294
 
    } else if (msg->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {
1295
 
 
1296
 
        /* Respond with 437 (section 6.3 turn-07) */
1297
 
        send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_ALLOCATION_MISMATCH,
1298
 
                       NULL);
1299
 
 
1300
 
    } else {
1301
 
 
1302
 
        /* Respond with Bad Request? */
1303
 
        send_reply_err(alloc, rdata, PJ_TRUE, PJ_STUN_SC_BAD_REQUEST, NULL);
1304
 
 
1305
 
    }
1306
 
 
1307
 
    return PJ_SUCCESS;
1308
 
}
1309
 
 
1310
 
/*
1311
 
 * Callback notification from STUN session when it receives STUN
1312
 
 * indications. This callback was trigger by STUN incoming message
1313
 
 * processing in pj_turn_allocation_on_rx_client_pkt().
1314
 
 */
1315
 
static pj_status_t stun_on_rx_indication(pj_stun_session *sess,
1316
 
                                         const pj_uint8_t *pkt,
1317
 
                                         unsigned pkt_len,
1318
 
                                         const pj_stun_msg *msg,
1319
 
                                         void *token,
1320
 
                                         const pj_sockaddr_t *src_addr,
1321
 
                                         unsigned src_addr_len)
1322
 
{
1323
 
    pj_stun_xor_peer_addr_attr *peer_attr;
1324
 
    pj_stun_data_attr *data_attr;
1325
 
    pj_turn_allocation *alloc;
1326
 
    pj_turn_permission *perm;
1327
 
    pj_ssize_t len;
1328
 
 
1329
 
    PJ_UNUSED_ARG(pkt);
1330
 
    PJ_UNUSED_ARG(pkt_len);
1331
 
    PJ_UNUSED_ARG(token);
1332
 
    PJ_UNUSED_ARG(src_addr);
1333
 
    PJ_UNUSED_ARG(src_addr_len);
1334
 
 
1335
 
    alloc = (pj_turn_allocation*) pj_stun_session_get_user_data(sess);
1336
 
 
1337
 
    /* Only expect Send Indication */
1338
 
    if (msg->hdr.type != PJ_STUN_SEND_INDICATION) {
1339
 
        /* Ignore */
1340
 
        return PJ_SUCCESS;
1341
 
    }
1342
 
 
1343
 
    /* Get XOR-PEER-ADDRESS attribute */
1344
 
    peer_attr = (pj_stun_xor_peer_addr_attr*)
1345
 
                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
1346
 
 
1347
 
    /* MUST have XOR-PEER-ADDRESS attribute */
1348
 
    if (!peer_attr)
1349
 
        return PJ_SUCCESS;
1350
 
 
1351
 
    /* Get DATA attribute */
1352
 
    data_attr = (pj_stun_data_attr*)
1353
 
                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
1354
 
 
1355
 
    /* Create/update/refresh the permission */
1356
 
    perm = lookup_permission_by_addr(alloc, &peer_attr->sockaddr,
1357
 
                                     pj_sockaddr_get_len(&peer_attr->sockaddr));
1358
 
    if (perm == NULL) {
1359
 
        perm = create_permission(alloc, &peer_attr->sockaddr,
1360
 
                                 pj_sockaddr_get_len(&peer_attr->sockaddr));
1361
 
    }
1362
 
    refresh_permission(perm);
1363
 
 
1364
 
    /* Return if we don't have data */
1365
 
    if (data_attr == NULL)
1366
 
        return PJ_SUCCESS;
1367
 
 
1368
 
    /* Relay the data to peer */
1369
 
    len = data_attr->length;
1370
 
    pj_sock_sendto(alloc->relay.tp.sock, data_attr->data, 
1371
 
                   &len, 0, &peer_attr->sockaddr,
1372
 
                   pj_sockaddr_get_len(&peer_attr->sockaddr));
1373
 
 
1374
 
    return PJ_SUCCESS;
1375
 
}
1376
 
 
1377