Index: pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp
===================================================================
--- pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp	(revision 1039)
+++ pjproject/trunk/pjlib-util/build/pjstun_srv_test.dsp	(revision 1040)
@@ -43,5 +43,5 @@
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
+# ADD CPP /nologo /MD /W4 /GX /O2 /I "../include" /I "../../pjlib/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c
 # ADD BASE RSC /l 0x409 /d "NDEBUG"
 # ADD RSC /l 0x409 /d "NDEBUG"
@@ -67,5 +67,5 @@
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c
 # ADD BASE RSC /l 0x409 /d "_DEBUG"
 # ADD RSC /l 0x409 /d "_DEBUG"
@@ -88,5 +88,17 @@
 # Begin Source File
 
+SOURCE="..\src\pjstun-srv-test\bind_usage.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjstun-srv-test\main.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjstun-srv-test\server.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjstun-srv-test\usage.c"
 # End Source File
 # End Group
@@ -94,4 +106,8 @@
 
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE="..\src\pjstun-srv-test\server.h"
+# End Source File
 # End Group
 # Begin Group "Resource Files"
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c	(revision 1039)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c	(revision 1040)
@@ -41,5 +41,5 @@
 	return PJ_ENOMEM;
     
-    endpt = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_endpoint);
+    endpt = PJ_POOL_ZALLOC_T(pool, pj_stun_endpoint);
     endpt->pool = pool;
     endpt->pf = factory;
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1039)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1040)
@@ -527,5 +527,5 @@
 		     addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
     INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
 
@@ -581,5 +581,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_ip_addr_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
     pj_memcpy(attr, buf, ATTR_HDR_LEN);
 
@@ -674,5 +674,5 @@
     PJ_ASSERT_RETURN(pool && value && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
     INIT_ATTR(attr, attr_type, value->slen);
     pj_strdup(pool, &attr->value, value);
@@ -713,5 +713,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_string_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
 
     /* Copy the header */
@@ -787,5 +787,5 @@
     PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_empty_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
     INIT_ATTR(attr, attr_type, sizeof(pj_stun_empty_attr));
 
@@ -806,5 +806,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_empty_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
     pj_memcpy(attr, buf, ATTR_HDR_LEN);
 
@@ -865,5 +865,5 @@
     PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
     INIT_ATTR(attr, attr_type, STUN_UINT_LEN);
     attr->value = value;
@@ -905,5 +905,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_uint_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
     pj_memcpy(attr, buf, ATTR_LEN);
 
@@ -968,5 +968,5 @@
     PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
     INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, STUN_MSG_INTEGRITY_LEN);
 
@@ -1004,5 +1004,5 @@
 
     /* Create attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msgint_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
     pj_memcpy(attr, buf, sizeof(pj_stun_msgint_attr));
     attr->hdr.type = pj_ntohs(attr->hdr.type);
@@ -1074,5 +1074,5 @@
     }
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
     INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen);
     attr->err_class = (pj_uint8_t)(err_code / 100);
@@ -1110,5 +1110,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_errcode_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
 
     /* Copy the header */
@@ -1187,5 +1187,5 @@
     PJ_ASSERT_RETURN(pool && attr_cnt < PJ_STUN_MAX_ATTR && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_unknown_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
     INIT_ATTR(attr, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, attr_cnt * 2);
 
@@ -1233,5 +1233,5 @@
     unsigned i;
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_unknown_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
     pj_memcpy(attr, buf, ATTR_HDR_LEN);
 
@@ -1310,5 +1310,5 @@
     PJ_ASSERT_RETURN(pool && attr_type && p_attr, PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_binary_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
     INIT_ATTR(attr, attr_type, sizeof(pj_stun_binary_attr));
 
@@ -1352,5 +1352,5 @@
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_binary_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
 
     /* Copy the header */
@@ -1419,5 +1419,5 @@
     PJ_ASSERT_RETURN(pool && msg_type && p_msg, PJ_EINVAL);
 
-    msg = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg);
+    msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
     msg->hdr.type = (pj_uint16_t) msg_type;
     msg->hdr.magic = magic;
@@ -1606,5 +1606,5 @@
 
     /* Create the message, copy the header, and convert to host byte order */
-    msg = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg);
+    msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
     pj_memcpy(&msg->hdr, pdu, sizeof(pj_stun_msg_hdr));
     msg->hdr.type = pj_ntohs(msg->hdr.type);
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c	(revision 1039)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c	(revision 1040)
@@ -125,5 +125,5 @@
     PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
 
-    tdata = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_tx_data);
+    tdata = PJ_POOL_ZALLOC_T(pool, pj_stun_tx_data);
     tdata->pool = pool;
     tdata->sess = sess;
@@ -321,5 +321,5 @@
     PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
 
-    sess = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_session);
+    sess = PJ_POOL_ZALLOC_T(pool, pj_stun_session);
     sess->endpt = endpt;
     sess->pool = pool;
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 1039)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 1040)
@@ -74,5 +74,5 @@
     PJ_ASSERT_RETURN(cb->on_send_msg, PJ_EINVAL);
 
