Changeset 1867 for pjproject/trunk/pjnath/src/pjturn-client/client_main.c
- Timestamp:
- Mar 13, 2008 3:11:29 PM (16 years ago)
- Location:
- pjproject/trunk/pjnath/src/pjturn-client
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjturn-client/client_main.c
r1611 r1867 34 34 35 35 36 struct peer 37 { 38 pj_sock_t sock; 39 pj_sockaddr addr; 40 }; 41 42 36 43 static struct global 37 44 { 45 pj_caching_pool cp; 46 pj_pool_t *pool; 38 47 pj_stun_config stun_config; 39 pj_pool_t *pool;40 pj_caching_pool cp;41 pj_timer_heap_t *th;42 pj_stun_session *sess;43 pj_sock_t sock;44 pj_sock_t peer_sock;45 48 pj_thread_t *thread; 46 49 pj_bool_t quit; 47 pj_sockaddr_in peer_addr; 48 pj_sockaddr_in srv_addr; 49 pj_sockaddr_in relay_addr; 50 char data_buf[256]; 51 char *data; 52 pj_bool_t detect; 53 pj_status_t detect_result; 50 51 pj_turn_udp *udp_rel; 52 pj_sockaddr relay_addr; 53 54 struct peer peer[2]; 54 55 } g; 55 56 … … 62 63 char *password; 63 64 char *nonce; 64 char *peer_addr;65 65 pj_bool_t use_fingerprint; 66 66 } o; 67 67 68 68 69 static int worker_thread(void *unused); 69 70 static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr); 71 static void turn_on_rx_data(pj_turn_udp *udp_rel, 72 const pj_uint8_t *pkt, 73 unsigned pkt_len, 74 const pj_sockaddr_t *peer_addr, 75 unsigned addr_len); 76 static void turn_on_state(pj_turn_udp *udp_rel, pj_turn_state_t old_state, 77 pj_turn_state_t new_state); 70 78 71 79 … … 78 86 } 79 87 80 static pj_status_t on_send_msg(pj_stun_session *sess, 81 const void *pkt, 82 pj_size_t pkt_size, 83 const pj_sockaddr_t *srv_addr, 84 unsigned addr_len) 85 { 86 pj_ssize_t len; 88 #define CHECK(expr) status=expr; \ 89 if (status!=PJ_SUCCESS) { \ 90 my_perror(#expr, status); \ 91 return status; \ 92 } 93 94 static int init() 95 { 96 int i; 87 97 pj_status_t status; 88 98 89 len = pkt_size; 90 status = pj_sock_sendto(g.sock, pkt, &len, 0, srv_addr, addr_len); 91 92 if (status != PJ_SUCCESS) 93 my_perror("Error sending packet", status); 94 95 return status; 96 } 97 98 static void on_request_complete(pj_stun_session *sess, 99 pj_status_t status, 100 pj_stun_tx_data *tdata, 101 const pj_stun_msg *response, 102 const pj_sockaddr_t *src_addr, 103 unsigned src_addr_len) 104 { 105 PJ_UNUSED_ARG(src_addr); 106 PJ_UNUSED_ARG(src_addr_len); 107 108 if (status == PJ_SUCCESS) { 109 switch (response->hdr.type) { 110 case PJ_STUN_ALLOCATE_RESPONSE: 111 { 112 pj_stun_relay_addr_attr *ar; 113 pj_stun_lifetime_attr *al; 114 115 al = (pj_stun_lifetime_attr*) 116 pj_stun_msg_find_attr(response, 117 PJ_STUN_ATTR_LIFETIME, 0); 118 if (!al) { 119 PJ_LOG(1,(THIS_FILE, "Error: LIFETIME attribute not present")); 120 return; 121 } 122 123 ar = (pj_stun_relay_addr_attr*) 124 pj_stun_msg_find_attr(response, 125 PJ_STUN_ATTR_RELAY_ADDR, 0); 126 if (ar) { 127 pj_memcpy(&g.relay_addr, &ar->sockaddr.ipv4, 128 sizeof(pj_sockaddr_in)); 129 PJ_LOG(3,(THIS_FILE, "Relay address is %s:%d", 130 pj_inet_ntoa(g.relay_addr.sin_addr), 131 (int)pj_ntohs(g.relay_addr.sin_port))); 132 } else { 133 pj_memset(&g.relay_addr, 0, sizeof(g.relay_addr)); 134 } 135 136 if (al->value == 0) { 137 PJ_LOG(3,(THIS_FILE, "Relay deallocated")); 138 } 99 CHECK( pj_init() ); 100 CHECK( pjlib_util_init() ); 101 CHECK( pjnath_init() ); 102 103 /* Check that server is specified */ 104 if (!o.srv_addr) { 105 printf("Error: server must be specified\n"); 106 return PJ_EINVAL; 107 } 108 109 pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0); 110 111 g.pool = pj_pool_create(&g.cp.factory, "main", 1000, 1000, NULL); 112 113 /* Init global STUN config */ 114 pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, NULL); 115 116 /* Create global timer heap */ 117 CHECK( pj_timer_heap_create(g.pool, 1000, &g.stun_config.timer_heap) ); 118 119 /* Create global ioqueue */ 120 CHECK( pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue) ); 121 122 /* 123 * Create peers 124 */ 125 for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { 126 int len; 127 pj_sockaddr addr; 128 pj_uint16_t port; 129 130 CHECK( pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g.peer[i].sock) ); 131 CHECK( pj_sock_bind_in(g.peer[i].sock, 0, 0) ); 132 133 len = sizeof(addr); 134 CHECK( pj_sock_getsockname(g.peer[i].sock, &addr, &len) ); 135 port = pj_sockaddr_get_port(&g.peer[i].addr); 136 137 CHECK( pj_gethostip(pj_AF_INET(), &g.peer[i].addr) ); 138 pj_sockaddr_set_port(&g.peer[0].addr, port); 139 140 } 141 142 /* Start the worker thread */ 143 CHECK( pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread) ); 144 145 146 return PJ_SUCCESS; 147 } 148 149 150 static int shutdown() 151 { 152 unsigned i; 153 154 if (g.thread) { 155 g.quit = 1; 156 pj_thread_join(g.thread); 157 pj_thread_destroy(g.thread); 158 g.thread = NULL; 159 } 160 if (g.udp_rel) { 161 pj_turn_udp_destroy(g.udp_rel); 162 g.udp_rel = NULL; 163 } 164 for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { 165 if (g.peer[i].sock) { 166 pj_sock_close(g.peer[i].sock); 167 g.peer[i].sock = 0; 168 } 169 } 170 if (g.stun_config.timer_heap) { 171 pj_timer_heap_destroy(g.stun_config.timer_heap); 172 g.stun_config.timer_heap = NULL; 173 } 174 if (g.stun_config.ioqueue) { 175 pj_ioqueue_destroy(g.stun_config.ioqueue); 176 g.stun_config.ioqueue = NULL; 177 } 178 if (g.pool) { 179 pj_pool_release(g.pool); 180 g.pool = NULL; 181 } 182 pj_pool_factory_dump(&g.cp.factory, PJ_TRUE); 183 pj_caching_pool_destroy(&g.cp); 184 185 return PJ_SUCCESS; 186 } 187 188 189 static int worker_thread(void *unused) 190 { 191 PJ_UNUSED_ARG(unused); 192 193 while (!g.quit) { 194 const pj_time_val delay = {0, 10}; 195 int i; 196 pj_fd_set_t readset; 197 198 /* Poll ioqueue for the TURN client */ 199 pj_ioqueue_poll(g.stun_config.ioqueue, &delay); 200 201 /* Poll the timer heap */ 202 pj_timer_heap_poll(g.stun_config.timer_heap, NULL); 203 204 /* Poll peer sockets */ 205 PJ_FD_ZERO(&readset); 206 for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { 207 PJ_FD_SET(g.peer[i].sock, &readset); 208 } 209 210 if (pj_sock_select(64, &readset, NULL, NULL, &delay) <= 0) 211 continue; 212 213 /* Handle incoming data on peer socket */ 214 for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { 215 char buf[128]; 216 pj_ssize_t len; 217 pj_sockaddr src_addr; 218 int src_addr_len; 219 pj_status_t status; 220 221 if (!PJ_FD_ISSET(g.peer[i].sock, &readset)) 222 continue; 223 224 len = sizeof(buf); 225 src_addr_len = sizeof(src_addr); 226 227 status = pj_sock_recvfrom(g.peer[i].sock, buf, &len, 0, 228 &src_addr, &src_addr_len); 229 if (status != PJ_SUCCESS) { 230 my_perror("recvfrom error", status); 231 } else { 232 char addrinfo[80]; 233 pj_sockaddr_print(&src_addr, addrinfo, sizeof(addrinfo), 3); 234 PJ_LOG(3,(THIS_FILE, "Peer%d received %d bytes from %s: %.*s", 235 i, len, addrinfo, len, buf)); 139 236 } 140 break;141 237 } 142 } else {143 my_perror("Client transaction error", status);144 }145 }146 147 static int worker_thread(void *unused)148 {149 PJ_UNUSED_ARG(unused);150 151 while (!g.quit) {152 pj_time_val timeout = {0, 50};153 pj_fd_set_t readset;154 int n;155 156 pj_timer_heap_poll(g.th, NULL);157 pj_ioqueue_poll(g.stun_config.ioqueue, &timeout);158 159 PJ_FD_ZERO(&readset);160 PJ_FD_SET(g.sock, &readset);161 PJ_FD_SET(g.peer_sock, &readset);162 163 n = (g.peer_sock > g.sock) ? g.peer_sock : g.sock;164 n = pj_sock_select(n+1, &readset, NULL, NULL, &timeout);165 if (n > 0) {166 if (PJ_FD_ISSET(g.sock, &readset)) {167 pj_uint8_t buffer[512];168 pj_ssize_t len;169 pj_sockaddr_in addr;170 int addrlen;171 pj_status_t rc;172 173 len = sizeof(buffer);174 addrlen = sizeof(addr);175 rc = pj_sock_recvfrom(g.sock, buffer, &len, 0, &addr, &addrlen);176 if (rc != PJ_SUCCESS || len <= 0)177 continue;178 179 if (pj_stun_msg_check(buffer, len, PJ_STUN_IS_DATAGRAM)==PJ_SUCCESS) {180 rc = pj_stun_session_on_rx_pkt(g.sess, buffer, len,181 OPTIONS,182 NULL, &addr, addrlen);183 if (rc != PJ_SUCCESS)184 my_perror("Error processing packet", rc);185 186 } else {187 buffer[len] = '\0';188 PJ_LOG(3,(THIS_FILE, "Received data on client sock: %s", (char*)buffer));189 }190 191 } else if (PJ_FD_ISSET(g.peer_sock, &readset)) {192 pj_uint8_t buffer[512];193 pj_ssize_t len;194 pj_sockaddr_in addr;195 int addrlen;196 pj_status_t rc;197 198 len = sizeof(buffer);199 addrlen = sizeof(addr);200 rc = pj_sock_recvfrom(g.peer_sock, buffer, &len, 0, &addr, &addrlen);201 if (rc != PJ_SUCCESS || len <= 0)202 continue;203 204 buffer[len] = '\0';205 206 if (pj_stun_msg_check(buffer, len, PJ_STUN_IS_DATAGRAM)==PJ_SUCCESS) {207 pj_stun_msg *msg;208 209 rc = pj_stun_msg_decode(g.pool, (pj_uint8_t*)buffer, len, 0,210 &msg, NULL, NULL);211 if (rc != PJ_SUCCESS) {212 my_perror("Error decoding packet on peer sock", rc);213 } else {214 pj_stun_msg_dump(msg, (char*)buffer, sizeof(buffer), NULL);215 PJ_LOG(3,(THIS_FILE, "Received STUN packet on peer sock: %s",216 buffer));217 }218 219 } else {220 PJ_LOG(3,(THIS_FILE, "Received data on peer sock: %s", (char*)buffer));221 }222 223 }224 225 } else if (n < 0)226 pj_thread_sleep(50);227 238 } 228 239 … … 230 241 } 231 242 232 static int init()233 { 234 pj_ sockaddr addr;235 pj_stun_ session_cb stun_cb;236 int len;243 static pj_status_t create_relay(void) 244 { 245 pj_turn_udp_cb rel_cb; 246 pj_stun_auth_cred cred; 247 pj_str_t srv; 237 248 pj_status_t status; 238 249 239 g.sock = PJ_INVALID_SOCKET; 240 241 status = pj_init(); 242 status = pjlib_util_init(); 243 status = pjnath_init(); 244 245 pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0); 246 247 if (o.srv_addr) { 248 pj_str_t s; 249 pj_uint16_t port; 250 251 if (o.srv_port) 252 port = (pj_uint16_t) atoi(o.srv_port); 253 else 254 port = PJ_STUN_PORT; 255 256 status = pj_sockaddr_in_init(&g.srv_addr, pj_cstr(&s, o.srv_addr), port); 257 if (status != PJ_SUCCESS) { 258 my_perror("Invalid address", status); 259 return status; 260 } 261 262 printf("Destination address set to %s:%d\n", o.srv_addr, (int)port); 263 } else { 264 printf("Error: address must be specified\n"); 265 return PJ_EINVAL; 266 } 267 268 g.pool = pj_pool_create(&g.cp.factory, NULL, 1000, 1000, NULL); 269 270 status = pj_timer_heap_create(g.pool, 1000, &g.th); 271 pj_assert(status == PJ_SUCCESS); 272 273 pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, g.th); 274 pj_assert(status == PJ_SUCCESS); 275 276 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g.peer_sock); 277 pj_assert(status == PJ_SUCCESS); 278 279 status = pj_sock_bind_in(g.peer_sock, 0, 0); 280 pj_assert(status == PJ_SUCCESS); 281 282 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g.sock); 283 pj_assert(status == PJ_SUCCESS); 284 285 status = pj_sockaddr_in_init(&addr.ipv4, NULL, 0); 286 pj_assert(status == PJ_SUCCESS); 287 288 addr.ipv4.sin_port = pj_htons((pj_uint16_t)LOCAL_PORT); 289 status = pj_sock_bind(g.sock, &addr, sizeof(addr)); 290 pj_assert(status == PJ_SUCCESS); 291 292 len = sizeof(addr); 293 status = pj_sock_getsockname(g.sock, &addr, &len); 294 pj_assert(status == PJ_SUCCESS); 295 296 PJ_LOG(3,(THIS_FILE, "Listening on port %d", (int)pj_ntohs(addr.ipv4.sin_port))); 297 298 len = sizeof(g.peer_addr); 299 status = pj_sock_getsockname(g.peer_sock, &g.peer_addr, &len); 300 if (g.peer_addr.sin_addr.s_addr == 0) 301 pj_gethostip(pj_AF_INET(), (pj_sockaddr*)&g.peer_addr.sin_addr); 302 303 PJ_LOG(3,(THIS_FILE, "Peer is on port %d", (int)pj_ntohs(g.peer_addr.sin_port))); 304 305 pj_memset(&stun_cb, 0, sizeof(stun_cb)); 306 stun_cb.on_send_msg = &on_send_msg; 307 stun_cb.on_request_complete = &on_request_complete; 308 309 status = pj_stun_session_create(&g.stun_config, NULL, &stun_cb, 310 o.use_fingerprint!=0, &g.sess); 311 pj_assert(status == PJ_SUCCESS); 250 if (g.udp_rel) { 251 PJ_LOG(1,(THIS_FILE, "Relay already created")); 252 return -1; 253 } 254 255 pj_bzero(&rel_cb, sizeof(rel_cb)); 256 rel_cb.on_rx_data = &turn_on_rx_data; 257 rel_cb.on_state = &turn_on_state; 258 CHECK( pj_turn_udp_create(&g.stun_config, pj_AF_INET(), &rel_cb, 0, 259 NULL, &g.udp_rel) ); 312 260 313 261 if (o.user_name) { 314 pj_stun_auth_cred cred;315 316 262 pj_bzero(&cred, sizeof(cred)); 317 318 263 cred.type = PJ_STUN_AUTH_CRED_STATIC; 319 264 cred.data.static_cred.realm = pj_str(o.realm); … … 322 267 cred.data.static_cred.data = pj_str(o.password); 323 268 cred.data.static_cred.nonce = pj_str(o.nonce); 324 325 pj_stun_session_set_credential(g.sess, &cred);326 puts("Session credential set");327 269 } else { 328 puts("Credential not set"); 329 } 330 331 if (o.peer_addr) { 332 if (parse_addr(o.peer_addr, &g.peer_addr)!=PJ_SUCCESS) 333 return -1; 334 } 335 336 status = pj_ioqueue_create(g.pool, 16, &g.stun_config.ioqueue); 337 if (status != PJ_SUCCESS) 338 return status; 339 340 status = pj_thread_create(g.pool, "stun", &worker_thread, NULL, 341 0, 0, &g.thread); 342 if (status != PJ_SUCCESS) 343 return status; 270 PJ_LOG(2,(THIS_FILE, "Warning: no credential is set")); 271 } 272 273 srv = pj_str(o.srv_addr); 274 CHECK( pj_turn_udp_init(g.udp_rel, /* the relay */ 275 &srv, /* srv addr */ 276 (o.srv_port?atoi(o.srv_port):PJ_STUN_PORT),/* def port */ 277 NULL, /* resolver */ 278 (o.user_name?&cred:NULL), /* credential */ 279 NULL) /* alloc param */ 280 ); 344 281 345 282 return PJ_SUCCESS; 346 283 } 347 284 348 349 static int shutdown() 350 { 351 if (g.thread) { 352 g.quit = 1; 353 pj_thread_join(g.thread); 354 pj_thread_destroy(g.thread); 355 g.thread = NULL; 356 } 357 if (g.sess) 358 pj_stun_session_destroy(g.sess); 359 if (g.sock != PJ_INVALID_SOCKET) 360 pj_sock_close(g.sock); 361 if (g.th) 362 pj_timer_heap_destroy(g.th); 363 if (g.pool) 364 pj_pool_release(g.pool); 365 366 pj_pool_factory_dump(&g.cp.factory, PJ_TRUE); 367 pj_caching_pool_destroy(&g.cp); 368 369 return PJ_SUCCESS; 370 } 371 372 static void send_bind_request(void) 373 { 374 pj_stun_tx_data *tdata; 375 pj_status_t rc; 376 377 rc = pj_stun_session_create_req(g.sess, PJ_STUN_BINDING_REQUEST, 378 PJ_STUN_MAGIC, NULL, &tdata); 379 pj_assert(rc == PJ_SUCCESS); 380 381 rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, 382 &g.srv_addr, sizeof(g.srv_addr), 383 tdata); 384 if (rc != PJ_SUCCESS) 385 my_perror("Error sending STUN request", rc); 386 } 387 388 static void send_allocate_request(pj_bool_t allocate) 389 { 390 pj_stun_tx_data *tdata; 391 pj_status_t rc; 392 393 rc = pj_stun_session_create_req(g.sess, PJ_STUN_ALLOCATE_REQUEST, 394 PJ_STUN_MAGIC, NULL, &tdata); 395 pj_assert(rc == PJ_SUCCESS); 396 397 398 if (BANDWIDTH != -1) { 399 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 400 PJ_STUN_ATTR_BANDWIDTH, BANDWIDTH); 401 } 402 403 if (!allocate) { 404 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 405 PJ_STUN_ATTR_LIFETIME, 0); 406 407 } else { 408 if (LIFETIME != -1) { 409 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 410 PJ_STUN_ATTR_LIFETIME, LIFETIME); 411 } 412 413 if (REQ_TRANSPORT != -1) { 414 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 415 PJ_STUN_ATTR_REQ_TRANSPORT, REQ_TRANSPORT); 416 } 417 418 if (REQ_PORT_PROPS != -1) { 419 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 420 PJ_STUN_ATTR_REQ_PORT_PROPS, REQ_PORT_PROPS); 421 } 422 423 if (REQ_IP) { 424 pj_sockaddr_in addr; 425 pj_str_t tmp; 426 427 pj_sockaddr_in_init(&addr, pj_cstr(&tmp, REQ_IP), 0); 428 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 429 PJ_STUN_ATTR_REQ_IP, PJ_FALSE, 430 &addr, sizeof(addr)); 431 } 432 } 433 434 rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, 435 &g.srv_addr, sizeof(g.srv_addr), 436 tdata); 437 pj_assert(rc == PJ_SUCCESS); 438 } 439 440 static void send_sad_request(pj_bool_t set) 441 { 442 pj_stun_tx_data *tdata; 443 pj_status_t rc; 444 445 if (g.peer_addr.sin_addr.s_addr == 0 || 446 g.peer_addr.sin_port == 0) 447 { 448 puts("Error: peer address is not set"); 449 return; 450 } 451 452 rc = pj_stun_session_create_req(g.sess, 453 PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST, 454 PJ_STUN_MAGIC, NULL, &tdata); 455 pj_assert(rc == PJ_SUCCESS); 456 457 if (set) { 458 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 459 PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE, 460 &g.peer_addr, sizeof(g.peer_addr)); 461 } 462 463 rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, 464 &g.srv_addr, sizeof(g.srv_addr), 465 tdata); 466 pj_assert(rc == PJ_SUCCESS); 467 } 468 469 static void send_send_ind(void) 470 { 471 pj_stun_tx_data *tdata; 472 int len; 473 pj_status_t rc; 474 475 if (g.peer_addr.sin_addr.s_addr == 0 || 476 g.peer_addr.sin_port == 0) 477 { 478 puts("Error: peer address is not set"); 479 return; 480 } 481 482 len = strlen(g.data); 483 if (len==0) { 484 puts("Error: data is not set"); 485 return; 486 } 487 488 rc = pj_stun_session_create_ind(g.sess, PJ_STUN_SEND_INDICATION, &tdata); 489 pj_assert(rc == PJ_SUCCESS); 490 491 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 492 PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE, 493 &g.peer_addr, sizeof(g.peer_addr)); 494 pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, 495 PJ_STUN_ATTR_DATA, (pj_uint8_t*)g.data, len); 496 497 rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, 498 &g.srv_addr, sizeof(g.srv_addr), 499 tdata); 500 pj_assert(rc == PJ_SUCCESS); 501 502 } 503 504 static void send_raw_data_to_srv(void) 505 { 506 pj_ssize_t len; 507 508 if (g.srv_addr.sin_addr.s_addr == 0 || 509 g.srv_addr.sin_port == 0) 510 { 511 puts("Error: server address is not set"); 512 return; 513 } 514 515 len = strlen(g.data); 516 if (len==0) { 517 puts("Error: data is not set"); 518 return; 519 } 520 521 len = strlen(g.data); 522 pj_sock_sendto(g.sock, g.data, &len, 0, &g.srv_addr, sizeof(g.srv_addr)); 523 } 524 525 static void send_raw_data_to_relay(void) 526 { 527 pj_ssize_t len; 528 529 if (g.relay_addr.sin_addr.s_addr == 0 || 530 g.relay_addr.sin_port == 0) 531 { 532 puts("Error: relay address is not set"); 533 return; 534 } 535 536 len = strlen(g.data); 537 if (len==0) { 538 puts("Error: data is not set"); 539 return; 540 } 541 542 len = strlen(g.data); 543 pj_sock_sendto(g.peer_sock, g.data, &len, 0, &g.relay_addr, sizeof(g.relay_addr)); 285 static void destroy_relay(void) 286 { 287 if (g.udp_rel) { 288 pj_turn_udp_destroy(g.udp_rel); 289 g.udp_rel = NULL; 290 } 291 } 292 293 294 static void turn_on_rx_data(pj_turn_udp *udp_rel, 295 const pj_uint8_t *pkt, 296 unsigned pkt_len, 297 const pj_sockaddr_t *peer_addr, 298 unsigned addr_len) 299 { 300 char addrinfo[80]; 301 302 pj_sockaddr_print(peer_addr, addrinfo, sizeof(addrinfo), 3); 303 304 PJ_LOG(3,(THIS_FILE, "Client received %d bytes data from %s: %.*s", 305 pkt_len, addrinfo, pkt_len, pkt)); 306 } 307 308 309 static void turn_on_state(pj_turn_udp *udp_rel, pj_turn_state_t old_state, 310 pj_turn_state_t new_state) 311 { 312 if (new_state == PJ_TURN_STATE_READY) { 313 pj_turn_session_info info; 314 pj_turn_udp_get_info(udp_rel, &info); 315 pj_memcpy(&g.relay_addr, &info.relay_addr, sizeof(pj_sockaddr)); 316 } 544 317 } 545 318 … … 577 350 } 578 351 579 static void set_peer_addr(void) 580 { 581 char addr[64]; 582 583 printf("Current peer address: %s:%d\n", 584 pj_inet_ntoa(g.peer_addr.sin_addr), 585 pj_ntohs(g.peer_addr.sin_port)); 586 587 printf("Input peer address in IP:PORT format: "); 352 static void menu(void) 353 { 354 pj_turn_session_info info; 355 char client_state[20], relay_addr[80], peer0_addr[80], peer1_addr[80]; 356 357 if (g.udp_rel) { 358 pj_turn_udp_get_info(g.udp_rel, &info); 359 strcpy(client_state, pj_turn_state_name(info.state)); 360 pj_sockaddr_print(&info.relay_addr, relay_addr, sizeof(relay_addr), 3); 361 } else { 362 strcpy(client_state, "NULL"); 363 strcpy(relay_addr, "0.0.0.0:0"); 364 } 365 366 pj_sockaddr_print(&g.peer[0].addr, peer0_addr, sizeof(peer0_addr), 3); 367 pj_sockaddr_print(&g.peer[1].addr, peer1_addr, sizeof(peer1_addr), 3); 368 369 370 puts("\n"); 371 puts("+====================================================================+"); 372 puts("| CLIENT | PEER-0 |"); 373 puts("| | |"); 374 printf("| State : %12s | Address: %21s |\n", 375 client_state, peer0_addr); 376 printf("| Relay addr: %21s | |\n", 377 relay_addr); 378 puts("| | 0 Send data to relay address |"); 379 puts("| A Allocate relay +--------------------------------+ "); 380 puts("| S[01] Send data to peer 0/1 | PEER-1 |"); 381 puts("| B[01] BindChannel to peer 0/1 | |"); 382 printf("| X Delete allocation | Address: %21s |\n", 383 peer1_addr); 384 puts("+-----------------------------------+ |"); 385 puts("| q Quit | 1 Send data to relay adderss |"); 386 puts("+-----------------------------------+--------------------------------+"); 387 printf(">>> "); 588 388 fflush(stdout); 589 fgets(addr, sizeof(addr), stdin);590 591 if (parse_addr(addr, &g.peer_addr) != PJ_SUCCESS) {592 return;593 }594 595 }596 597 598 static void nat_detect_cb(void *user_data,599 const pj_stun_nat_detect_result *res)600 {601 g.detect_result = res->status;602 603 if (res->status == PJ_SUCCESS) {604 PJ_LOG(3,(THIS_FILE, "NAT successfully detected as %s", res->nat_type_name));605 } else {606 PJ_LOG(2,(THIS_FILE, "Error detecting NAT type: %s", res->status_text));607 }608 }609 610 static pj_status_t perform_detection()611 {612 pj_status_t status;613 614 g.detect_result = PJ_EPENDING;615 status = pj_stun_detect_nat_type(&g.srv_addr, &g.stun_config, NULL,616 &nat_detect_cb);617 if (status != PJ_SUCCESS)618 return status;619 620 while (g.detect_result == PJ_EPENDING)621 pj_thread_sleep(100);622 623 status = g.detect_result;624 625 return status;626 }627 628 629 static void menu(void)630 {631 puts("Menu:");632 puts(" d Perform NAT detection");633 printf(" pr Set peer address (currently %s:%d)\n",634 pj_inet_ntoa(g.peer_addr.sin_addr), pj_ntohs(g.peer_addr.sin_port));635 printf(" dt Set data (currently \"%s\")\n", g.data);636 puts(" br Send Bind request");637 puts(" ar Send Allocate request");638 puts(" dr Send de-Allocate request");639 puts(" sr Send Set Active Destination request");640 puts(" cr Send clear Active Destination request");641 puts(" si Send data with Send Indication");642 puts(" rw Send raw data to TURN server");643 puts(" rW Send raw data to relay address");644 puts(" q Quit");645 puts("");646 printf("Choice: ");647 389 } 648 390 … … 651 393 { 652 394 while (!g.quit) { 653 char input[10]; 395 char input[32]; 396 struct peer *peer; 397 pj_ssize_t len; 398 pj_status_t status; 654 399 655 400 menu(); … … 657 402 fgets(input, sizeof(input), stdin); 658 403 659 if (input[0] == 'd' && (input[1]=='\r' || input[1]=='\n')) { 660 661 perform_detection(); 662 663 } else if (input[0]=='d' && input[1]=='t') { 664 printf("Input data: "); 665 fgets(g.data, sizeof(g.data_buf), stdin); 666 667 } else if (input[0]=='p' && input[1]=='r') { 668 set_peer_addr(); 669 670 } else if (input[0]=='b' && input[1]=='r') { 671 send_bind_request(); 672 673 } else if (input[0]=='a' && input[1]=='r') { 674 send_allocate_request(PJ_TRUE); 675 676 } else if (input[0]=='d' && input[1]=='r') { 677 send_allocate_request(PJ_FALSE); 678 679 } else if (input[0]=='s' && input[1]=='r') { 680 send_sad_request(PJ_TRUE); 681 682 } else if (input[0]=='c' && input[1]=='r') { 683 send_sad_request(PJ_FALSE); 684 685 } else if (input[0]=='s' && input[1]=='i') { 686 send_send_ind(); 687 688 } else if (input[0]=='r' && input[1]=='w') { 689 send_raw_data_to_srv(); 690 691 } else if (input[0]=='r' && input[1]=='W') { 692 send_raw_data_to_relay(); 693 694 } else if (input[0]=='q') { 695 g.quit = 1; 404 switch (input[0]) { 405 case 'A': 406 create_relay(); 407 break; 408 case 'S': 409 if (g.udp_rel == NULL) { 410 puts("Error: no relay"); 411 continue; 412 } 413 if (input[1] != '0' && input[1] != '1') { 414 puts("Usage: S0 or S1"); 415 continue; 416 } 417 peer = &g.peer[input[1]-'0']; 418 strcpy(input, "Hello from client"); 419 status = pj_turn_udp_sendto(g.udp_rel, input, strlen(input)+1, 420 &peer->addr, 421 pj_sockaddr_get_len(&peer->addr)); 422 if (status != PJ_SUCCESS) 423 my_perror("turn_udp_sendto() failed", status); 424 break; 425 case 'B': 426 if (g.udp_rel == NULL) { 427 puts("Error: no relay"); 428 continue; 429 } 430 if (input[1] != '0' && input[1] != '1') { 431 puts("Usage: B0 or B1"); 432 continue; 433 } 434 peer = &g.peer[input[1]-'0']; 435 status = pj_turn_udp_bind_channel(g.udp_rel, &peer->addr, 436 pj_sockaddr_get_len(&peer->addr)); 437 if (status != PJ_SUCCESS) 438 my_perror("turn_udp_bind_channel() failed", status); 439 break; 440 case 'X': 441 if (g.udp_rel == NULL) { 442 puts("Error: no relay"); 443 continue; 444 } 445 destroy_relay(); 446 break; 447 case '0': 448 case '1': 449 peer = &g.peer[input[1]-'0']; 450 sprintf(input, "Hello from peer%d", input[0]-'0'); 451 len = strlen(input)+1; 452 pj_sock_sendto(peer->sock, input, &len, 0, &g.relay_addr, 453 pj_sockaddr_get_len(&g.relay_addr)); 454 break; 455 case 'q': 456 g.quit = PJ_TRUE; 457 break; 696 458 } 697 459 } … … 701 463 static void usage(void) 702 464 { 703 puts("Usage: pj stun_client TARGET [OPTIONS]");465 puts("Usage: pjturn_client TARGET [OPTIONS]"); 704 466 puts(""); 705 467 puts("where TARGET is \"host[:port]\""); 706 468 puts(""); 707 469 puts("and OPTIONS:"); 708 puts(" --detect, -d Perform NAT type detection first");709 470 puts(" --realm, -r Set realm of the credential"); 710 471 puts(" --username, -u Set username of the credential"); … … 712 473 puts(" --nonce, -N Set NONCE"); 713 474 puts(" --fingerprint, -F Use fingerprint for outgoing requests"); 714 puts(" --peer, -P Set peer address (address is in HOST:PORT format)");715 puts(" --data, -D Set data");716 475 puts(" --help, -h"); 717 476 } … … 720 479 { 721 480 struct pj_getopt_option long_options[] = { 722 { "detect", 0, 0, 'd'},723 481 { "realm", 1, 0, 'r'}, 724 482 { "username", 1, 0, 'u'}, … … 726 484 { "nonce", 1, 0, 'N'}, 727 485 { "fingerprint",0, 0, 'F'}, 728 { "peer", 1, 0, 'P'},729 486 { "data", 1, 0, 'D'}, 730 487 { "help", 0, 0, 'h'} … … 734 491 pj_status_t status; 735 492 736 g.data = g.data_buf; 737 pj_ansi_strcpy(g.data, "Hello world"); 738 739 while((c=pj_getopt_long(argc,argv, "r:u:p:N:dhF", long_options, &opt_id))!=-1) { 493 while((c=pj_getopt_long(argc,argv, "r:u:p:N:hF", long_options, &opt_id))!=-1) { 740 494 switch (c) { 741 case 'd':742 g.detect = PJ_TRUE;743 break;744 495 case 'r': 745 496 o.realm = pj_optarg; … … 759 510 case 'F': 760 511 o.use_fingerprint = PJ_TRUE; 761 break;762 case 'P':763 o.peer_addr = pj_optarg;764 break;765 case 'D':766 g.data = pj_optarg;767 512 break; 768 513 … … 787 532 } 788 533 789 status = init(); 790 if (status != PJ_SUCCESS) 534 if ((status=init()) != 0) 791 535 goto on_return; 792 536 793 if (g.detect) { 794 status = perform_detection(); 795 if (status != PJ_SUCCESS) 796 goto on_return; 797 } 798 537 if ((status=create_relay()) != 0) 538 goto on_return; 539 799 540 console_main(); 800 541
Note: See TracChangeset
for help on using the changeset viewer.