Index: /pjproject/trunk/pjnath/src/pjturn-client/client_main.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjturn-client/client_main.c	(revision 2039)
+++ /pjproject/trunk/pjnath/src/pjturn-client/client_main.c	(revision 2040)
@@ -36,6 +36,6 @@
 struct peer
 {
-    pj_sock_t	sock;
-    pj_sockaddr	addr;
+    pj_stun_sock   *stun_sock;
+    pj_sockaddr	    mapped_addr;
 };
 
@@ -64,4 +64,5 @@
     char	*password;
     pj_bool_t	 use_fingerprint;
+    char	*stun_server;
 } o;
 
@@ -75,4 +76,12 @@
 static void turn_on_state(pj_turn_sock *relay, pj_turn_state_t old_state,
 			  pj_turn_state_t new_state);
+static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock, 
+				     pj_stun_sock_op op,
+				     pj_status_t status);
+static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
+				      void *pkt,
+				      unsigned pkt_len,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned addr_len);
 
 
@@ -123,18 +132,34 @@
      */
     for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) {
-	int len;
-	pj_sockaddr addr;
-	pj_uint16_t port;
-
-	CHECK( pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g.peer[i].sock) );
-	CHECK( pj_sock_bind_in(g.peer[i].sock, 0, 0) );
-
-	len = sizeof(addr);
-	CHECK( pj_sock_getsockname(g.peer[i].sock, &addr, &len) );
-	port = pj_sockaddr_get_port(&addr);
-
-	CHECK( pj_gethostip(pj_AF_INET(), &g.peer[i].addr) );
-	pj_sockaddr_set_port(&g.peer[i].addr, port);
-
+	pj_stun_sock_cb stun_sock_cb;
+	char name[] = "peer0";
+	pj_str_t server;
+
+	pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
+	stun_sock_cb.on_rx_data = &stun_sock_on_rx_data;
+	stun_sock_cb.on_status = &stun_sock_on_status;
+
+	g.peer[i].mapped_addr.addr.sa_family = pj_AF_INET();
+
+	name[strlen(name)-1] = '0'+i;
+	status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(), 
+				     &stun_sock_cb, NULL,
+				     &g.peer[i], &g.peer[i].stun_sock);
+	if (status != PJ_SUCCESS) {
+	    my_perror("pj_stun_sock_create()", status);
+	    return status;
+	}
+
+	if (o.stun_server)
+	    server = pj_str(o.stun_server);
+	else
+	    server = pj_str(o.srv_addr);
+	status = pj_stun_sock_start(g.peer[i].stun_sock, &server, 
+				    (pj_uint16_t)(o.srv_port?atoi(o.srv_port):PJ_STUN_PORT), 
+				    NULL);
+	if (status != PJ_SUCCESS) {
+	    my_perror("pj_stun_sock_start()", status);
+	    return status;
+	}
     }
 
@@ -162,7 +187,7 @@
     }
     for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) {
-	if (g.peer[i].sock) {
-	    pj_sock_close(g.peer[i].sock);
-	    g.peer[i].sock = 0;
+	if (g.peer[i].stun_sock) {
+	    pj_stun_sock_destroy(g.peer[i].stun_sock);
+	    g.peer[i].stun_sock = NULL;
 	}
     }
@@ -192,6 +217,4 @@
     while (!g.quit) {
 	const pj_time_val delay = {0, 10};
-	int i, n=0;
-	pj_fd_set_t readset;
 
 	/* Poll ioqueue for the TURN client */
@@ -201,40 +224,4 @@
 	pj_timer_heap_poll(g.stun_config.timer_heap, NULL);
 
-	/* Poll peer sockets */
-	PJ_FD_ZERO(&readset);
-	for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) {
-	    PJ_FD_SET(g.peer[i].sock, &readset);
-	    if (g.peer[i].sock > n)
-		n = g.peer[i].sock;
-	}
-
-	if (pj_sock_select(n+1, &readset, NULL, NULL, &delay) <= 0)
-	    continue;
-
-	/* Handle incoming data on peer socket */
-	for (i=0; i<(int)PJ_ARRAY_SIZE(g.peer); ++i) {
-	    char buf[128];
-	    pj_ssize_t len;
-	    pj_sockaddr src_addr;
-	    int src_addr_len;
-	    pj_status_t status;
-
-	    if (!PJ_FD_ISSET(g.peer[i].sock, &readset))
-		continue;
-
-	    len = sizeof(buf);
-	    src_addr_len = sizeof(src_addr);
-
-	    status = pj_sock_recvfrom(g.peer[i].sock, buf, &len, 0, 
-				      &src_addr, &src_addr_len);
-	    if (status != PJ_SUCCESS) {
-		my_perror("recvfrom error", status);
-	    } else {
-		char addrinfo[80];
-		pj_sockaddr_print(&src_addr, addrinfo, sizeof(addrinfo), 3);
-		PJ_LOG(3,(THIS_FILE, "Peer%d received %d bytes from %s: %.*s",
-			  i, len, addrinfo, len, buf));
-	    }
-	}
     }
 
@@ -325,4 +312,60 @@
 }
 