-    tsx = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_client_tsx);
+    tsx = PJ_POOL_ZALLOC_T(pool, pj_stun_client_tsx);
     tsx->endpt = endpt;
     pj_memcpy(&tsx->cb, cb, sizeof(*cb));
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c	(revision 1040)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c	(revision 1040)
@@ -0,0 +1,174 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include "server.h"
+
+#define THIS_FILE   "bind_usage.c"
+
+static void usage_on_rx_data(pj_stun_usage *usage,
+			     void *pkt,
+			     pj_size_t pkt_size,
+			     const pj_sockaddr_t *src_addr,
+			     unsigned src_addr_len);
+static pj_status_t sess_on_send_msg(pj_stun_session *sess,
+				    const void *pkt,
+				    pj_size_t pkt_size,
+				    const pj_sockaddr_t *dst_addr,
+				    unsigned addr_len);
+static pj_status_t sess_on_rx_request(pj_stun_session *sess,
+				      const pj_uint8_t *pkt,
+				      unsigned pkt_len,
+				      const pj_stun_msg *msg,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len);
+
+PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
+					      const pj_str_t *ip_addr,
+					      unsigned port,
+					      pj_stun_usage **p_bu)
+{
+    pj_stun_server_info *si;
+    pj_stun_session *session;
+    pj_stun_usage *usage;
+    pj_stun_usage_cb usage_cb;
+    pj_stun_session_cb sess_cb;
+    pj_sockaddr_in local_addr;
+    pj_status_t status;
+
+    si = pj_stun_server_get_info(srv);
+
+    status = pj_sockaddr_in_init(&local_addr, ip_addr, (pj_uint16_t)port);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_bzero(&usage_cb, sizeof(usage_cb));
+    usage_cb.on_rx_data = &usage_on_rx_data;
+
+    status = pj_stun_usage_create(srv, "bind%p", &usage_cb,
+				  PJ_AF_INET, PJ_SOCK_DGRAM, 0,
+				  &local_addr, sizeof(local_addr),
+				  &usage);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_bzero(&sess_cb, sizeof(sess_cb));
+    sess_cb.on_send_msg = &sess_on_send_msg;
+    sess_cb.on_rx_request = &sess_on_rx_request;
+    status = pj_stun_session_create(si->endpt, "bind%p", &sess_cb, PJ_FALSE,
+				    &session);
+    if (status != PJ_SUCCESS) {
+	pj_stun_usage_destroy(usage);
+	return status;
+    }
+
+    pj_stun_usage_set_user_data(usage, session);
+    pj_stun_session_set_user_data(session, usage);
+
+    *p_bu = usage;
+
+    return PJ_SUCCESS;
+}
+
+
+static void usage_on_rx_data(pj_stun_usage *usage,
+			     void *pkt,
+			     pj_size_t pkt_size,
+			     const pj_sockaddr_t *src_addr,
+			     unsigned src_addr_len)
+{
+    pj_stun_session *session;
+    pj_status_t status;
+
+    session = (pj_stun_session*) pj_stun_usage_get_user_data(usage);
+
+    /* Handle packet to session */
+    status = pj_stun_session_on_rx_pkt(session, (pj_uint8_t*)pkt, pkt_size,
+				       PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
+				       NULL, src_addr, src_addr_len);
+    if (status != PJ_SUCCESS) {
+	pj_stun_perror(THIS_FILE, "Error handling incoming packet", status);
+	return;
+    }
+}
+
+
+static pj_status_t sess_on_send_msg(pj_stun_session *sess,
+				    const void *pkt,
+				    pj_size_t pkt_size,
+				    const pj_sockaddr_t *dst_addr,
+				    unsigned addr_len)
+{
+    pj_stun_usage *usage;
+
+    usage = pj_stun_session_get_user_data(sess);
+
+    return pj_stun_usage_sendto(usage, pkt, pkt_size, 0,
+				dst_addr, addr_len);
+}
+
+
+static pj_status_t sess_on_rx_request(pj_stun_session *sess,
+				      const pj_uint8_t *pkt,
+				      unsigned pkt_len,
+				      const pj_stun_msg *msg,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len)
+{
+    pj_stun_tx_data *tdata;
+    pj_status_t status;
+
+    PJ_UNUSED_ARG(pkt);
+    PJ_UNUSED_ARG(pkt_len);
+
+    /* Create response */
+    status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create MAPPED-ADDRESS attribute */
+    status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+				   	  PJ_STUN_ATTR_MAPPED_ADDR,
+					  PJ_FALSE,
+				          src_addr, src_addr_len);
+    if (status != PJ_SUCCESS) {
+	pj_stun_perror(THIS_FILE, "Error creating response", status);
+	pj_stun_msg_destroy_tdata(sess, tdata);
+	return status;
+    }
+
+    /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
+    if (msg->hdr.magic == PJ_STUN_MAGIC) {
+	status = 
+	    pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+					 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS,
+					 PJ_TRUE,
+					 src_addr, src_addr_len);
+	if (status != PJ_SUCCESS) {
+	    pj_stun_perror(THIS_FILE, "Error creating response", status);
+	    pj_stun_msg_destroy_tdata(sess, tdata);
+	    return status;
+	}
+    }
+
+    /* Send */
+    status = pj_stun_session_send_msg(sess, PJ_TRUE, 
+				      src_addr, src_addr_len, tdata);
+    return status;
+
+}
+
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c	(revision 1040)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c	(revision 1040)
@@ -0,0 +1,132 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include "server.h"
+
+struct options
+{
+    char	*realm;
+    char	*user_name;
+    char	*password;
+    char	*nonce;
+    pj_bool_t	 use_fingerprint;
+} o;
+
+static void usage(void)
+{
+    puts("Usage: pjstun_srv_test [OPTIONS]");
+    puts("");
+    puts("where OPTIONS:");
+    puts(" --realm, -r       Set realm of the credential");
+    puts(" --username, -u    Set username of the credential");
+    puts(" --password, -p    Set password of the credential");
+    puts(" --nonce, -N       Set NONCE");      
+    puts(" --fingerprint, -F Use fingerprint for outgoing requests");
+    puts(" --help, -h");
+}
+
+
+static void server_main(void)
+{
+    int quit = 0;
+
+    while (!quit) {
+	char line[10];
+
+	printf("Menu:\n"
+	       "  q     Quit\n"
+	       "Choice:");
+
+	fgets(line, sizeof(line), stdin);
+	if (line[0] == 'q')
+	    quit = 1;
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    struct pj_getopt_option long_options[] = {
+	{ "realm",	1, 0, 'r'},
+	{ "username",	1, 0, 'u'},
+	{ "password",	1, 0, 'p'},
+	{ "nonce",	1, 0, 'N'},
+	{ "fingerprint",0, 0, 'F'},
+	{ "help",	0, 0, 'h'}
+    };
+    int c, opt_id;
+    pj_caching_pool cp;
+    pj_stun_server *srv;
+    pj_stun_usage *bu;
+    pj_status_t status;
+
+    while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
+	switch (c) {
+	case 'r':
+	    o.realm = pj_optarg;
+	    break;
+	case 'u':
+	    o.user_name = pj_optarg;
+	    break;
+	case 'p':
+	    o.password = pj_optarg;
+	    break;
+	case 'N':
+	    o.nonce = pj_optarg;
+	    break;
+	case 'h':
+	    usage();
+	    return 0;
+	case 'F':
+	    o.use_fingerprint = PJ_TRUE;
+	    break;
+	default:
+	    printf("Argument \"%s\" is not valid. Use -h to see help",
+		   argv[pj_optind]);
+	    return 1;
+	}
+    }
+
+    if (pj_optind != argc) {
+	puts("Error: invalid arguments");
+	return 1;
+    }
+
+    pj_init();
+    pjlib_util_init();
+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+    status = pj_stun_server_create(&cp.factory, 1, &srv);
+    if (status != PJ_SUCCESS) {
+	pj_stun_perror(THIS_FILE, "Unable to create server", status);
+	return 1;
+    }
+
+    status = pj_stun_bind_usage_create(srv, NULL, 3478, &bu);
+    if (status != PJ_SUCCESS) {
+	pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
+	return 1;
+    }
+
+    server_main();
+
+    pj_stun_usage_destroy(bu);
+    pj_stun_server_destroy(srv);
+    pj_pool_factory_dump(&cp.factory, PJ_TRUE);
+    pj_shutdown();
+    return 0;
+}
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.c	(revision 1039)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.c	(revision 1040)
@@ -17,63 +17,22 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util.h>
-#include <pjlib.h>
 
