blob: 36de03f54b74cbf1afbb5914aecd5967ec2532ff [file] [log] [blame]
Benny Prijono5ac0bd72008-03-13 15:11:29 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono5ac0bd72008-03-13 15:11:29 +00005 *
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 <pjnath.h>
21#include <pjlib-util.h>
22#include <pjlib.h>
23
24
25#define THIS_FILE "client_main.c"
26#define LOCAL_PORT 1998
27#define BANDWIDTH 64 /* -1 to disable */
28#define LIFETIME 600 /* -1 to disable */
29#define REQ_TRANSPORT -1 /* 0: udp, 1: tcp, -1: disable */
30#define REQ_PORT_PROPS -1 /* -1 to disable */
31#define REQ_IP 0 /* IP address string */
32
33//#define OPTIONS PJ_STUN_NO_AUTHENTICATE
34#define OPTIONS 0
35
36
37struct peer
38{
Benny Prijono3fdf3f62008-06-21 10:18:49 +000039 pj_stun_sock *stun_sock;
40 pj_sockaddr mapped_addr;
Benny Prijono5ac0bd72008-03-13 15:11:29 +000041};
42
43
44static struct global
45{
46 pj_caching_pool cp;
47 pj_pool_t *pool;
48 pj_stun_config stun_config;
49 pj_thread_t *thread;
50 pj_bool_t quit;
51
Benny Prijonobf7d2222008-10-02 17:54:40 +000052 pj_dns_resolver *resolver;
53
Benny Prijono879ad1a2008-04-09 09:38:12 +000054 pj_turn_sock *relay;
Benny Prijono5ac0bd72008-03-13 15:11:29 +000055 pj_sockaddr relay_addr;
56
57 struct peer peer[2];
58} g;
59
60static struct options
61{
Benny Prijono879ad1a2008-04-09 09:38:12 +000062 pj_bool_t use_tcp;
63 char *srv_addr;
64 char *srv_port;
65 char *realm;
66 char *user_name;
67 char *password;
68 pj_bool_t use_fingerprint;
Benny Prijono3fdf3f62008-06-21 10:18:49 +000069 char *stun_server;
Benny Prijonobf7d2222008-10-02 17:54:40 +000070 char *nameserver;
Benny Prijono5ac0bd72008-03-13 15:11:29 +000071} o;
72
73
74static int worker_thread(void *unused);
Benny Prijono879ad1a2008-04-09 09:38:12 +000075static void turn_on_rx_data(pj_turn_sock *relay,
Benny Prijonoff1df042008-06-06 14:47:10 +000076 void *pkt,
Benny Prijono5ac0bd72008-03-13 15:11:29 +000077 unsigned pkt_len,
78 const pj_sockaddr_t *peer_addr,
79 unsigned addr_len);
Benny Prijono879ad1a2008-04-09 09:38:12 +000080static void turn_on_state(pj_turn_sock *relay, pj_turn_state_t old_state,
Benny Prijono5ac0bd72008-03-13 15:11:29 +000081 pj_turn_state_t new_state);
Benny Prijono3fdf3f62008-06-21 10:18:49 +000082static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
83 pj_stun_sock_op op,
84 pj_status_t status);
85static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
86 void *pkt,
87 unsigned pkt_len,
88 const pj_sockaddr_t *src_addr,
89 unsigned addr_len);
Benny Prijono5ac0bd72008-03-13 15:11:29 +000090
91
92static void my_perror(const char *title, pj_status_t status)
93{
94 char errmsg[PJ_ERR_MSG_SIZE];
95 pj_strerror(status, errmsg, sizeof(errmsg));
96
97 PJ_LOG(3,(THIS_FILE, "%s: %s", title, errmsg));
98}
99
100#define CHECK(expr) status=expr; \
101 if (status!=PJ_SUCCESS) { \
102 my_perror(#expr, status); \
103 return status; \
104 }
105
106static int init()
107{
108 int i;
109 pj_status_t status;
110
111 CHECK( pj_init() );
112 CHECK( pjlib_util_init() );
113 CHECK( pjnath_init() );
114
115 /* Check that server is specified */
116 if (!o.srv_addr) {
117 printf("Error: server must be specified\n");
118 return PJ_EINVAL;
119 }
120
121 pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0);
122
123 g.pool = pj_pool_create(&g.cp.factory, "main", 1000, 1000, NULL);
124
125 /* Init global STUN config */
126 pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, NULL);
127
128 /* Create global timer heap */
129 CHECK( pj_timer_heap_create(g.pool, 1000, &g.stun_config.timer_heap) );
130
131 /* Create global ioqueue */
132 CHECK( pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue) );
133
134 /*
135 * Create peers
136 */
Benny Prijono24a21852008-04-14 04:04:30 +0000137 for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) {
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000138 pj_stun_sock_cb stun_sock_cb;
139 char name[] = "peer0";
Benny Prijono1222ef62008-07-12 10:08:37 +0000140 pj_uint16_t port;
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000141 pj_str_t server;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000142
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000143 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
144 stun_sock_cb.on_rx_data = &stun_sock_on_rx_data;
145 stun_sock_cb.on_status = &stun_sock_on_status;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000146
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000147 g.peer[i].mapped_addr.addr.sa_family = pj_AF_INET();
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000148
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000149 name[strlen(name)-1] = '0'+i;
150 status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(),
151 &stun_sock_cb, NULL,
152 &g.peer[i], &g.peer[i].stun_sock);
153 if (status != PJ_SUCCESS) {
154 my_perror("pj_stun_sock_create()", status);
155 return status;
156 }
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000157
Benny Prijono1222ef62008-07-12 10:08:37 +0000158 if (o.stun_server) {
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000159 server = pj_str(o.stun_server);
Benny Prijono1222ef62008-07-12 10:08:37 +0000160 port = PJ_STUN_PORT;
161 } else {
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000162 server = pj_str(o.srv_addr);
Benny Prijono1222ef62008-07-12 10:08:37 +0000163 port = (pj_uint16_t)(o.srv_port?atoi(o.srv_port):PJ_STUN_PORT);
164 }
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000165 status = pj_stun_sock_start(g.peer[i].stun_sock, &server,
Benny Prijono1222ef62008-07-12 10:08:37 +0000166 port, NULL);
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000167 if (status != PJ_SUCCESS) {
168 my_perror("pj_stun_sock_start()", status);
169 return status;
170 }
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000171 }
172
173 /* Start the worker thread */
174 CHECK( pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread) );
175
176
177 return PJ_SUCCESS;
178}
179
180
181static int shutdown()
182{
183 unsigned i;
184
185 if (g.thread) {
186 g.quit = 1;
187 pj_thread_join(g.thread);
188 pj_thread_destroy(g.thread);
189 g.thread = NULL;
190 }
Benny Prijono879ad1a2008-04-09 09:38:12 +0000191 if (g.relay) {
192 pj_turn_sock_destroy(g.relay);
193 g.relay = NULL;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000194 }
195 for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000196 if (g.peer[i].stun_sock) {
197 pj_stun_sock_destroy(g.peer[i].stun_sock);
198 g.peer[i].stun_sock = NULL;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000199 }
200 }
201 if (g.stun_config.timer_heap) {
202 pj_timer_heap_destroy(g.stun_config.timer_heap);
203 g.stun_config.timer_heap = NULL;
204 }
205 if (g.stun_config.ioqueue) {
206 pj_ioqueue_destroy(g.stun_config.ioqueue);
207 g.stun_config.ioqueue = NULL;
208 }
209 if (g.pool) {
210 pj_pool_release(g.pool);
211 g.pool = NULL;
212 }
213 pj_pool_factory_dump(&g.cp.factory, PJ_TRUE);
214 pj_caching_pool_destroy(&g.cp);
215
216 return PJ_SUCCESS;
217}
218
219
220static int worker_thread(void *unused)
221{
222 PJ_UNUSED_ARG(unused);
223
224 while (!g.quit) {
225 const pj_time_val delay = {0, 10};
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000226
227 /* Poll ioqueue for the TURN client */
228 pj_ioqueue_poll(g.stun_config.ioqueue, &delay);
229
230 /* Poll the timer heap */
231 pj_timer_heap_poll(g.stun_config.timer_heap, NULL);
232
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000233 }
234
235 return 0;
236}
237
238static pj_status_t create_relay(void)
239{
Benny Prijono879ad1a2008-04-09 09:38:12 +0000240 pj_turn_sock_cb rel_cb;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000241 pj_stun_auth_cred cred;
242 pj_str_t srv;
243 pj_status_t status;
244
Benny Prijono879ad1a2008-04-09 09:38:12 +0000245 if (g.relay) {
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000246 PJ_LOG(1,(THIS_FILE, "Relay already created"));
247 return -1;
248 }
249
Benny Prijonobf7d2222008-10-02 17:54:40 +0000250 /* Create DNS resolver if configured */
251 if (o.nameserver) {
252 pj_str_t ns = pj_str(o.nameserver);
253
254 status = pj_dns_resolver_create(&g.cp.factory, "resolver", 0,
255 g.stun_config.timer_heap,
256 g.stun_config.ioqueue, &g.resolver);
257 if (status != PJ_SUCCESS) {
258 PJ_LOG(1,(THIS_FILE, "Error creating resolver (err=%d)", status));
259 return status;
260 }
261
262 status = pj_dns_resolver_set_ns(g.resolver, 1, &ns, NULL);
263 if (status != PJ_SUCCESS) {
264 PJ_LOG(1,(THIS_FILE, "Error configuring nameserver (err=%d)", status));
265 return status;
266 }
267 }
268
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000269 pj_bzero(&rel_cb, sizeof(rel_cb));
270 rel_cb.on_rx_data = &turn_on_rx_data;
271 rel_cb.on_state = &turn_on_state;
Benny Prijono879ad1a2008-04-09 09:38:12 +0000272 CHECK( pj_turn_sock_create(&g.stun_config, pj_AF_INET(),
273 (o.use_tcp? PJ_TURN_TP_TCP : PJ_TURN_TP_UDP),
274 &rel_cb, 0,
275 NULL, &g.relay) );
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000276
277 if (o.user_name) {
278 pj_bzero(&cred, sizeof(cred));
279 cred.type = PJ_STUN_AUTH_CRED_STATIC;
280 cred.data.static_cred.realm = pj_str(o.realm);
281 cred.data.static_cred.username = pj_str(o.user_name);
Benny Prijono24a21852008-04-14 04:04:30 +0000282 cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000283 cred.data.static_cred.data = pj_str(o.password);
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000284 //cred.data.static_cred.nonce = pj_str(o.nonce);
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000285 } else {
286 PJ_LOG(2,(THIS_FILE, "Warning: no credential is set"));
287 }
288
289 srv = pj_str(o.srv_addr);
Benny Prijonoff1df042008-06-06 14:47:10 +0000290 CHECK(pj_turn_sock_alloc(g.relay, /* the relay */
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000291 &srv, /* srv addr */
292 (o.srv_port?atoi(o.srv_port):PJ_STUN_PORT),/* def port */
Benny Prijonobf7d2222008-10-02 17:54:40 +0000293 g.resolver, /* resolver */
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000294 (o.user_name?&cred:NULL), /* credential */
295 NULL) /* alloc param */
296 );
297
298 return PJ_SUCCESS;
299}
300
301static void destroy_relay(void)
302{
Benny Prijono879ad1a2008-04-09 09:38:12 +0000303 if (g.relay) {
304 pj_turn_sock_destroy(g.relay);
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000305 }
306}
307
308
Benny Prijono879ad1a2008-04-09 09:38:12 +0000309static void turn_on_rx_data(pj_turn_sock *relay,
Benny Prijonoff1df042008-06-06 14:47:10 +0000310 void *pkt,
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000311 unsigned pkt_len,
312 const pj_sockaddr_t *peer_addr,
313 unsigned addr_len)
314{
315 char addrinfo[80];
316
317 pj_sockaddr_print(peer_addr, addrinfo, sizeof(addrinfo), 3);
318
319 PJ_LOG(3,(THIS_FILE, "Client received %d bytes data from %s: %.*s",
320 pkt_len, addrinfo, pkt_len, pkt));
321}
322
323
Benny Prijono879ad1a2008-04-09 09:38:12 +0000324static void turn_on_state(pj_turn_sock *relay, pj_turn_state_t old_state,
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000325 pj_turn_state_t new_state)
326{
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000327 PJ_LOG(3,(THIS_FILE, "State %s --> %s", pj_turn_state_name(old_state),
328 pj_turn_state_name(new_state)));
329
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000330 if (new_state == PJ_TURN_STATE_READY) {
331 pj_turn_session_info info;
Benny Prijono879ad1a2008-04-09 09:38:12 +0000332 pj_turn_sock_get_info(relay, &info);
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000333 pj_memcpy(&g.relay_addr, &info.relay_addr, sizeof(pj_sockaddr));
Benny Prijono879ad1a2008-04-09 09:38:12 +0000334 } else if (new_state > PJ_TURN_STATE_READY && g.relay) {
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000335 PJ_LOG(3,(THIS_FILE, "Relay shutting down.."));
Benny Prijono879ad1a2008-04-09 09:38:12 +0000336 g.relay = NULL;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000337 }
338}
339
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000340static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock,
341 pj_stun_sock_op op,
342 pj_status_t status)
343{
344 struct peer *peer = (struct peer*) pj_stun_sock_get_user_data(stun_sock);
345
346 if (status == PJ_SUCCESS) {
347 PJ_LOG(4,(THIS_FILE, "peer%d: %s success", peer-g.peer,
348 pj_stun_sock_op_name(op)));
349 } else {
350 char errmsg[PJ_ERR_MSG_SIZE];
351 pj_strerror(status, errmsg, sizeof(errmsg));
352 PJ_LOG(1,(THIS_FILE, "peer%d: %s error: %s", peer-g.peer,
353 pj_stun_sock_op_name(op), errmsg));
354 return PJ_FALSE;
355 }
356
357 if (op==PJ_STUN_SOCK_BINDING_OP || op==PJ_STUN_SOCK_KEEP_ALIVE_OP) {
358 pj_stun_sock_info info;
359 int cmp;
360
361 pj_stun_sock_get_info(stun_sock, &info);
362 cmp = pj_sockaddr_cmp(&info.mapped_addr, &peer->mapped_addr);
363
364 if (cmp) {
365 char straddr[PJ_INET6_ADDRSTRLEN+10];
366
367 pj_sockaddr_cp(&peer->mapped_addr, &info.mapped_addr);
368 pj_sockaddr_print(&peer->mapped_addr, straddr, sizeof(straddr), 3);
369 PJ_LOG(3,(THIS_FILE, "peer%d: STUN mapped address is %s",
370 peer-g.peer, straddr));
371 }
372 }
373
374 return PJ_TRUE;
375}
376
377static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
378 void *pkt,
379 unsigned pkt_len,
380 const pj_sockaddr_t *src_addr,
381 unsigned addr_len)
382{
383 struct peer *peer = (struct peer*) pj_stun_sock_get_user_data(stun_sock);
384 char straddr[PJ_INET6_ADDRSTRLEN+10];
385
386 ((char*)pkt)[pkt_len] = '\0';
387
388 pj_sockaddr_print(src_addr, straddr, sizeof(straddr), 3);
389 PJ_LOG(3,(THIS_FILE, "peer%d: received %d bytes data from %s: %s",
390 peer-g.peer, pkt_len, straddr, (char*)pkt));
391
392 return PJ_TRUE;
393}
394
395
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000396static void menu(void)
397{
398 pj_turn_session_info info;
399 char client_state[20], relay_addr[80], peer0_addr[80], peer1_addr[80];
400
Benny Prijono879ad1a2008-04-09 09:38:12 +0000401 if (g.relay) {
402 pj_turn_sock_get_info(g.relay, &info);
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000403 strcpy(client_state, pj_turn_state_name(info.state));
Benny Prijono17d10b52008-03-14 17:56:11 +0000404 if (info.state >= PJ_TURN_STATE_READY)
405 pj_sockaddr_print(&info.relay_addr, relay_addr, sizeof(relay_addr), 3);
406 else
407 strcpy(relay_addr, "0.0.0.0:0");
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000408 } else {
409 strcpy(client_state, "NULL");
410 strcpy(relay_addr, "0.0.0.0:0");
411 }
412
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000413 pj_sockaddr_print(&g.peer[0].mapped_addr, peer0_addr, sizeof(peer0_addr), 3);
414 pj_sockaddr_print(&g.peer[1].mapped_addr, peer1_addr, sizeof(peer1_addr), 3);
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000415
416
417 puts("\n");
418 puts("+====================================================================+");
419 puts("| CLIENT | PEER-0 |");
420 puts("| | |");
Benny Prijono17d10b52008-03-14 17:56:11 +0000421 printf("| State : %-12s | Address: %-21s |\n",
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000422 client_state, peer0_addr);
Benny Prijono17d10b52008-03-14 17:56:11 +0000423 printf("| Relay addr: %-21s | |\n",
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000424 relay_addr);
425 puts("| | 0 Send data to relay address |");
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000426 puts("| a Allocate relay +--------------------------------+ ");
427 puts("| s,ss Send data to peer 0/1 | PEER-1 |");
428 puts("| b,bb BindChannel to peer 0/1 | |");
429 printf("| x Delete allocation | Address: %-21s |\n",
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000430 peer1_addr);
431 puts("+-----------------------------------+ |");
Benny Prijono879ad1a2008-04-09 09:38:12 +0000432 puts("| q Quit d Dump | 1 Send data to relay adderss |");
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000433 puts("+-----------------------------------+--------------------------------+");
434 printf(">>> ");
435 fflush(stdout);
436}
437
438
439static void console_main(void)
440{
441 while (!g.quit) {
442 char input[32];
443 struct peer *peer;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000444 pj_status_t status;
445
446 menu();
447
Benny Prijono32d267b2009-01-01 22:08:21 +0000448 if (fgets(input, sizeof(input), stdin) == NULL)
449 break;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000450
451 switch (input[0]) {
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000452 case 'a':
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000453 create_relay();
454 break;
Benny Prijonof279d672008-04-01 18:23:56 +0000455 case 'd':
456 pj_pool_factory_dump(&g.cp.factory, PJ_TRUE);
457 break;
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000458 case 's':
Benny Prijono879ad1a2008-04-09 09:38:12 +0000459 if (g.relay == NULL) {
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000460 puts("Error: no relay");
461 continue;
462 }
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000463 if (input[1]!='s')
464 peer = &g.peer[0];
465 else
466 peer = &g.peer[1];
467
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000468 strcpy(input, "Hello from client");
Benny Prijono879ad1a2008-04-09 09:38:12 +0000469 status = pj_turn_sock_sendto(g.relay, (const pj_uint8_t*)input,
Benny Prijono68854002008-03-20 19:21:27 +0000470 strlen(input)+1,
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000471 &peer->mapped_addr,
472 pj_sockaddr_get_len(&peer->mapped_addr));
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000473 if (status != PJ_SUCCESS)
474 my_perror("turn_udp_sendto() failed", status);
475 break;
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000476 case 'b':
Benny Prijono879ad1a2008-04-09 09:38:12 +0000477 if (g.relay == NULL) {
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000478 puts("Error: no relay");
479 continue;
480 }
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000481 if (input[1]!='b')
482 peer = &g.peer[0];
483 else
484 peer = &g.peer[1];
485
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000486 status = pj_turn_sock_bind_channel(g.relay, &peer->mapped_addr,
487 pj_sockaddr_get_len(&peer->mapped_addr));
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000488 if (status != PJ_SUCCESS)
489 my_perror("turn_udp_bind_channel() failed", status);
490 break;
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000491 case 'x':
Benny Prijono879ad1a2008-04-09 09:38:12 +0000492 if (g.relay == NULL) {
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000493 puts("Error: no relay");
494 continue;
495 }
496 destroy_relay();
497 break;
498 case '0':
499 case '1':
Benny Prijono879ad1a2008-04-09 09:38:12 +0000500 if (g.relay == NULL) {
Benny Prijono68854002008-03-20 19:21:27 +0000501 puts("No relay");
502 break;
503 }
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000504 peer = &g.peer[input[0]-'0'];
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000505 sprintf(input, "Hello from peer%d", input[0]-'0');
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000506 pj_stun_sock_sendto(peer->stun_sock, NULL, input, strlen(input)+1, 0,
507 &g.relay_addr, pj_sockaddr_get_len(&g.relay_addr));
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000508 break;
509 case 'q':
510 g.quit = PJ_TRUE;
511 break;
512 }
513 }
514}
515
516
517static void usage(void)
518{
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000519 puts("Usage: pjturn_client TURN-SERVER [OPTIONS]");
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000520 puts("");
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000521 puts("where TURN-SERVER is \"host[:port]\"");
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000522 puts("");
523 puts("and OPTIONS:");
Benny Prijono879ad1a2008-04-09 09:38:12 +0000524 puts(" --tcp, -T Use TCP to connect to TURN server");
525 puts(" --realm, -r REALM Set realm of the credential to REALM");
526 puts(" --username, -u UID Set username of the credential to UID");
527 puts(" --password, -p PASSWD Set password of the credential to PASSWD");
528 puts(" --fingerprint, -F Use fingerprint for outgoing requests");
Benny Prijonobf7d2222008-10-02 17:54:40 +0000529 puts(" --stun-srv, -S NAME Use this STUN srv instead of TURN for Binding discovery");
530 puts(" --nameserver, -N IP Activate DNS SRV, use this DNS server");
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000531 puts(" --help, -h");
532}
533
534int main(int argc, char *argv[])
535{
536 struct pj_getopt_option long_options[] = {
537 { "realm", 1, 0, 'r'},
538 { "username", 1, 0, 'u'},
539 { "password", 1, 0, 'p'},
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000540 { "fingerprint",0, 0, 'F'},
Benny Prijono879ad1a2008-04-09 09:38:12 +0000541 { "tcp", 0, 0, 'T'},
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000542 { "help", 0, 0, 'h'},
Benny Prijonobf7d2222008-10-02 17:54:40 +0000543 { "stun-srv", 1, 0, 'S'},
544 { "nameserver", 1, 0, 'N'}
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000545 };
546 int c, opt_id;
547 char *pos;
548 pj_status_t status;
549
Benny Prijonobf7d2222008-10-02 17:54:40 +0000550 while((c=pj_getopt_long(argc,argv, "r:u:p:S:N:hFT", long_options, &opt_id))!=-1) {
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000551 switch (c) {
552 case 'r':
553 o.realm = pj_optarg;
554 break;
555 case 'u':
556 o.user_name = pj_optarg;
557 break;
558 case 'p':
559 o.password = pj_optarg;
560 break;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000561 case 'h':
562 usage();
563 return 0;
564 case 'F':
565 o.use_fingerprint = PJ_TRUE;
566 break;
Benny Prijono879ad1a2008-04-09 09:38:12 +0000567 case 'T':
568 o.use_tcp = PJ_TRUE;
569 break;
Benny Prijono3fdf3f62008-06-21 10:18:49 +0000570 case 'S':
571 o.stun_server = pj_optarg;
572 break;
Benny Prijonobf7d2222008-10-02 17:54:40 +0000573 case 'N':
574 o.nameserver = pj_optarg;
575 break;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000576 default:
577 printf("Argument \"%s\" is not valid. Use -h to see help",
578 argv[pj_optind]);
579 return 1;
580 }
581 }
582
583 if (pj_optind == argc) {
584 puts("Error: TARGET is needed");
Benny Prijono68854002008-03-20 19:21:27 +0000585 usage();
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000586 return 1;
587 }
588
589 if ((pos=pj_ansi_strchr(argv[pj_optind], ':')) != NULL) {
590 o.srv_addr = argv[pj_optind];
591 *pos = '\0';
592 o.srv_port = pos+1;
593 } else {
594 o.srv_addr = argv[pj_optind];
595 }
596
597 if ((status=init()) != 0)
598 goto on_return;
599
Benny Prijono9e6d60a2008-03-20 16:32:06 +0000600 //if ((status=create_relay()) != 0)
601 // goto on_return;
Benny Prijono5ac0bd72008-03-13 15:11:29 +0000602
603 console_main();
604
605on_return:
606 shutdown();
607 return status ? 1 : 0;
608}
609