+static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock, 
+				     pj_stun_sock_op op,
+				     pj_status_t status)
+{
+    struct peer *peer = (struct peer*) pj_stun_sock_get_user_data(stun_sock);
+
+    if (status == PJ_SUCCESS) {
+	PJ_LOG(4,(THIS_FILE, "peer%d: %s success", peer-g.peer,
+		  pj_stun_sock_op_name(op)));
+    } else {
+	char errmsg[PJ_ERR_MSG_SIZE];
+	pj_strerror(status, errmsg, sizeof(errmsg));
+	PJ_LOG(1,(THIS_FILE, "peer%d: %s error: %s", peer-g.peer,
+		  pj_stun_sock_op_name(op), errmsg));
+	return PJ_FALSE;
+    }
+
+    if (op==PJ_STUN_SOCK_BINDING_OP || op==PJ_STUN_SOCK_KEEP_ALIVE_OP) {
+	pj_stun_sock_info info;
+	int cmp;
+
+	pj_stun_sock_get_info(stun_sock, &info);
+	cmp = pj_sockaddr_cmp(&info.mapped_addr, &peer->mapped_addr);
+
+	if (cmp) {
+	    char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+	    pj_sockaddr_cp(&peer->mapped_addr, &info.mapped_addr);
+	    pj_sockaddr_print(&peer->mapped_addr, straddr, sizeof(straddr), 3);
+	    PJ_LOG(3,(THIS_FILE, "peer%d: STUN mapped address is %s",
+		      peer-g.peer, straddr));
+	}
+    }
+
+    return PJ_TRUE;
+}
+
+static pj_bool_t stun_sock_on_rx_data(pj_stun_sock *stun_sock,
+				      void *pkt,
+				      unsigned pkt_len,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned addr_len)
+{
+    struct peer *peer = (struct peer*) pj_stun_sock_get_user_data(stun_sock);
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+
+    ((char*)pkt)[pkt_len] = '\0';
+
+    pj_sockaddr_print(src_addr, straddr, sizeof(straddr), 3);
+    PJ_LOG(3,(THIS_FILE, "peer%d: received %d bytes data from %s: %s",
+	      peer-g.peer, pkt_len, straddr, (char*)pkt));
+
+    return PJ_TRUE;
+}
+
+
 static void menu(void)
 {
@@ -342,6 +385,6 @@
     }
 
-    pj_sockaddr_print(&g.peer[0].addr, peer0_addr, sizeof(peer0_addr), 3);
-    pj_sockaddr_print(&g.peer[1].addr, peer1_addr, sizeof(peer1_addr), 3);
+    pj_sockaddr_print(&g.peer[0].mapped_addr, peer0_addr, sizeof(peer0_addr), 3);
+    pj_sockaddr_print(&g.peer[1].mapped_addr, peer1_addr, sizeof(peer1_addr), 3);
 
 
@@ -373,5 +416,4 @@
 	char input[32];
 	struct peer *peer;
-	pj_ssize_t len;
 	pj_status_t status;
 
@@ -400,6 +442,6 @@
 	    status = pj_turn_sock_sendto(g.relay, (const pj_uint8_t*)input, 
 					strlen(input)+1, 
-					&peer->addr, 
-					pj_sockaddr_get_len(&peer->addr));
+					&peer->mapped_addr, 
+					pj_sockaddr_get_len(&peer->mapped_addr));
 	    if (status != PJ_SUCCESS)
 		my_perror("turn_udp_sendto() failed", status);
@@ -415,6 +457,6 @@
 		peer = &g.peer[1];
 
-	    status = pj_turn_sock_bind_channel(g.relay, &peer->addr,
-					      pj_sockaddr_get_len(&peer->addr));
+	    status = pj_turn_sock_bind_channel(g.relay, &peer->mapped_addr,
+					      pj_sockaddr_get_len(&peer->mapped_addr));
 	    if (status != PJ_SUCCESS)
 		my_perror("turn_udp_bind_channel() failed", status);
@@ -435,7 +477,6 @@
 	    peer = &g.peer[input[0]-'0'];
 	    sprintf(input, "Hello from peer%d", input[0]-'0');
-	    len = strlen(input)+1;
-	    pj_sock_sendto(peer->sock, input, &len, 0, &g.relay_addr, 
-			   pj_sockaddr_get_len(&g.relay_addr));
+	    pj_stun_sock_sendto(peer->stun_sock, NULL, input, strlen(input)+1, 0,
+				&g.relay_addr, pj_sockaddr_get_len(&g.relay_addr));
 	    break;
 	case 'q':
@@ -449,7 +490,7 @@
 static void usage(void)
 {
-    puts("Usage: pjturn_client TARGET [OPTIONS]");
+    puts("Usage: pjturn_client TURN-SERVER [OPTIONS]");
     puts("");
-    puts("where TARGET is \"host[:port]\"");
+    puts("where TURN-SERVER is \"host[:port]\"");
     puts("");
     puts("and OPTIONS:");
@@ -459,4 +500,5 @@
     puts(" --password, -p PASSWD Set password of the credential to PASSWD");
     puts(" --fingerprint, -F     Use fingerprint for outgoing requests");
+    puts(" --stun-srv, -S        Use this STUN srv instead of TURN for Binding discovery");
     puts(" --help, -h");
 }
@@ -470,5 +512,6 @@
 	{ "fingerprint",0, 0, 'F'},
 	{ "tcp",        0, 0, 'T'},
-	{ "help",	0, 0, 'h'}
+	{ "help",	0, 0, 'h'},
+	{ "stun-srv",   1, 0, 'S'}
     };
     int c, opt_id;
@@ -476,5 +519,5 @@
     pj_status_t status;
 
-    while((c=pj_getopt_long(argc,argv, "r:u:p:N:hFT", long_options, &opt_id))!=-1) {
+    while((c=pj_getopt_long(argc,argv, "r:u:p:S:hFT", long_options, &opt_id))!=-1) {
 	switch (c) {
 	case 'r':
@@ -496,5 +539,7 @@
 	    o.use_tcp = PJ_TRUE;
 	    break;
-
+	case 'S':
+	    o.stun_server = pj_optarg;
+	    break;
 	default:
 	    printf("Argument \"%s\" is not valid. Use -h to see help",