-#include <stdio.h>
-#include <conio.h>
+#include "server.h"
 
+#define THIS_FILE	"server.c"
 
-#define THIS_FILE	"server_main.c"
-#define MAX_THREADS	8
-#define MAX_SERVICE	16
-#define MAX_PKT_LEN	512
+struct pj_stun_server
+{
+    pj_stun_server_info	si;
 
-struct service
-{
-    unsigned		 index;
-    pj_uint16_t		 port;
-    pj_bool_t		 is_stream;
-    pj_sock_t		 sock;
-    pj_ioqueue_key_t	*key;
-    pj_ioqueue_op_key_t  recv_opkey,
-			 send_opkey;
+    pj_pool_t		*pool;
 
-    pj_stun_session	*sess;
-
-    int		         src_addr_len;
-    pj_sockaddr_in	 src_addr;
-    pj_ssize_t		 rx_pkt_len;
-    pj_uint8_t		 rx_pkt[MAX_PKT_LEN];
-    pj_uint8_t		 tx_pkt[MAX_PKT_LEN];
+    pj_bool_t		 thread_quit_flag;
+    pj_thread_t	       **threads;
 };
 
-static struct stun_server
-{
-    pj_caching_pool	 cp;
-    pj_pool_t		*pool;
-    pj_stun_endpoint	*endpt;
-    pj_ioqueue_t	*ioqueue;
-    pj_timer_heap_t	*timer_heap;
-    unsigned		 service_cnt;
-    struct service	 services[MAX_SERVICE];
-
-    pj_bool_t		 thread_quit_flag;
-    unsigned		 thread_cnt;
-    pj_thread_t		*threads[16];
-
-
-} server;
-
-static struct options
-{
-    char	*realm;
-    char	*user_name;
-    char	*password;
-    char	*nonce;
-    pj_bool_t	 use_fingerprint;
-} o;
-
-static pj_status_t server_perror(const char *sender, const char *title, 
-				 pj_status_t status)
+PJ_DEF(pj_status_t) pj_stun_perror( const char *sender, 
+				    const char *title, 
+				    pj_status_t status)
 {
     char errmsg[PJ_ERR_MSG_SIZE];
@@ -81,261 +40,15 @@
 
     PJ_LOG(3,(sender, "%s: %s", title, errmsg));
-
     return status;
 }
 
-
-/* Callback to be called to send outgoing message */
-static pj_status_t on_send_msg(pj_stun_session *sess,
-			       const void *pkt,
-			       pj_size_t pkt_size,
-			       const pj_sockaddr_t *dst_addr,
-			       unsigned addr_len)
-{
-    struct service *svc;
-    pj_ssize_t length;
-    pj_status_t status;
-
-    svc = (struct service*) pj_stun_session_get_user_data(sess);
-
-    /* Send packet */
-    length = pkt_size;
-    if (svc->is_stream) {
-	status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0);
-    } else {
-#if 0
-	pj_pool_t *pool;
-	char *buf;
-	pj_stun_msg *msg;
-
-	pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL);
-	status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL);
-	buf = pj_pool_alloc(pool, 512);
-	PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL)));
-#endif
-	status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length, 
-				   0, dst_addr, addr_len);
-    }
-
-    return (status == PJ_SUCCESS || status == PJ_EPENDING) ? 
-	    PJ_SUCCESS : status;
-}
-
-
-/* Handle STUN binding request */
-static pj_status_t on_rx_binding_request(pj_stun_session *sess,
-					 const pj_uint8_t *pkt,
-					 unsigned pkt_len,
-					 const pj_stun_msg *msg,
-					 const pj_sockaddr_t *src_addr,
-					 unsigned src_addr_len)
-{
-    struct service *svc = (struct service *) pj_stun_session_get_user_data(sess);
-    pj_stun_tx_data *tdata;
-    pj_status_t status;
-
-    /* Create response */
-    status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Create MAPPED-ADDRESS attribute */
-    status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
-				   	  PJ_STUN_ATTR_MAPPED_ADDR,
-					  PJ_FALSE,
-				          src_addr, src_addr_len);
-    if (status != PJ_SUCCESS) {
-	server_perror(THIS_FILE, "Error creating response", status);
-	pj_stun_msg_destroy_tdata(sess, tdata);
-	return status;
-    }
-
-    /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
-    if (msg->hdr.magic == PJ_STUN_MAGIC) {
-	status = 
-	    pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
-					 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS,
-					 PJ_TRUE,
-					 src_addr, src_addr_len);
-	if (status != PJ_SUCCESS) {
-	    server_perror(THIS_FILE, "Error creating response", status);
-	    pj_stun_msg_destroy_tdata(sess, tdata);
-	    return status;
-	}
-    }
-
-    /* Send */
-    status = pj_stun_session_send_msg(sess, PJ_TRUE, 
-				      src_addr, src_addr_len, tdata);
-    return status;
-}
-
-
-/* Handle unknown request */
-static pj_status_t on_rx_unknown_request(pj_stun_session *sess,
-					 const pj_uint8_t *pkt,
-					 unsigned pkt_len,
-					 const pj_stun_msg *msg,
-					 const pj_sockaddr_t *src_addr,
-					 unsigned src_addr_len)
-{
-    pj_stun_tx_data *tdata;
-    pj_status_t status;
-
-    /* Create response */
-    status = pj_stun_session_create_response(sess, msg, 
-					     PJ_STUN_STATUS_BAD_REQUEST,
-					     NULL, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Send */
-    status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata);
-    return status;
-}
-
-/* Callback to be called by STUN session on incoming STUN requests */
-static pj_status_t on_rx_request(pj_stun_session *sess,
-				 const pj_uint8_t *pkt,
-				 unsigned pkt_len,
-				 const pj_stun_msg *msg,
-				 const pj_sockaddr_t *src_addr,
-				 unsigned src_addr_len)
-{
-    switch (PJ_STUN_GET_METHOD(msg->hdr.type)) {
-    case PJ_STUN_BINDING_METHOD:
-	return on_rx_binding_request(sess, pkt, pkt_len, msg, 
-				     src_addr, src_addr_len);
-    default:
-	return on_rx_unknown_request(sess, pkt, pkt_len, msg,
-				     src_addr, src_addr_len);
-    }
-}
-
-
-/* Callback on ioqueue read completion */
-static void on_read_complete(pj_ioqueue_key_t *key, 
-			     pj_ioqueue_op_key_t *op_key, 
-			     pj_ssize_t bytes_read)
-{
-    struct service *svc = (struct service *) pj_ioqueue_get_user_data(key);
-    pj_status_t status;
-
-    if (bytes_read <= 0)
-	goto next_read;
-
-    /* Handle packet to session */
-    status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read,
-				       PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
-				       NULL, &svc->src_addr, svc->src_addr_len);
-    if (status != PJ_SUCCESS) {
-	server_perror(THIS_FILE, "Error processing incoming packet", status);
-    }
-
-next_read:
-    if (bytes_read < 0) {
-	server_perror(THIS_FILE, "on_read_complete()", -bytes_read);
-    }
-
-    svc->rx_pkt_len = sizeof(svc->rx_pkt);
-    svc->src_addr_len = sizeof(svc->src_addr);
-
-    status = pj_ioqueue_recvfrom(svc->key, &svc->recv_opkey, 
-				 svc->rx_pkt, &svc->rx_pkt_len, 
-				 PJ_IOQUEUE_ALWAYS_ASYNC,
-				 &svc->src_addr, &svc->src_addr_len);
-    if (status != PJ_EPENDING)
-	server_perror(THIS_FILE, "error starting async read", status);
-}
-
-
-static pj_status_t init_service(struct service *svc)
-{
-    pj_status_t status;
-    pj_ioqueue_callback service_callback;
-    pj_stun_session_cb sess_cb;
-    pj_sockaddr_in addr;
-
-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &svc->sock);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    status = pj_sockaddr_in_init(&addr, NULL, svc->port);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-    
-    status = pj_sock_bind(svc->sock, &addr, sizeof(addr));
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    pj_bzero(&sess_cb, sizeof(sess_cb));
-    sess_cb.on_send_msg = &on_send_msg;
-    sess_cb.on_rx_request = &on_rx_request;
-    status = pj_stun_session_create(server.endpt, "session", 
-				    &sess_cb, 
-				    o.use_fingerprint!=0, 
-				    &svc->sess);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    pj_stun_session_set_user_data(svc->sess, (void*)svc);
-
-    if (o.user_name) {
-	pj_stun_auth_cred cred;
-
-	pj_bzero(&cred, sizeof(cred));
-
-	cred.type = PJ_STUN_AUTH_CRED_STATIC;
-	cred.data.static_cred.realm = pj_str(o.realm);
-	cred.data.static_cred.username = pj_str(o.user_name);
-	cred.data.static_cred.data_type = 0;
-	cred.data.static_cred.data = pj_str(o.password);
-	cred.data.static_cred.nonce = pj_str(o.nonce);
-
-	pj_stun_session_set_credential(svc->sess, &cred);
-	puts("Session credential set");
-    } else {
-	puts("Credential not set");
-    }
-
-    pj_bzero(&service_callback, sizeof(service_callback));
-    service_callback.on_read_complete = &on_read_complete;
-
-    status = pj_ioqueue_register_sock(server.pool, server.ioqueue, svc->sock,
-				      svc, &service_callback, &svc->key);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-
-    pj_ioqueue_op_key_init(&svc->recv_opkey, sizeof(svc->recv_opkey));
-    pj_ioqueue_op_key_init(&svc->send_opkey, sizeof(svc->send_opkey));
-
-    on_read_complete(svc->key, &svc->recv_opkey, 0);
-
-    PJ_LOG(4,(THIS_FILE, "Service started on port %d", svc->port));
-    return PJ_SUCCESS;
-
-on_error:
-    if (svc->key != NULL) {
-	pj_ioqueue_unregister(svc->key);
-	svc->key = NULL;
-	svc->sock = PJ_INVALID_SOCKET;
-    } else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) {
-	pj_sock_close(svc->sock);
-	svc->sock = PJ_INVALID_SOCKET;
-    }
-
-    return status;
-}
-
-
 static int worker_thread(void *p)
 {
-    PJ_UNUSED_ARG(p);
+    pj_stun_server *srv = (pj_stun_server*)p;
 
-    while (!server.thread_quit_flag) {
+    while (!srv->thread_quit_flag) {
 	pj_time_val timeout = { 0, 50 };
-	pj_timer_heap_poll(server.timer_heap, NULL);
-	pj_ioqueue_poll(server.ioqueue, &timeout);
+	pj_timer_heap_poll(srv->si.timer_heap, NULL);
+	pj_ioqueue_poll(srv->si.ioqueue, &timeout);
     }
 
@@ -344,45 +57,71 @@
 
 
-pj_status_t server_init(void)
+PJ_DEF(pj_status_t) pj_stun_server_create(pj_pool_factory *pf,
+					  unsigned thread_cnt,
+					  pj_stun_server **p_srv)
 {
+    pj_pool_t *pool;
+    pj_stun_server *srv;
+    unsigned i;
     pj_status_t status;
 
-    status = pj_init();
+    pool = pj_pool_create(pf, "server%p", 4000, 4000, NULL);
+
+    srv = PJ_POOL_ZALLOC_T(pool, pj_stun_server);
+    srv->pool = pool;
+    srv->si.pf = pf;
+
+    status = pj_ioqueue_create(srv->pool, PJ_IOQUEUE_MAX_HANDLES, 
+			       &srv->si.ioqueue);
     if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "pj_init() error", status);
+	goto on_error;
 
-    status = pjlib_util_init();
+    status = pj_timer_heap_create(srv->pool, 1024, &srv->si.timer_heap);
     if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "pjlib_util_init() error", status);
+	goto on_error;
 
-    pj_caching_pool_init(&server.cp, 
-			 &pj_pool_factory_default_policy, 0);
+    status = pj_stun_endpoint_create(srv->si.pf, 0, srv->si.ioqueue, 
+				     srv->si.timer_heap, &srv->si.endpt);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    srv->si.thread_cnt = thread_cnt;
+    srv->threads = pj_pool_calloc(pool, thread_cnt, sizeof(pj_thread_t*));
+    for (i=0; i<thread_cnt; ++i) {
+	status = pj_thread_create(pool, "worker%p", &worker_thread,
+				  srv, 0, 0, &srv->threads[i]);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    }
+
+    *p_srv = srv;
+    return PJ_SUCCESS;
+
+on_error:
+    pj_stun_server_destroy(srv);
+    return status;
+}
 
 
-    server.pool = pj_pool_create(&server.cp.factory, "server", 4000, 4000,
-				 NULL);
+PJ_DEF(pj_stun_server_info*) pj_stun_server_get_info(pj_stun_server *srv)
+{
+    return &srv->si;
+}
 
