~ubuntu-branches/ubuntu/maverick/sflphone/maverick

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-06-03 15:59:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100603155946-ybe8d8o8zx8lp0m8
Tags: upstream-0.9.8.3
ImportĀ upstreamĀ versionĀ 0.9.8.3

Show diffs side-by-side

added added

removed removed

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