summaryrefslogtreecommitdiff
path: root/pjlib-util
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-02-23 01:07:54 +0000
committerBenny Prijono <bennylp@teluu.com>2007-02-23 01:07:54 +0000
commit75d3c1c4773b7b4e35db24ccf695788d871aba2e (patch)
tree833a5a8424487cdba248f146154fa3fbc565a471 /pjlib-util
parentb9c4802224bd1772e144def6df556fbf0a3a71ed (diff)
Ticket #121 and #122: Initial implementation of generic STUN transaction, with Binding request as an example
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@996 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib-util')
-rw-r--r--pjlib-util/include/pjlib-util/stun_endpoint.h12
-rw-r--r--pjlib-util/include/pjlib-util/stun_msg.h9
-rw-r--r--pjlib-util/include/pjlib-util/stun_transaction.h32
-rw-r--r--pjlib-util/src/pjlib-util/stun_endpoint.c12
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg.c6
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg_dump.c34
-rw-r--r--pjlib-util/src/pjlib-util/stun_transaction.c89
-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
-rw-r--r--pjlib-util/src/pjstun-srv/server_main.c16
11 files changed, 720 insertions, 193 deletions
diff --git a/pjlib-util/include/pjlib-util/stun_endpoint.h b/pjlib-util/include/pjlib-util/stun_endpoint.h
index 59bcdee1..fadde315 100644
--- a/pjlib-util/include/pjlib-util/stun_endpoint.h
+++ b/pjlib-util/include/pjlib-util/stun_endpoint.h
@@ -61,16 +61,16 @@ typedef struct pj_stun_endpoint
/**
* Create a STUN endpoint instance.
*/
-PJ_DECL(pj_status_t) pj_stun_endpt_create(pj_pool_factory *factory,
- unsigned options,
- pj_ioqueue_t *ioqueue,
- pj_timer_heap_t *timer_heap,
- pj_stun_endpoint **p_endpt);
+PJ_DECL(pj_status_t) pj_stun_endpoint_create(pj_pool_factory *factory,
+ unsigned options,
+ pj_ioqueue_t *ioqueue,
+ pj_timer_heap_t *timer_heap,
+ pj_stun_endpoint **p_endpt);
/**
* Destroy STUN endpoint instance.
*/
-PJ_DECL(pj_status_t) pj_stun_endpt_destroy(pj_stun_endpoint *endpt);
+PJ_DECL(pj_status_t) pj_stun_endpoint_destroy(pj_stun_endpoint *endpt);
/**
diff --git a/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h
index f5e697f0..b0f80d6b 100644
--- a/pjlib-util/include/pjlib-util/stun_msg.h
+++ b/pjlib-util/include/pjlib-util/stun_msg.h
@@ -1195,15 +1195,16 @@ PJ_DECL(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
* @param msg The STUN message
* @param buffer Buffer where the printable string output will
* be printed on.
- * @param length On input, specify the maximum length of the buffer.
- * On output, it will be filled up with the actual
- * length of the output string.
+ * @param length Specify the maximum length of the buffer.
+ * @param printed_len Optional pointer, which on output will be filled
+ * up with the actual length of the output string.
*
* @return The message string output.
*/
PJ_DECL(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
char *buffer,
- unsigned *length);
+ unsigned length,
+ unsigned *printed_len);
/**
diff --git a/pjlib-util/include/pjlib-util/stun_transaction.h b/pjlib-util/include/pjlib-util/stun_transaction.h
index ee57d11e..5463d3d7 100644
--- a/pjlib-util/include/pjlib-util/stun_transaction.h
+++ b/pjlib-util/include/pjlib-util/stun_transaction.h
@@ -102,6 +102,7 @@ typedef struct pj_stun_tsx_cb
*
* @param endpt The STUN endpoint, which will be used to retrieve
* various settings for the transaction.
+ * @param pool Pool to be used to allocate memory from.
* @param cb Callback structure, to be used by the transaction
* to send message and to notify the application about
* the completion of the transaction.
@@ -110,6 +111,7 @@ typedef struct pj_stun_tsx_cb
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
PJ_DECL(pj_status_t) pj_stun_client_tsx_create( pj_stun_endpoint *endpt,
+ pj_pool_t *pool,
const pj_stun_tsx_cb *cb,
pj_stun_client_tsx **p_tsx);
@@ -168,39 +170,17 @@ PJ_DECL(void*) pj_stun_client_tsx_get_data(pj_stun_client_tsx *tsx);
* @param tsx The STUN client transaction.
* @param retransmit Should this message be retransmitted by the
* STUN transaction.
- * @param msg The STUN message.
+ * @param pkt The STUN packet to send.
+ * @param pkt_len Length of STUN packet.
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
PJ_DECL(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
pj_bool_t retransmit,
- const pj_stun_msg *msg);
+ void *pkt,
+ unsigned pkt_len);
-/**
- * Notify the STUN transaction about the arrival of STUN response.
- * If the STUN response contains a final error (300 and greater), the
- * transaction will be terminated and callback will be called. If the
- * STUN response contains response code 100-299, retransmission
- * will cease, but application must still call this function again
- * with a final response later to allow the transaction to complete.
- *
- * @param tsx The STUN client transaction instance.
- * @param packet The incoming packet.
- * @param pkt_size Size of the incoming packet.
- * @param parsed_len Optional pointer to receive the number of bytes
- * that have been parsed from the incoming packet
- * for the STUN message. This is useful if the
- * STUN transaction is running over stream oriented
- * socket such as TCP or TLS.
- *
- * @return PJ_SUCCESS on success or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
- const void *packet,
- pj_size_t pkt_size,
- unsigned *parsed_len);
-
/**
* Notify the STUN transaction about the arrival of STUN response.
diff --git a/pjlib-util/src/pjlib-util/stun_endpoint.c b/pjlib-util/src/pjlib-util/stun_endpoint.c
index 6a1de943..033a2839 100644
--- a/pjlib-util/src/pjlib-util/stun_endpoint.c
+++ b/pjlib-util/src/pjlib-util/stun_endpoint.c
@@ -25,11 +25,11 @@
/*
* Create a STUN endpoint instance.
*/
-PJ_DEF(pj_status_t) pj_stun_endpt_create( pj_pool_factory *factory,
- unsigned options,
- pj_ioqueue_t *ioqueue,
- pj_timer_heap_t *timer_heap,
- pj_stun_endpoint **p_endpt)
+PJ_DEF(pj_status_t) pj_stun_endpoint_create( pj_pool_factory *factory,
+ unsigned options,
+ pj_ioqueue_t *ioqueue,
+ pj_timer_heap_t *timer_heap,
+ pj_stun_endpoint **p_endpt)
{
pj_pool_t *pool;
pj_stun_endpoint *endpt;
@@ -57,7 +57,7 @@ PJ_DEF(pj_status_t) pj_stun_endpt_create( pj_pool_factory *factory,
/*
* Destroy STUN endpoint instance.
*/
-PJ_DEF(pj_status_t) pj_stun_endpt_destroy(pj_stun_endpoint *endpt)
+PJ_DEF(pj_status_t) pj_stun_endpoint_destroy(pj_stun_endpoint *endpt)
{
PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c
index 9abb2a4c..ec92f6b6 100644
--- a/pjlib-util/src/pjlib-util/stun_msg.c
+++ b/pjlib-util/src/pjlib-util/stun_msg.c
@@ -1332,8 +1332,10 @@ PJ_DEF(pj_status_t) pj_stun_msg_check(const void *pdu, unsigned pdu_len,
{
pj_stun_msg_hdr *hdr;
- PJ_ASSERT_RETURN(pdu && pdu_len > sizeof(pj_stun_msg_hdr),
- PJLIB_UTIL_ESTUNINMSGLEN);
+ PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
+
+ if (pdu_len < sizeof(pj_stun_msg_hdr))
+ return PJLIB_UTIL_ESTUNINMSGLEN;
PJ_UNUSED_ARG(options);
diff --git a/pjlib-util/src/pjlib-util/stun_msg_dump.c b/pjlib-util/src/pjlib-util/stun_msg_dump.c
index 2def62e4..21d569da 100644
--- a/pjlib-util/src/pjlib-util/stun_msg_dump.c
+++ b/pjlib-util/src/pjlib-util/stun_msg_dump.c
@@ -32,7 +32,7 @@ static int print_attr(char *buffer, unsigned length,
char *p = buffer, *end = buffer + length;
int len;
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
" %s: length=%d",
pj_stun_get_attr_name(ahdr->type),
(int)ahdr->length);
@@ -58,16 +58,16 @@ static int print_attr(char *buffer, unsigned length,
attr = (const pj_stun_generic_ip_addr_attr*)ahdr;
if (attr->addr.addr.sa_family == PJ_AF_INET) {
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", IPv4 addr=%s:%d\n",
pj_inet_ntoa(attr->addr.ipv4.sin_addr),
pj_ntohs(attr->addr.ipv4.sin_port));
} else if (attr->addr.addr.sa_family == PJ_AF_INET6) {
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", IPv6 addr present\n");
} else {
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", INVALID ADDRESS FAMILY!\n");
}
}
@@ -87,8 +87,8 @@ static int print_attr(char *buffer, unsigned length,
const pj_stun_generic_uint_attr *attr;
attr = (const pj_stun_generic_uint_attr*)ahdr;
- len = pj_ansi_snprintf(buffer, end-p,
- ", value=%d (%x)\n",
+ len = pj_ansi_snprintf(p, end-p,
+ ", value=%d (0x%x)\n",
(pj_uint32_t)attr->value,
(pj_uint32_t)attr->value);
}
@@ -103,7 +103,7 @@ static int print_attr(char *buffer, unsigned length,
const pj_stun_generic_string_attr *attr;
attr = (pj_stun_generic_string_attr*)ahdr;
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", value=\"%.*s\"\n",
(int)attr->value.slen,
attr->value.ptr);
@@ -115,7 +115,7 @@ static int print_attr(char *buffer, unsigned length,
const pj_stun_error_code_attr *attr;
attr = (const pj_stun_error_code_attr*) ahdr;
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", err_code=%d, reason=\"%.*s\"\n",
attr->err_class*100 + attr->number,
(int)attr->reason.slen,
@@ -130,12 +130,12 @@ static int print_attr(char *buffer, unsigned length,
attr = (const pj_stun_unknown_attr*) ahdr;
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
", unknown list:");
APPLY();
for (j=0; j<attr->attr_count; ++j) {
- len = pj_ansi_snprintf(buffer, end-p,
+ len = pj_ansi_snprintf(p, end-p,
" %d",
(int)attr->attrs[j]);
APPLY();
@@ -147,7 +147,7 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_DATA:
case PJ_STUN_ATTR_USE_CANDIDATE:
default:
- len = pj_ansi_snprintf(buffer, end-p, "\n");
+ len = pj_ansi_snprintf(p, end-p, "\n");
break;
}
@@ -166,7 +166,8 @@ on_return:
*/
PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
char *buffer,
- unsigned *length)
+ unsigned length,
+ unsigned *printed_len)
{
char *p, *end;
int len;
@@ -175,7 +176,7 @@ PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
PJ_ASSERT_RETURN(msg && buffer && length, NULL);
p = buffer;
- end = buffer + (*length);
+ end = buffer + length;
len = pj_ansi_snprintf(p, end-p, "STUN %s %s\n",
pj_stun_get_method_name(msg->hdr.type),
@@ -183,8 +184,8 @@ PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
APPLY();
len = pj_ansi_snprintf(p, end-p,
- " Hdr: length=%d, magic=%x, tsx_id=%x %x %x\n"
- " Attributes:\n",
+ " Hdr: length=%d, magic=%08x, tsx_id=%08x %08x %08x\n"
+ " Attributes:\n",
msg->hdr.length,
msg->hdr.magic,
*(pj_uint32_t*)&msg->hdr.tsx_id[0],
@@ -199,7 +200,8 @@ PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
on_return:
*p = '\0';
- *length = (p-buffer);
+ if (printed_len)
+ *printed_len = (p-buffer);
return buffer;
}
diff --git a/pjlib-util/src/pjlib-util/stun_transaction.c b/pjlib-util/src/pjlib-util/stun_transaction.c
index 701122fe..02f33177 100644
--- a/pjlib-util/src/pjlib-util/stun_transaction.c
+++ b/pjlib-util/src/pjlib-util/stun_transaction.c
@@ -31,19 +31,18 @@
struct pj_stun_client_tsx
{
char obj_name[PJ_MAX_OBJ_NAME];
- pj_pool_t *pool;
pj_stun_endpoint *endpt;
pj_stun_tsx_cb cb;
void *user_data;
- pj_uint32_t tsx_id[4];
-
+ pj_bool_t complete;
+ \
pj_bool_t require_retransmit;
pj_timer_entry timer;
unsigned transmit_count;
pj_time_val retransmit_time;
- pj_uint8_t last_pkt[PJ_STUN_MAX_PKT_LEN];
+ void *last_pkt;
unsigned last_pkt_size;
};
@@ -65,25 +64,23 @@ static void stun_perror(pj_stun_client_tsx *tsx, const char *title,
* Create a STUN client transaction.
*/
PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_endpoint *endpt,
+ pj_pool_t *pool,
const pj_stun_tsx_cb *cb,
pj_stun_client_tsx **p_tsx)
{
- pj_pool_t *pool;
pj_stun_client_tsx *tsx;
PJ_ASSERT_RETURN(endpt && cb && p_tsx, PJ_EINVAL);
PJ_ASSERT_RETURN(cb->on_send_msg, PJ_EINVAL);
- pool = pj_pool_create(endpt->pf, "tsx", 1000, 1000, NULL);
tsx = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_client_tsx);
- tsx->pool = pool;
tsx->endpt = endpt;
pj_memcpy(&tsx->cb, cb, sizeof(*cb));
tsx->timer.cb = &retransmit_timer_callback;
tsx->timer.user_data = tsx;
- pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "stuntsx%p", pool);
+ pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "stuntsx%p", tsx);
*p_tsx = tsx;
@@ -103,12 +100,21 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_destroy(pj_stun_client_tsx *tsx)
pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
tsx->timer.id = 0;
}
- pj_pool_release(tsx->pool);
return PJ_SUCCESS;
}
/*
+ * Check if transaction has completed.
+ */
+PJ_DEF(pj_bool_t) pj_stun_client_tsx_is_complete(pj_stun_client_tsx *tsx)
+{
+ PJ_ASSERT_RETURN(tsx, PJ_FALSE);
+ return tsx->complete;
+}
+
+
+/*
* Set user data.
*/
PJ_DEF(pj_status_t) pj_stun_client_tsx_set_data(pj_stun_client_tsx *tsx,
@@ -145,13 +151,13 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
tsx->retransmit_time.sec = 0;
tsx->retransmit_time.msec = tsx->endpt->rto_msec;
- } else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT) {
+ } else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT-1) {
unsigned msec;
msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
- msec = (msec >> 1) + 100;
+ msec = (msec << 1) + 100;
tsx->retransmit_time.sec = msec / 1000;
- tsx->retransmit_time.msec = msec % 100;
+ tsx->retransmit_time.msec = msec % 1000;
} else {
tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000;
@@ -161,13 +167,14 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
/* Schedule timer first because when send_msg() failed we can
* cancel it (as opposed to when schedule_timer() failed we cannot
* cancel transmission).
- */
+ */;
status = pj_timer_heap_schedule(tsx->endpt->timer_heap, &tsx->timer,
&tsx->retransmit_time);
if (status != PJ_SUCCESS) {
tsx->timer.id = 0;
return status;
}
+ tsx->timer.id = TIMER_ACTIVE;
}
@@ -195,24 +202,15 @@ static pj_status_t tsx_transmit_msg(pj_stun_client_tsx *tsx)
*/
PJ_DEF(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
pj_bool_t retransmit,
- const pj_stun_msg *msg)
+ void *pkt,
+ unsigned pkt_len)
{
- pj_status_t status;
-
- PJ_ASSERT_RETURN(tsx && msg, PJ_EINVAL);
- PJ_ASSERT_RETURN(tsx->timer.id != 0, PJ_EBUSY);
+ PJ_ASSERT_RETURN(tsx && pkt && pkt_len, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tsx->timer.id == 0, PJ_EBUSY);
/* Encode message */
- status = pj_stun_msg_encode(msg, tsx->last_pkt, sizeof(tsx->last_pkt),
- 0, &tsx->last_pkt_size);
- if (status != PJ_SUCCESS) {
- stun_perror(tsx, "STUN msg_encode() failed", status);
- return status;
- }
-
- /* Update STUN transaction ID */
- tsx->tsx_id[0] = msg->hdr.magic;
- pj_memcpy(&tsx->tsx_id[1], msg->hdr.tsx_id, 12);
+ tsx->last_pkt = pkt;
+ tsx->last_pkt_size = pkt_len;
/* Update STUN retransmit flag */
tsx->require_retransmit = retransmit;
@@ -235,6 +233,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
/* Retransmission count exceeded. Transaction has failed */
tsx->timer.id = 0;
PJ_LOG(4,(tsx->obj_name, "STUN timeout waiting for response"));
+ tsx->complete = PJ_TRUE;
if (tsx->cb.on_complete) {
tsx->cb.on_complete(tsx, PJLIB_UTIL_ESTUNNOTRESPOND, NULL);
}
@@ -245,6 +244,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap,
status = tsx_transmit_msg(tsx);
if (status != PJ_SUCCESS) {
tsx->timer.id = 0;
+ tsx->complete = PJ_TRUE;
if (tsx->cb.on_complete) {
tsx->cb.on_complete(tsx, status, NULL);
}
@@ -271,12 +271,6 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
return PJLIB_UTIL_ESTUNNOTRESPONSE;
}
- /* Compare response's transaction ID */
- if (msg->hdr.magic != tsx->tsx_id[0] ||
- pj_memcmp(msg->hdr.tsx_id, &tsx->tsx_id[1], 12) != 0)
- {
- return PJLIB_UTIL_ESTUNINVALIDID;
- }
/* We have a response with matching transaction ID.
* We can cancel retransmit timer now.
@@ -311,6 +305,7 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
}
/* Call callback */
+ tsx->complete = PJ_TRUE;
if (tsx->cb.on_complete) {
tsx->cb.on_complete(tsx, status, msg);
}
@@ -319,29 +314,3 @@ PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
}
-
-/*
- * Notify the STUN transaction about the arrival of STUN response.
- */
-PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
- const void *packet,
- pj_size_t pkt_size,
- unsigned *parsed_len)
-{
- pj_stun_msg *msg;
- pj_status_t status;
-
- PJ_ASSERT_RETURN(tsx && packet && pkt_size, PJ_EINVAL);
-
- /* Try to parse the message */
- status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
- pkt_size, 0, &msg, parsed_len,
- NULL, NULL, NULL);
- if (status != PJ_SUCCESS) {
- stun_perror(tsx, "STUN msg_decode() error", status);
- return status;
- }
-
- return pj_stun_client_tsx_on_rx_msg(tsx, msg);
-}
-
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,
diff --git a/pjlib-util/src/pjstun-srv/server_main.c b/pjlib-util/src/pjstun-srv/server_main.c
index 56a1bf85..5fd58ef9 100644
--- a/pjlib-util/src/pjstun-srv/server_main.c
+++ b/pjlib-util/src/pjstun-srv/server_main.c
@@ -100,6 +100,13 @@ static pj_status_t send_msg(struct service *svc, const pj_stun_msg *msg)
pj_ssize_t length;
pj_status_t status;
+ /* Print to log */
+ PJ_LOG(4,(THIS_FILE, "TX STUN message: \n"
+ "--- begin STUN message ---\n"
+ "%s"
+ "--- end of STUN message ---\n",
+ pj_stun_msg_dump(msg, svc->tx_pkt, sizeof(svc->tx_pkt), NULL)));
+
/* Encode packet */
tx_pkt_len = sizeof(svc->tx_pkt);
status = pj_stun_msg_encode(msg, svc->tx_pkt, tx_pkt_len, 0,
@@ -220,6 +227,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
unsigned err_code;
unsigned uattr_cnt;
pj_uint16_t uattr_types[16];
+ char dump[512];
pj_status_t status;
if (bytes_read <= 0)
@@ -241,9 +249,11 @@ static void on_read_complete(pj_ioqueue_key_t *key,
goto next_read;
}
- PJ_LOG(4,(THIS_FILE, "RX STUN %s %s message",
- pj_stun_get_method_name(rx_msg->hdr.type),
- pj_stun_get_class_name(rx_msg->hdr.type)));
+ PJ_LOG(4,(THIS_FILE, "RX STUN message: \n"
+ "--- begin STUN message ---\n"
+ "%s"
+ "--- end of STUN message ---\n",
+ pj_stun_msg_dump(rx_msg, dump, sizeof(dump), NULL)));
if (PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) {
switch (rx_msg->hdr.type) {