-    status = pj_ioqueue_create(server.pool, PJ_IOQUEUE_MAX_HANDLES, 
-			       &server.ioqueue);
-    if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "pj_ioqueue_create()", status);
 
-    status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap);
-    if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "Error creating timer heap", status);
+PJ_DEF(pj_status_t) pj_stun_server_destroy(pj_stun_server *srv)
+{
+    unsigned i;
 
-    status = pj_stun_endpoint_create(&server.cp.factory, 0, 
-				     server.ioqueue, server.timer_heap, 
-				     &server.endpt);
-    if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "Error creating endpoint", status);
+    srv->thread_quit_flag = PJ_TRUE;
+    for (i=0; i<srv->si.thread_cnt; ++i) {
+	pj_thread_join(srv->threads[i]);
+	srv->threads[i] = NULL;
+    }
 
-    server.service_cnt = 1;
-    server.services[0].index = 0;
-    server.services[0].port = PJ_STUN_PORT;
-
-    status = init_service(&server.services[0]);
-    if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "init_service() error", status);
+    pj_stun_endpoint_destroy(srv->si.endpt);
+    pj_timer_heap_destroy(srv->si.timer_heap);
+    pj_ioqueue_destroy(srv->si.ioqueue);
+    pj_pool_release(srv->pool);
 
     return PJ_SUCCESS;
