summaryrefslogtreecommitdiff
path: root/pjlib-util/src/pjstun-client
diff options
context:
space:
mode:
Diffstat (limited to 'pjlib-util/src/pjstun-client')
-rw-r--r--pjlib-util/src/pjstun-client/client_main.c136
-rw-r--r--pjlib-util/src/pjstun-client/stun_session.c226
-rw-r--r--pjlib-util/src/pjstun-client/stun_session.h341
3 files changed, 633 insertions, 70 deletions
diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c
index 7dc0540d..5f9d7d4c 100644
--- a/pjlib-util/src/pjstun-client/client_main.c
+++ b/pjlib-util/src/pjstun-client/client_main.c
@@ -18,8 +18,142 @@
*/
#include <pjlib-util.h>
#include <pjlib.h>
+#include "stun_session.h"
+
+#include <conio.h>
#define THIS_FILE "client_main.c"
-#define MAX_THREADS 8
+
+
+static my_perror(const char *title, pj_status_t status)
+{
+ char errmsg[PJ_ERR_MSG_SIZE];
+ pj_strerror(status, errmsg, sizeof(errmsg));
+
+ PJ_LOG(3,(THIS_FILE, "%s: %s", title, errmsg));
+}
+
+static pj_status_t on_send_msg(pj_stun_tx_data *tdata,
+ const void *pkt,
+ pj_size_t pkt_size,
+ unsigned addr_len,
+ const pj_sockaddr_t *dst_addr)
+{
+ pj_sock_t sock;
+ pj_ssize_t len;
+ pj_status_t status;
+
+ sock = (pj_sock_t) pj_stun_session_get_user_data(tdata->sess);
+
+ len = pkt_size;
+ status = pj_sock_sendto(sock, pkt, &len, 0, dst_addr, addr_len);
+
+ if (status != PJ_SUCCESS)
+ my_perror("Error sending packet", status);
+
+ return status;
+}
+
+static void on_bind_response(pj_stun_session *sess,
+ pj_status_t status,
+ pj_stun_tx_data *request,
+ const pj_stun_msg *response)
+{
+ my_perror("on_bind_response()", status);
+}
+
+int main()
+{
+ pj_stun_endpoint *endpt = NULL;
+ pj_pool_t *pool = NULL;
+ pj_caching_pool cp;
+ pj_timer_heap_t *th = NULL;
+ pj_stun_session *sess;
+ pj_sock_t sock = PJ_INVALID_SOCKET;
+ pj_sockaddr_in addr;
+ pj_stun_session_cb stun_cb;
+ pj_stun_tx_data *tdata;
+ pj_str_t s;
+ pj_status_t status;
+
+ status = pj_init();
+ status = pjlib_util_init();
+
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+ pool = pj_pool_create(&cp.factory, NULL, 1000, 1000, NULL);
+
+ status = pj_timer_heap_create(pool, 1000, &th);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_stun_endpoint_create(&cp.factory, 0, NULL, th, &endpt);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), PJ_STUN_PORT);
+ pj_assert(status == PJ_SUCCESS);
+
+ pj_memset(&stun_cb, 0, sizeof(stun_cb));
+ stun_cb.on_send_msg = &on_send_msg;
+ stun_cb.on_bind_response = &on_bind_response;
+
+ status = pj_stun_session_create(endpt, NULL, &stun_cb, &sess);
+ pj_assert(status == PJ_SUCCESS);
+
+ pj_stun_session_set_user_data(sess, (void*)sock);
+
+ status = pj_stun_session_create_bind_req(sess, &tdata);
+ pj_assert(status == PJ_SUCCESS);
+
+ status = pj_stun_session_send_msg(sess, 0, sizeof(addr), &addr, tdata);
+ pj_assert(status == PJ_SUCCESS);
+
+ while (1) {
+ pj_fd_set_t rset;
+ int n;
+ pj_time_val timeout;
+
+ if (kbhit()) {
+ if (_getch()==27)
+ break;
+ }
+
+ PJ_FD_ZERO(&rset);
+ PJ_FD_SET(sock, &rset);
+
+ timeout.sec = 0; timeout.msec = 100;
+
+ n = pj_sock_select(FD_SETSIZE, &rset, NULL, NULL, &timeout);
+
+ if (PJ_FD_ISSET(sock, &rset)) {
+ char pkt[512];
+ pj_ssize_t len;
+
+ len = sizeof(pkt);
+ status = pj_sock_recv(sock, pkt, &len, 0);
+ if (status == PJ_SUCCESS) {
+ pj_stun_session_on_rx_pkt(sess, pkt, len, NULL);
+ }
+ }
+
+ pj_timer_heap_poll(th, NULL);
+ }
+
+on_return:
+ if (sock != PJ_INVALID_SOCKET)
+ pj_sock_close(sock);
+ if (endpt)
+ pj_stun_endpoint_destroy(endpt);
+ if (th)
+ pj_timer_heap_destroy(th);
+ if (pool)
+ pj_pool_release(pool);
+ pj_caching_pool_destroy(&cp);
+
+ return 0;
+}
+
diff --git a/pjlib-util/src/pjstun-client/stun_session.c b/pjlib-util/src/pjstun-client/stun_session.c
index 571b723d..101bb0b4 100644
--- a/pjlib-util/src/pjstun-client/stun_session.c
+++ b/pjlib-util/src/pjstun-client/stun_session.c
@@ -26,11 +26,14 @@ struct pj_stun_session
pj_stun_session_cb cb;
void *user_data;
- pj_str_t realm;
- pj_str_t username;
- pj_str_t password;
+ /* Long term credential */
+ pj_str_t l_realm;
+ pj_str_t l_username;
+ pj_str_t l_password;
- pj_bool_t fingerprint_enabled;
+ /* Short term credential */
+ pj_str_t s_username;
+ pj_str_t s_password;
pj_stun_tx_data pending_request_list;
};
@@ -64,8 +67,8 @@ static void stun_perror(pj_stun_session *sess, const char *title,
static void tsx_on_complete(pj_stun_client_tsx *tsx,
- pj_status_t status,
- const pj_stun_msg *response);
+ pj_status_t status,
+ const pj_stun_msg *response);
static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
const void *stun_pkt,
pj_size_t pkt_size);
@@ -164,6 +167,7 @@ static void destroy_tdata(pj_stun_tx_data *tdata)
static pj_status_t session_apply_req(pj_stun_session *sess,
pj_pool_t *pool,
+ unsigned options,
pj_stun_msg *msg)
{
pj_status_t status;
@@ -171,32 +175,30 @@ static pj_status_t session_apply_req(pj_stun_session *sess,
/* From draft-ietf-behave-rfc3489bis-05.txt
* Section 8.3.1. Formulating the Request Message
*/
- if (sess->realm.slen || sess->username.slen) {
+ if (options & PJ_STUN_USE_LONG_TERM_CRED) {
pj_stun_generic_string_attr *auname;
pj_stun_msg_integrity_attr *amsgi;
+ pj_stun_generic_string_attr *arealm;
/* Create and add USERNAME attribute */
status = pj_stun_generic_string_attr_create(sess->pool,
PJ_STUN_ATTR_USERNAME,
- &sess->username,
+ &sess->l_username,
&auname);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
status = pj_stun_msg_add_attr(msg, &auname->hdr);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
- if (sess->realm.slen) {
- /* Add REALM only when long term credential is used */
- pj_stun_generic_string_attr *arealm;
- status = pj_stun_generic_string_attr_create(sess->pool,
- PJ_STUN_ATTR_REALM,
- &sess->realm,
- &arealm);
- PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-
- status = pj_stun_msg_add_attr(msg, &arealm->hdr);
- PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
- }
+ /* Add REALM only when long term credential is used */
+ status = pj_stun_generic_string_attr_create(sess->pool,
+ PJ_STUN_ATTR_REALM,
+ &sess->l_realm,
+ &arealm);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &arealm->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
/* Add MESSAGE-INTEGRITY attribute */
status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi);
@@ -205,12 +207,34 @@ static pj_status_t session_apply_req(pj_stun_session *sess,
status = pj_stun_msg_add_attr(msg, &amsgi->hdr);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
- PJ_TODO(COMPUTE_MESSAGE_INTEGRITY);
+ PJ_TODO(COMPUTE_MESSAGE_INTEGRITY1);
+
+ } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) {
+ pj_stun_generic_string_attr *auname;
+ pj_stun_msg_integrity_attr *amsgi;
+
+ /* Create and add USERNAME attribute */
+ status = pj_stun_generic_string_attr_create(sess->pool,
+ PJ_STUN_ATTR_USERNAME,
+ &sess->s_username,
+ &auname);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ status = pj_stun_msg_add_attr(msg, &auname->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ /* Add MESSAGE-INTEGRITY attribute */
+ status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ status = pj_stun_msg_add_attr(msg, &amsgi->hdr);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ PJ_TODO(COMPUTE_MESSAGE_INTEGRITY2);
}
/* Add FINGERPRINT attribute if necessary */
- if (sess->fingerprint_enabled) {
+ if (options & PJ_STUN_USE_FINGERPRINT) {
pj_stun_fingerprint_attr *af;
status = pj_stun_generic_uint_attr_create(sess->pool,
@@ -226,9 +250,49 @@ static pj_status_t session_apply_req(pj_stun_session *sess,
}
+static void tsx_on_complete(pj_stun_client_tsx *tsx,
+ pj_status_t status,
+ const pj_stun_msg *response)
+{
+ pj_stun_tx_data *tdata;
+
+ tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
+
+ switch (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)) {
+ case PJ_STUN_BINDING_METHOD:
+ tdata->sess->cb.on_bind_response(tdata->sess, status, tdata, response);
+ break;
+ case PJ_STUN_ALLOCATE_METHOD:
+ tdata->sess->cb.on_allocate_response(tdata->sess, status,
+ tdata, response);
+ break;
+ case PJ_STUN_SET_ACTIVE_DESTINATION_METHOD:
+ tdata->sess->cb.on_set_active_destination_response(tdata->sess, status,
+ tdata, response);
+ break;
+ case PJ_STUN_CONNECT_METHOD:
+ tdata->sess->cb.on_connect_response(tdata->sess, status, tdata,
+ response);
+ break;
+ default:
+ pj_assert(!"Unknown method");
+ break;
+ }
+}
+
+static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
+ const void *stun_pkt,
+ pj_size_t pkt_size)
+{
+ pj_stun_tx_data *tdata;
+ tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
+ return tdata->sess->cb.on_send_msg(tdata, stun_pkt, pkt_size,
+ tdata->addr_len, tdata->dst_addr);
+}
+/* **************************************************************************/
PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
const char *name,
@@ -260,6 +324,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess)
{
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+
pj_pool_release(sess->pool);
return PJ_SUCCESS;
@@ -280,26 +345,34 @@ PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess)
return sess->user_data;
}
-PJ_DEF(pj_status_t) pj_stun_session_set_credential( pj_stun_session *sess,
- const pj_str_t *realm,
- const pj_str_t *user,
- const pj_str_t *passwd)
+PJ_DEF(pj_status_t)
+pj_stun_session_set_long_term_credential(pj_stun_session *sess,
+ const pj_str_t *realm,
+ const pj_str_t *user,
+ const pj_str_t *passwd)
{
- pj_str_t empty = { NULL, 0 };
+ pj_str_t nil = { NULL, 0 };
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
- pj_strdup_with_null(sess->pool, &sess->realm, realm ? realm : &empty);
- pj_strdup_with_null(sess->pool, &sess->username, user ? user : &empty);
- pj_strdup_with_null(sess->pool, &sess->password, passwd ? passwd : &empty);
+ pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil);
+ pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil);
+ pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil);
return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
- pj_bool_t enabled)
+
+PJ_DEF(pj_status_t)
+pj_stun_session_set_short_term_credential(pj_stun_session *sess,
+ const pj_str_t *user,
+ const pj_str_t *passwd)
{
+ pj_str_t nil = { NULL, 0 };
+
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
- sess->fingerprint_enabled = enabled;
+ pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil);
+ pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil);
+
return PJ_SUCCESS;
}
@@ -307,7 +380,6 @@ PJ_DEF(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
pj_stun_tx_data **p_tdata)
{
- pj_pool_t *pool;
pj_stun_tx_data *tdata;
pj_status_t status;
@@ -317,12 +389,6 @@ PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
if (status != PJ_SUCCESS)
return status;
- status = session_apply_req(sess, pool, tdata->msg);
- if (status != PJ_SUCCESS) {
- destroy_tdata(tdata);
- return status;
- }
-
*p_tdata = tdata;
return PJ_SUCCESS;
}
@@ -367,6 +433,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create_data_ind( pj_stun_session *sess,
}
PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
+ unsigned options,
unsigned addr_len,
const pj_sockaddr_t *server,
pj_stun_tx_data *tdata)
@@ -375,9 +442,12 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL);
+ /* Allocate packet */
+ tdata->max_len = PJ_STUN_MAX_PKT_LEN;
+ tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len);
+
if (PJ_LOG_MAX_LEVEL >= 5) {
- char buf[512];
- unsigned buflen = sizeof(buf);
+ char *buf = (char*) tdata->pkt;
const char *dst_name;
int dst_port;
const pj_sockaddr *dst = (const pj_sockaddr*)server;
@@ -397,11 +467,29 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
PJ_LOG(5,(SNAME(sess),
"Sending STUN message to %s:%d:\n"
- "%s\n",
+ "--- begin STUN message ---\n"
+ "%s"
+ "--- end of STUN message ---\n",
dst_name, dst_port,
- pj_stun_msg_dump(tdata->msg, buf, &buflen)));
+ pj_stun_msg_dump(tdata->msg, buf, tdata->max_len, NULL)));
}
+ /* Apply options */
+ status = session_apply_req(sess, tdata->pool, options, tdata->msg);
+ if (status != PJ_SUCCESS) {
+ LOG_ERR_(sess, "Error applying options", status);
+ destroy_tdata(tdata);
+ return status;
+ }
+
+ /* Encode message */
+ status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len,
+ 0, &tdata->pkt_size);
+ if (status != PJ_SUCCESS) {
+ LOG_ERR_(sess, "STUN encode() error", status);
+ destroy_tdata(tdata);
+ return status;
+ }
/* If this is a STUN request message, then send the request with
* a new STUN client transaction.
@@ -409,16 +497,21 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) {
/* Create STUN client transaction */
- status = pj_stun_client_tsx_create(sess->endpt, &tsx_cb,
- &tdata->client_tsx);
+ status = pj_stun_client_tsx_create(sess->endpt, tdata->pool,
+ &tsx_cb, &tdata->client_tsx);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata);
+ /* Save the remote address */
+ tdata->addr_len = addr_len;
+ tdata->dst_addr = server;
+
/* Send the request! */
status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE,
- tdata->msg);
+ tdata->pkt, tdata->pkt_size);
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
LOG_ERR_(sess, "Error sending STUN request", status);
+ destroy_tdata(tdata);
return status;
}
@@ -427,7 +520,14 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
} else {
/* Otherwise for non-request message, send directly to transport. */
- status = sess->cb.on_send_msg(tdata, addr_len, server);
+ status = sess->cb.on_send_msg(tdata, tdata->pkt, tdata->pkt_size,
+ addr_len, server);
+
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ LOG_ERR_(sess, "Error sending STUN request", status);
+ destroy_tdata(tdata);
+ return status;
+ }
}
@@ -441,19 +541,36 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
unsigned *parsed_len)
{
pj_stun_msg *msg;
+ pj_pool_t *tmp_pool;
+ char *dump;
pj_status_t status;
PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL);
+ tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL);
+ if (!tmp_pool)
+ return PJ_ENOMEM;
+
/* Try to parse the message */
- status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
+ status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet,
pkt_size, 0, &msg, parsed_len,
NULL, NULL, NULL);
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "STUN msg_decode() error", status);
+ pj_pool_release(tmp_pool);
return status;
}
+ dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN);
+
+ PJ_LOG(4,(SNAME(sess),
+ "RX STUN message:\n"
+ "--- begin STUN message ---"
+ "%s"
+ "--- end of STUN message ---\n",
+ pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL)));
+
+
if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))
{
@@ -463,6 +580,7 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
tdata = tsx_lookup(sess, msg);
if (tdata == NULL) {
LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND);
+ pj_pool_release(tmp_pool);
return PJ_ENOTFOUND;
}
@@ -471,8 +589,10 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
* and this will call the session callback too.
*/
status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_pool_release(tmp_pool);
return status;
+ }
/* If transaction has completed, destroy the transmit data.
* This will remove the transaction from the pending list too.
@@ -482,18 +602,22 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
tdata = NULL;
}
+ pj_pool_release(tmp_pool);
return PJ_SUCCESS;
} else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
+ PJ_TODO(HANDLE_INCOMING_STUN_REQUEST);
} else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) {
+ PJ_TODO(HANDLE_INCOMING_STUN_INDICATION);
} else {
pj_assert(!"Unexpected!");
- return PJ_EBUG;
}
+ pj_pool_release(tmp_pool);
+ return PJ_ENOTSUP;
}
diff --git a/pjlib-util/src/pjstun-client/stun_session.h b/pjlib-util/src/pjstun-client/stun_session.h
index f9759cb9..057b35aa 100644
--- a/pjlib-util/src/pjstun-client/stun_session.h
+++ b/pjlib-util/src/pjstun-client/stun_session.h
@@ -25,84 +25,389 @@
#include <pj/list.h>
+/** Forward declaration for pj_stun_tx_data */
typedef struct pj_stun_tx_data pj_stun_tx_data;
+
+/** Forward declaration for pj_stun_session */
typedef struct pj_stun_session pj_stun_session;
+/**
+ * This is the callback to be registered to pj_stun_session, to send
+ * outgoing message and to receive various notifications from the STUN
+ * session.
+ */
typedef struct pj_stun_session_cb
{
+ /**
+ * Callback to be called by the STUN session to send outgoing message.
+ *
+ * @param tdata The STUN transmit data containing the original
+ * STUN message
+ * @param pkt Packet to be sent.
+ * @param pkt_size Size of the packet to be sent.
+ * @param addr_len Length of destination address.
+ * @param dst_addr The destination address.
+ *
+ * @return The callback should return the status of the
+ * packet sending.
+ */
pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata,
+ const void *pkt,
+ pj_size_t pkt_size,
unsigned addr_len,
const pj_sockaddr_t *dst_addr);
- void (*on_bind_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
- void (*on_allocate_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
- void (*on_set_active_destination_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
- void (*on_connect_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+ /**
+ * Callback to be called when Binding response is received or the
+ * transaction has timed out.
+ *
+ * @param sess The STUN session.
+ * @param status Status of the request. If the value if not
+ * PJ_SUCCESS, the transaction has timed-out
+ * or other error has occurred, and the response
+ * argument may be NULL.
+ * @param request The original STUN request.
+ * @param response The response message, on successful transaction.
+ */
+ void (*on_bind_response)(pj_stun_session *sess,
+ pj_status_t status,
+ pj_stun_tx_data *request,
+ const pj_stun_msg *response);
+
+ /**
+ * Callback to be called when Allocate response is received or the
+ * transaction has timed out.
+ *
+ * @param sess The STUN session.
+ * @param status Status of the request. If the value if not
+ * PJ_SUCCESS, the transaction has timed-out
+ * or other error has occurred, and the response
+ * argument may be NULL.
+ * @param request The original STUN request.
+ * @param response The response message, on successful transaction.
+ */
+ void (*on_allocate_response)(pj_stun_session *sess,
+ pj_status_t status,
+ pj_stun_tx_data *request,
+ const pj_stun_msg *response);
+
+ /**
+ * Callback to be called when Set Active Destination response is received
+ * or the transaction has timed out.
+ *
+ * @param sess The STUN session.
+ * @param status Status of the request. If the value if not
+ * PJ_SUCCESS, the transaction has timed-out
+ * or other error has occurred, and the response
+ * argument may be NULL.
+ * @param request The original STUN request.
+ * @param response The response message, on successful transaction.
+ */
+ void (*on_set_active_destination_response)(pj_stun_session *sess,
+ pj_status_t status,
+ pj_stun_tx_data *request,
+ const pj_stun_msg *response);
+
+ /**
+ * Callback to be called when Connect response is received or the
+ * transaction has timed out.
+ *
+ * @param sess The STUN session.
+ * @param status Status of the request. If the value if not
+ * PJ_SUCCESS, the transaction has timed-out
+ * or other error has occurred, and the response
+ * argument may be NULL.
+ * @param request The original STUN request.
+ * @param response The response message, on successful transaction.
+ */
+ void (*on_connect_response)( pj_stun_session *sess,
+ pj_status_t status,
+ pj_stun_tx_data *request,
+ const pj_stun_msg *response);
} pj_stun_session_cb;
+/**
+ * This structure describe the outgoing STUN transmit data to carry the
+ * message to be sent.
+ */
struct pj_stun_tx_data
{
PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data);
- pj_pool_t *pool;
- pj_stun_session *sess;
- pj_stun_msg *msg;
- void *user_data;
+ pj_pool_t *pool; /**< Pool. */
+ pj_stun_session *sess; /**< The STUN session. */
+ pj_stun_msg *msg; /**< The STUN message. */
+ void *user_data; /**< Arbitrary user data. */
+
+ pj_stun_client_tsx *client_tsx; /**< Client STUN transaction. */
+ pj_uint8_t client_key[12];/**< Client transaction key. */
- pj_stun_client_tsx *client_tsx;
- pj_uint8_t client_key[12];
+ void *pkt; /**< The STUN packet. */
+ unsigned max_len; /**< Length of packet buffer. */
+ unsigned pkt_size; /**< The actual length of STUN pkt. */
+
+ unsigned addr_len; /**< Length of destination address. */
+ const pj_sockaddr_t *dst_addr; /**< Destination address. */
};
+/**
+ * Options that can be specified when creating or sending outgoing STUN
+ * messages. These options may be specified as bitmask.
+ */
+enum pj_stun_session_option
+{
+ /**
+ * Add short term credential to the message. This option may not be used
+ * together with PJ_STUN_USE_LONG_TERM_CRED option.
+ */
+ PJ_STUN_USE_SHORT_TERM_CRED = 1,
+
+ /**
+ * Add long term credential to the message. This option may not be used
+ * together with PJ_STUN_USE_SHORT_TERM_CRED option.
+ */
+ PJ_STUN_USE_LONG_TERM_CRED = 2,
+
+ /**
+ * Add STUN fingerprint to the message.
+ */
+ PJ_STUN_USE_FINGERPRINT = 4
+};
+
+
+/**
+ * Create a STUN session.
+ *
+ * @param endpt The STUN endpoint, to be used to register timers etc.
+ * @param name Optional name to be associated with this instance. The
+ * name will be used for example for logging purpose.
+ * @param cb Session callback.
+ * @param p_sess Pointer to receive STUN session instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt,
const char *name,
const pj_stun_session_cb *cb,
pj_stun_session **p_sess);
+/**
+ * Destroy the STUN session.
+ *
+ * @param sess The STUN session instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess);
+/**
+ * Associated an arbitrary data with this STUN session. The user data may
+ * be retrieved later with pj_stun_session_get_user_data() function.
+ *
+ * @param sess The STUN session instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess,
void *user_data);
+/**
+ * Retrieve the user data previously associated to this STUN session with
+ * pj_stun_session_set_user_data().
+ *
+ * @param sess The STUN session instance.
+ *
+ * @return The user data associated with this STUN session.
+ */
PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess);
-PJ_DECL(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess,
- const pj_str_t *realm,
- const pj_str_t *user,
- const pj_str_t *passwd);
+/**
+ * Save a long term credential to be used by this STUN session when sending
+ * outgoing messages. After long term credential is configured, application
+ * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN
+ * message to send the long term credential in the message.
+ *
+ * @param sess The STUN session instance.
+ * @param realm Realm of the long term credential.
+ * @param user The user name.
+ * @param passwd The pain-text password.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_session_set_long_term_credential(pj_stun_session *sess,
+ const pj_str_t *realm,
+ const pj_str_t *user,
+ const pj_str_t *passwd);
+
-PJ_DECL(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
- pj_bool_t enabled);
+/**
+ * Save a short term credential to be used by this STUN session when sending
+ * outgoing messages. After short term credential is configured, application
+ * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN
+ * message to send the short term credential in the message.
+ *
+ * @param sess The STUN session instance.
+ * @param user The user name.
+ * @param passwd The pain-text password.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_session_set_short_term_credential(pj_stun_session *sess,
+ const pj_str_t *user,
+ const pj_str_t *passwd);
+/**
+ * Create a STUN Bind request message. After the message has been
+ * successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the request.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Create a STUN Allocate request message. After the message has been
+ * successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the request.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Create a STUN Set Active Destination request message. After the message
+ * has been successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the request.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t)
pj_stun_session_create_set_active_destination_req(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Create a STUN Connect request message. After the message has been
+ * successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the request.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create_connect_req(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
-PJ_DECL(pj_status_t)
+/**
+ * Create a STUN Connection Status Indication message. After the message
+ * has been successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the message.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
pj_stun_session_create_connection_status_ind(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Create a STUN Send Indication message. After the message has been
+ * successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the message.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create_send_ind(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Create a STUN Data Indication message. After the message has been
+ * successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess The STUN session instance.
+ * @param p_tdata Pointer to receive STUN transmit data instance containing
+ * the message.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess,
pj_stun_tx_data **p_tdata);
+/**
+ * Send STUN message to the specified destination. This function will encode
+ * the pj_stun_msg instance to a packet buffer, and add credential or
+ * fingerprint if necessary. If the message is a request, the session will
+ * also create and manage a STUN client transaction to be used to manage the
+ * retransmission of the request. After the message has been encoded and
+ * transaction is setup, the \a on_send_msg() callback of pj_stun_session_cb
+ * (which is registered when the STUN session is created) will be called
+ * to actually send the message to the wire.
+ *
+ * @param sess The STUN session instance.
+ * @param options Optional flags, from pj_stun_session_option.
+ * @param addr_len Length of destination address.
+ * @param dst_addr The destination socket address.
+ * @param tdata The STUN transmit data containing the STUN message to
+ * be sent.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
+ unsigned options,
unsigned addr_len,
- const pj_sockaddr_t *server,
+ const pj_sockaddr_t *dst_addr,
pj_stun_tx_data *tdata);
+/**
+ * Application must call this function to notify the STUN session about
+ * the arrival of STUN packet. The STUN packet MUST have been checked
+ * first with #pj_stun_msg_check() to verify that this is indeed a valid
+ * STUN packet.
+ *
+ * The STUN session will decode the packet into pj_stun_msg, and process
+ * the message accordingly. If the message is a response, it will search
+ * through the outstanding STUN client transactions for a matching
+ * transaction ID and hand over the response to the transaction.
+ *
+ * On successful message processing, application will be notified about
+ * the message via one of the pj_stun_session_cb callback.
+ *
+ * @param sess The STUN session instance.
+ * @param packet The packet containing STUN message.
+ * @param pkt_size Size of the packet.
+ * @param parsed_len Optional pointer to receive the size of the parsed
+ * STUN message (useful if packet is received via a
+ * stream oriented protocol).
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
const void *packet,
pj_size_t pkt_size,