@@ -390,148 +129,2 @@
 
 
-pj_status_t server_main(void)
-{
-#if 0
-    for (;;) {
-	pj_time_val timeout = { 0, 50 };
-	pj_timer_heap_poll(server.timer_heap, NULL);
-	pj_ioqueue_poll(server.ioqueue, &timeout);
-
-	if (kbhit() && _getch()==27)
-	    break;
-    }
-#else
-    pj_status_t status;
-
-    status = pj_thread_create(server.pool, "stun_server", &worker_thread, NULL,
-			      0, 0, &server.threads[0]);
-    if (status != PJ_SUCCESS)
-	return server_perror(THIS_FILE, "create_thread() error", status);
-
-    while (!server.thread_quit_flag) {
-	char line[10];
-
-	printf("Menu:\n"
-	       "  q     Quit\n"
-	       "Choice:");
-
-	fgets(line, sizeof(line), stdin);
-	if (line[0] == 'q')
-	    server.thread_quit_flag = 1;
-    }
-
-#endif
-
-    return PJ_SUCCESS;
-}
-
-
-pj_status_t server_destroy(void)
-{
-    unsigned i;
-
-    for (i=0; i<PJ_ARRAY_SIZE(server.services); ++i) {
-	struct service *svc = &server.services[i];
-
-	if (svc->key != NULL) {
-	    pj_ioqueue_unregister(svc->key);
-	    svc->key = NULL;
-	    svc->sock = PJ_INVALID_SOCKET;
-	} else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) {
-	    pj_sock_close(svc->sock);
-	    svc->sock = PJ_INVALID_SOCKET;
-	}
-    }
-
-    server.thread_quit_flag = PJ_TRUE;
-    for (i=0; i<PJ_ARRAY_SIZE(server.threads); ++i) {
-	if (server.threads[i]) {
-	    pj_thread_join(server.threads[i]);
-	    pj_thread_destroy(server.threads[i]);
-	    server.threads[i] = NULL;
-	}
-    }
-
-    pj_stun_session_destroy(server.services[0].sess);
-    pj_stun_endpoint_destroy(server.endpt);
-    pj_ioqueue_destroy(server.ioqueue);
-    pj_pool_release(server.pool);
-
-    pj_pool_factory_dump(&server.cp.factory, PJ_TRUE);
-    pj_caching_pool_destroy(&server.cp);
-
-    pj_shutdown();
-
-    return PJ_SUCCESS;
-}
-
-
-static void usage(void)
-{
-    puts("Usage: pjstun_srv_test [OPTIONS]");
-    puts("");
-    puts("where OPTIONS:");
-    puts(" --realm, -r       Set realm of the credential");
-    puts(" --username, -u    Set username of the credential");
-    puts(" --password, -p    Set password of the credential");
-    puts(" --nonce, -N       Set NONCE");      
-    puts(" --fingerprint, -F Use fingerprint for outgoing requests");
-    puts(" --help, -h");
-}
-
-
-int main(int argc, char *argv[])
-{
-    struct pj_getopt_option long_options[] = {
-	{ "realm",	1, 0, 'r'},
-	{ "username",	1, 0, 'u'},
-	{ "password",	1, 0, 'p'},
-	{ "nonce",	1, 0, 'N'},
-	{ "fingerprint",0, 0, 'F'},
-	{ "help",	0, 0, 'h'}
-    };
-    int c, opt_id;
-
-    while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
-	switch (c) {
-	case 'r':
-	    o.realm = pj_optarg;
-	    break;
-	case 'u':
-	    o.user_name = pj_optarg;
-	    break;
-	case 'p':
-	    o.password = pj_optarg;
-	    break;
-	case 'N':
-	    o.nonce = pj_optarg;
-	    break;
-	case 'h':
-	    usage();
-	    return 0;
-	case 'F':
-	    o.use_fingerprint = PJ_TRUE;
-	    break;
-	default:
-	    printf("Argument \"%s\" is not valid. Use -h to see help",
-		   argv[pj_optind]);
-	    return 1;
-	}
-    }
-
-    if (pj_optind != argc) {
-	puts("Error: invalid arguments");
-	return 1;
-    }
-
-
-    if (server_init()) {
-	server_destroy();
-	return 1;
-    }
-
-    server_main();
-    server_destroy();
-
-    return 0;
-}
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h	(revision 1040)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h	(revision 1040)
@@ -0,0 +1,122 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __STUN_SERVER_H__
+#define __STUN_SERVER_H__
+
+#include <pjlib-util.h>
+#include <pjlib.h>
+
+
+/** Opaque declaration for STUN server instance */
+typedef struct pj_stun_server pj_stun_server;
+
+/** STUN server info */
+typedef struct pj_stun_server_info
+{
+    pj_pool_factory	*pf;
+    pj_stun_endpoint	*endpt;
+    pj_ioqueue_t	*ioqueue;
+    pj_timer_heap_t	*timer_heap;
+    unsigned		 thread_cnt;
+} pj_stun_server_info;
+
+/** STUN usage */
+typedef struct pj_stun_usage pj_stun_usage;
+
+/** STUN usage callback */
+typedef struct pj_stun_usage_cb
+{
+    void (*on_rx_data)(pj_stun_usage *usage,
+		       void *pkt,
+		       pj_size_t pkt_size,
+		       const pj_sockaddr_t *src_addr,
+		       unsigned src_addr_len);
+} pj_stun_usage_cb;
+
+
+PJ_DECL(pj_status_t) pj_stun_perror(const char *sender, 
+				    const char *title, 
+				    pj_status_t status);
+
+/**
+ * Create instance of STUN server.
+ */
+PJ_DECL(pj_status_t) pj_stun_server_create(pj_pool_factory *pf,
+					   unsigned thread_cnt,
+					   pj_stun_server **p_srv);
+
+/**
+ * Get STUN server info.
+ */
+PJ_DECL(pj_stun_server_info*) pj_stun_server_get_info(pj_stun_server *srv);
+
+
+/**
+ * Destroy STUN server.
+ */
+PJ_DECL(pj_status_t) pj_stun_server_destroy(pj_stun_server *srv);
+
+
+/**
+ * Create STUN usage.
+ */
+PJ_DECL(pj_status_t) pj_stun_usage_create(pj_stun_server *srv,
+					  const char *name,
+					  const pj_stun_usage_cb *cb,
+					  int family,
+					  int type,
+					  int protocol,
+					  const pj_sockaddr_t *local_addr,
+					  int addr_len,
+					  pj_stun_usage **p_usage);
+
+/**
+ * Destroy usage.
+ */
+PJ_DECL(pj_status_t) pj_stun_usage_destroy(pj_stun_usage *usage);
+
+/**
+ * Set user data.
+ */
+PJ_DECL(pj_status_t) pj_stun_usage_set_user_data(pj_stun_usage *usage,
+						 void *user_data);
+/**
+ * Get user data.
+ */
+PJ_DECL(void*) pj_stun_usage_get_user_data(pj_stun_usage *usage);
+
+/**
+ * Send with the usage.
+ */
+PJ_DECL(pj_status_t) pj_stun_usage_sendto(pj_stun_usage *usage,
+					  const void *pkt,
+					  pj_size_t pkt_size,
+					  unsigned flags,
+					  const pj_sockaddr_t *dst_addr,
+					  unsigned addr_len);
+
+PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
+					      const pj_str_t *ip_addr,
+					      unsigned port,
+					      pj_stun_usage **p_bu);
+
+
+#endif	/* __STUN_SERVER_H__ */
+
+
Index: pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c	(revision 1040)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c	(revision 1040)
@@ -0,0 +1,259 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include "server.h"
+
+struct worker
+{
+    pj_ioqueue_op_key_t	read_key;
+    unsigned		index;
+    pj_uint8_t		readbuf[4000];
+    pj_sockaddr		src_addr;
+    int			src_addr_len;
+};
+
+struct pj_stun_usage
+{
+    pj_pool_t		*pool;
+    pj_mutex_t		*mutex;
+    pj_stun_usage_cb	 cb;
+    int			 type;
+    pj_sock_t		 sock;
+    pj_ioqueue_key_t	*key;
+    unsigned		 worker_cnt;
+    struct worker	*worker;
+
+    pj_ioqueue_op_key_t	*send_key;
+    unsigned		 send_count, send_index;
+
+    pj_bool_t		 quitting;
+    void		*user_data;
+};
+
+
+static void on_read_complete(pj_ioqueue_key_t *key, 
+                             pj_ioqueue_op_key_t *op_key, 
+                             pj_ssize_t bytes_read);
+
+/*
+ * Create STUN usage.
+ */
+PJ_DEF(pj_status_t) pj_stun_usage_create( pj_stun_server *srv,
+					  const char *name,
+					  const pj_stun_usage_cb *cb,
+					  int family,
+					  int type,
+					  int protocol,
+					  const pj_sockaddr_t *local_addr,
+					  int addr_len,
+					  pj_stun_usage **p_usage)
+{
+    pj_stun_server_info *si;
+    pj_pool_t *pool;
+    pj_stun_usage *usage;
+    pj_ioqueue_callback ioqueue_cb;
+    unsigned i;
+    pj_status_t status;
+
+    si = pj_stun_server_get_info(srv);
+
+    pool = pj_pool_create(si->pf, name, 4000, 4000, NULL);
+    usage = PJ_POOL_ZALLOC_T(pool, pj_stun_usage);
+    usage->pool = pool;
+
+    status = pj_mutex_create_simple(pool, name, &usage->mutex);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    pj_memcpy(&usage->cb, cb, sizeof(*cb));
+
+    usage->type = type;
+    status = pj_sock_socket(family, type, protocol, &usage->sock);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    status = pj_sock_bind(usage->sock, local_addr, addr_len);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
+    ioqueue_cb.on_read_complete = &on_read_complete;
+    status = pj_ioqueue_register_sock(usage->pool, si->ioqueue, usage->sock,
+				      usage, &ioqueue_cb, &usage->key);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    usage->worker_cnt = si->thread_cnt;
+    usage->worker = pj_pool_calloc(pool, si->thread_cnt, 
+				   sizeof(struct worker));
+    for (i=0; i<si->thread_cnt; ++i) {
+	pj_ioqueue_op_key_init(&usage->worker[i].read_key, 
+			       sizeof(usage->worker[i].read_key));
+	usage->worker[i].index = i;
+    }
+
+    usage->send_count = usage->worker_cnt * 2;
+    usage->send_key = pj_pool_calloc(pool, usage->send_count, 
+				     sizeof(pj_ioqueue_op_key_t));
+    for (i=0; i<usage->send_count; ++i) {
+	pj_ioqueue_op_key_init(&usage->send_key[i], 
+			       sizeof(usage->send_key[i]));
+    }
+
+    for (i=0; i<si->thread_cnt; ++i) {
+	pj_ssize_t size;
+
+	size = sizeof(usage->worker[i].readbuf);
+	usage->worker[i].src_addr_len = sizeof(usage->worker[i].src_addr);
+	status = pj_ioqueue_recvfrom(usage->key, &usage->worker[i].read_key,
+				     usage->worker[i].readbuf, &size, 
+				     PJ_IOQUEUE_ALWAYS_ASYNC,
+				     &usage->worker[i].src_addr,
+				     &usage->worker[i].src_addr_len);
+	if (status != PJ_EPENDING)
+	    goto on_error;
+    }
+
+    *p_usage = usage;
+    return PJ_SUCCESS;
+
+on_error:
+    pj_stun_usage_destroy(usage);
+    return status;
+}
+
+
+/**
+ * Destroy usage.
+ */
+PJ_DEF(pj_status_t) pj_stun_usage_destroy(pj_stun_usage *usage)
+{
+    if (usage->key) {
+	pj_ioqueue_unregister(usage->key);
+	usage->key = NULL;
+	usage->sock = PJ_INVALID_SOCKET;
+    } else if (usage->sock != 0 && usage->sock != PJ_INVALID_SOCKET) {
+	pj_sock_close(usage->sock);
+	usage->sock = PJ_INVALID_SOCKET;
+    }
+
+    if (usage->mutex) {
+	pj_mutex_destroy(usage->mutex);
+	usage->mutex = NULL;
+    }
+
+    if (usage->pool) {
+	pj_pool_t *pool = usage->pool;
+	usage->pool = NULL;
+	pj_pool_release(pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/**
+ * Set user data.
+ */
+PJ_DEF(pj_status_t) pj_stun_usage_set_user_data( pj_stun_usage *usage,
+						 void *user_data)
+{
+    usage->user_data = user_data;
+    return PJ_SUCCESS;
+}
+
+/**
+ * Get user data.
+ */
+PJ_DEF(void*) pj_stun_usage_get_user_data(pj_stun_usage *usage)
+{
+    return usage->user_data;
+}
+
+
+/**
+ * Send with the usage.
+ */
+PJ_DEF(pj_status_t) pj_stun_usage_sendto( pj_stun_usage *usage,
+					  const void *pkt,
+					  pj_size_t pkt_size,
+					  unsigned flags,
+					  const pj_sockaddr_t *dst_addr,
+					  unsigned addr_len)
+{
+    pj_ssize_t size = pkt_size;
+    unsigned i, count = usage->send_count, index;
+
+    pj_mutex_lock(usage->mutex);
+    for (i=0, ++usage->send_index; i<count; ++i, ++usage->send_index) {
+	if (usage->send_index >= usage->send_count)
+	    usage->send_index = 0;
+
+	if (pj_ioqueue_is_pending(usage->key, &usage->send_key[usage->send_index])==0) {
+	    break;
+	}
+    }
+
+    if (i==count) {
+	pj_mutex_unlock(usage->mutex);
+	return PJ_EBUSY;
+    }
+
+    index = usage->send_index;
+    pj_mutex_unlock(usage->mutex);
+
+    return pj_ioqueue_sendto(usage->key, &usage->send_key[index], 
+			     pkt, &size, flags,
+			     dst_addr, addr_len);
+}
+
+
+static void on_read_complete(pj_ioqueue_key_t *key, 
+                             pj_ioqueue_op_key_t *op_key, 
+                             pj_ssize_t bytes_read)
+{
+    enum { MAX_LOOP = 10 };
+    pj_stun_usage *usage = pj_ioqueue_get_user_data(key);
+    struct worker *worker = (struct worker*) op_key;
+    unsigned count;
+    pj_status_t status;
+    
+    for (count=0; !usage->quitting; ++count) {
+	unsigned flags;
+
+	if (bytes_read > 0) {
+	    (*usage->cb.on_rx_data)(usage, worker->readbuf, bytes_read,
+				    &worker->src_addr, worker->src_addr_len);
+	} else if (bytes_read < 0) {
+	    pj_stun_perror(usage->pool->obj_name, "recv() error", -bytes_read);
+	}
+
+	if (usage->quitting)
+	    break;
+
+	bytes_read = sizeof(worker->readbuf);
+	flags = (count >= MAX_LOOP) ? PJ_IOQUEUE_ALWAYS_ASYNC : 0;
+	worker->src_addr_len = sizeof(worker->src_addr);
+	status = pj_ioqueue_recvfrom(usage->key, &worker->read_key,
+				     worker->readbuf, &bytes_read, flags,
+				     &worker->src_addr, &worker->src_addr_len);
+	if (status == PJ_EPENDING)
+	    break;
+    }
+}
+
Index: pjproject/trunk/pjlib/include/pj/pool.h
===================================================================
--- pjproject/trunk/pjlib/include/pj/pool.h	(revision 1039)
+++ pjproject/trunk/pjlib/include/pj/pool.h	(revision 1040)
@@ -443,5 +443,5 @@
  * @return pointer to the allocated memory.
  *
- * @see PJ_POOL_ALLOC_TYPE
+ * @see PJ_POOL_ALLOC_T
  */
 PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);
@@ -470,5 +470,5 @@
  * @return	    Pointer to the allocated memory.
  *
- * @see PJ_POOL_ZALLOC_TYPE
+ * @see PJ_POOL_ZALLOC_T
  */
 PJ_INLINE(void*) pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
@@ -489,5 +489,5 @@
  * @return	    Memory buffer of the specified type.
  */
-#define PJ_POOL_ALLOC_TYPE(pool,type) \
+#define PJ_POOL_ALLOC_T(pool,type) \
 	    ((type*)pj_pool_alloc(pool, sizeof(type)))
 
@@ -503,5 +503,5 @@
  * @return	    Memory buffer of the specified type.
  */
-#define PJ_POOL_ZALLOC_TYPE(pool,type) \
+#define PJ_POOL_ZALLOC_T(pool,type) \
 	    ((type*)pj_pool_zalloc(pool, sizeof(type)))
 
