summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjlib-util/include/pjlib-util/stun_msg.h46
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg.c200
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg_dump.c4
-rw-r--r--pjlib-util/src/pjstun-client/client_main.c229
-rw-r--r--pjlib-util/src/pjstun-srv-test/bind_usage.c16
-rw-r--r--pjlib-util/src/pjstun-srv-test/main.c9
-rw-r--r--pjlib-util/src/pjstun-srv-test/server.h15
-rw-r--r--pjlib-util/src/pjstun-srv-test/turn_usage.c181
-rw-r--r--pjlib-util/src/pjstun-srv-test/usage.c8
-rw-r--r--pjlib/include/pj/hash.h3
-rw-r--r--pjlib/src/pj/addr_resolv_sock.c2
11 files changed, 527 insertions, 186 deletions
diff --git a/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h
index f7f4d086..ae66c2d1 100644
--- a/pjlib-util/include/pjlib-util/stun_msg.h
+++ b/pjlib-util/include/pjlib-util/stun_msg.h
@@ -269,12 +269,12 @@ typedef enum pj_stun_msg_type
/**
* STUN/TURN Send Indication
*/
- PJ_STUN_SEND_INDICATION = 0x0004,
+ PJ_STUN_SEND_INDICATION = 0x0014,
/**
* STUN/TURN Data Indication
*/
- PJ_STUN_DATA_INDICATION = 0x0115,
+ PJ_STUN_DATA_INDICATION = 0x0015,
/**
* STUN/TURN Set Active Destination Request
@@ -309,7 +309,7 @@ typedef enum pj_stun_msg_type
/**
* STUN/TURN Connect Status Indication
*/
- PJ_STUN_CONNECT_STATUS_INDICATION = 0x0118
+ PJ_STUN_CONNECT_STATUS_INDICATION = 0x0018
} pj_stun_msg_type;
@@ -515,7 +515,7 @@ typedef struct pj_stun_attr_hdr
\endverbatim
*/
-typedef struct pj_stun_ip_addr_attr
+typedef struct pj_stun_sockaddr_attr
{
/**
* Standard STUN attribute header.
@@ -523,6 +523,12 @@ typedef struct pj_stun_ip_addr_attr
pj_stun_attr_hdr hdr;
/**
+ * Flag to indicate whether this attribute should be sent in XOR-ed
+ * format, or has been received in XOR-ed format.
+ */
+ pj_bool_t xor_ed;
+
+ /**
* The socket address (as a union)
*/
union {
@@ -531,7 +537,7 @@ typedef struct pj_stun_ip_addr_attr
pj_sockaddr_in6 ipv6; /**< IPv6 socket address. */
} addr;
-} pj_stun_ip_addr_attr;
+} pj_stun_sockaddr_attr;
/**
@@ -744,7 +750,7 @@ typedef struct pj_stun_unknown_attr
* This structure describes STUN MAPPED-ADDRESS attribute.
* The MAPPED-ADDRESS attribute indicates the mapped transport address.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_mapped_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_mapped_addr_attr;
/**
@@ -756,7 +762,7 @@ typedef struct pj_stun_ip_addr_attr pj_stun_mapped_addr_attr;
* obfuscated through the XOR function, STUN messages are able to pass
* through NATs which would otherwise interfere with STUN.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_xor_mapped_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_xor_mapped_addr_attr;
/**
@@ -776,7 +782,7 @@ typedef struct pj_stun_string_attr pj_stun_server_attr;
* different STUN server to try. It is encoded in the same way as
* MAPPED-ADDRESS.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_alt_server_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_alt_server_attr;
/**
@@ -797,7 +803,7 @@ typedef struct pj_stun_uint_attr pj_stun_refresh_interval_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_response_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_response_addr_attr;
/**
@@ -812,7 +818,7 @@ typedef struct pj_stun_ip_addr_attr pj_stun_response_addr_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_changed_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_changed_addr_attr;
/**
@@ -844,7 +850,7 @@ typedef struct pj_stun_uint_attr pj_stun_change_request_attr;
* Note that the usage of this attribute has been deprecated by the
* RFC 3489-bis standard.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_src_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_src_addr_attr;
/**
@@ -856,7 +862,7 @@ typedef struct pj_stun_ip_addr_attr pj_stun_src_addr_attr;
* traceability, so that a STUN server cannot be used as a reflector for
* denial-of-service attacks.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_reflected_from_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_reflected_from_attr;
/**
@@ -901,7 +907,7 @@ typedef struct pj_stun_uint_attr pj_stun_bandwidth_attr;
* The REMOTE-ADDRESS specifies the address and port of the peer as seen
* from the STUN relay server.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_remote_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_remote_addr_attr;
/**
@@ -919,7 +925,7 @@ typedef struct pj_stun_binary_attr pj_stun_data_attr;
* The RELAY-ADDRESS is present in Allocate responses. It specifies the
* address and port that the server allocated to the client.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_relay_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_relay_addr_attr;
/**
@@ -975,7 +981,7 @@ typedef struct pj_stun_uint_attr pj_stun_req_transport_attr;
* The REQUESTED-IP attribute is used by the client to request that a
* specific IP address be allocated to it.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_req_ip_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_req_ip_attr;
/**
* This describes the XOR-REFLECTED-FROM attribute, as described by
@@ -987,7 +993,7 @@ typedef struct pj_stun_ip_addr_attr pj_stun_req_ip_attr;
* the private network address. XOR-REFLECTED-FROM has identical syntax
* to XOR-MAPPED-ADDRESS.
*/
-typedef struct pj_stun_ip_addr_attr pj_stun_xor_reflected_from_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_xor_reflected_from_attr;
/**
* This describes the PRIORITY attribute from draft-ietf-mmusic-ice-13.
@@ -1015,7 +1021,7 @@ typedef struct pj_stun_empty_attr pj_stun_use_candidate_attr;
* STUN client to 'walk backwards' and communicate directly with all of
* the STUN-aware NATs along the path.
*/
-typedef pj_stun_ip_addr_attr pj_stun_xor_internal_addr_attr;
+typedef pj_stun_sockaddr_attr pj_stun_xor_internal_addr_attr;
/**
* This describes the STUN TIMER-VAL attribute.
@@ -1304,12 +1310,12 @@ PJ_DECL(pj_stun_attr_hdr*) pj_stun_msg_find_attr(const pj_stun_msg *msg,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t) pj_stun_ip_addr_attr_create(pj_pool_t *pool,
+PJ_DECL(pj_status_t) pj_stun_sockaddr_attr_create(pj_pool_t *pool,
int attr_type,
pj_bool_t xor_ed,
const pj_sockaddr_t *addr,
unsigned addr_len,
- pj_stun_ip_addr_attr **p_attr);
+ pj_stun_sockaddr_attr **p_attr);
/**
@@ -1327,7 +1333,7 @@ PJ_DECL(pj_status_t) pj_stun_ip_addr_attr_create(pj_pool_t *pool,
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
-PJ_DECL(pj_status_t) pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
+PJ_DECL(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
pj_stun_msg *msg,
int attr_type,
pj_bool_t xor_ed,
diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c
index e34655f8..1c750d8e 100644
--- a/pjlib-util/src/pjlib-util/stun_msg.c
+++ b/pjlib-util/src/pjlib-util/stun_msg.c
@@ -89,10 +89,13 @@ struct attr_desc
};
-static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
+static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr);
-static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf,
+static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr);
+static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
unsigned len,
unsigned *printed);
static pj_status_t decode_string_attr(pj_pool_t *pool,
@@ -143,14 +146,14 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_MAPPED_ADDR, */
"MAPPED-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_RESPONSE_ADDR, */
"RESPONSE-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_CHANGE_REQUEST, */
@@ -161,14 +164,14 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_SOURCE_ADDR, */
"SOURCE-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_CHANGED_ADDR, */
"CHANGED-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_USERNAME, */
@@ -203,8 +206,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REFLECTED_FROM, */
"REFLECTED-FROM",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* ID 0x000C is not assigned */
@@ -245,8 +248,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REMOTE_ADDRESS, */
"REMOTE-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_DATA, */
@@ -269,8 +272,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_RELAY_ADDRESS, */
"RELAY-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_REQUESTED_ADDR_TYPE, */
@@ -329,8 +332,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */
"XOR-MAPPED-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_xored_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_TIMER_VAL, */
@@ -341,14 +344,14 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_REQUESTED_IP, */
"REQUESTED-IP",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */
"XOR-REFLECTED-FROM",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_xored_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_PRIORITY, */
@@ -365,8 +368,8 @@ struct attr_desc mandatory_attr_desc[] =
{
/* PJ_STUN_ATTR_XOR_INTERNAL_ADDR, */
"XOR-INTERNAL-ADDRESS",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_xored_sockaddr_attr,
+ &encode_sockaddr_attr
},
/* Sentinel */
@@ -395,8 +398,8 @@ static struct attr_desc extended_attr_desc[] =
{
/* PJ_STUN_ATTR_ALTERNATE_SERVER, */
"ALTERNATE-SERVER",
- &decode_ip_addr_attr,
- &encode_ip_addr_attr
+ &decode_sockaddr_attr,
+ &encode_sockaddr_attr
},
{
/* PJ_STUN_ATTR_REFRESH_INTERVAL, */
@@ -539,36 +542,24 @@ PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
* Create a generic STUN IP address attribute for IPv4 address.
*/
PJ_DEF(pj_status_t)
-pj_stun_ip_addr_attr_create(pj_pool_t *pool,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len,
- pj_stun_ip_addr_attr **p_attr)
+pj_stun_sockaddr_attr_create(pj_pool_t *pool,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len,
+ pj_stun_sockaddr_attr **p_attr)
{
- pj_stun_ip_addr_attr *attr;
+ pj_stun_sockaddr_attr *attr;
PJ_ASSERT_RETURN(pool && addr_len && addr && p_attr, PJ_EINVAL);
PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
- attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
+ attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
- if (!xor_ed) {
- pj_memcpy(&attr->addr, addr, addr_len);
- } else if (addr_len == sizeof(pj_sockaddr_in)) {
- const pj_sockaddr_in *addr4 = (const pj_sockaddr_in*) addr;
-
- pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
- attr->addr.ipv4.sin_port = (pj_uint16_t)(addr4->sin_port ^ 0x2112);
- attr->addr.ipv4.sin_addr.s_addr = (addr4->sin_addr.s_addr ^
- pj_htonl(0x2112A442));
- } else if (addr_len == sizeof(pj_sockaddr_in6)) {
- return PJLIB_UTIL_ESTUNIPV6NOTSUPP;
- } else {
- return PJLIB_UTIL_ESTUNINADDRLEN;
- }
+ pj_memcpy(&attr->addr, addr, addr_len);
+ attr->xor_ed = xor_ed;
*p_attr = attr;
@@ -580,17 +571,17 @@ pj_stun_ip_addr_attr_create(pj_pool_t *pool,
* Create and add generic STUN IP address attribute to a STUN message.
*/
PJ_DEF(pj_status_t)
-pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
- pj_stun_msg *msg,
- int attr_type,
- pj_bool_t xor_ed,
- const pj_sockaddr_t *addr,
- unsigned addr_len)
+pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_bool_t xor_ed,
+ const pj_sockaddr_t *addr,
+ unsigned addr_len)
{
- pj_stun_ip_addr_attr *attr;
+ pj_stun_sockaddr_attr *attr;
pj_status_t status;
- status = pj_stun_ip_addr_attr_create(pool, attr_type, xor_ed,
+ status = pj_stun_sockaddr_attr_create(pool, attr_type, xor_ed,
addr, addr_len, &attr);
if (status != PJ_SUCCESS)
return status;
@@ -598,15 +589,15 @@ pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
return pj_stun_msg_add_attr(msg, &attr->hdr);
}
-static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
- const pj_uint8_t *buf,
- void **p_attr)
+static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
{
- pj_stun_ip_addr_attr *attr;
+ pj_stun_sockaddr_attr *attr;
pj_uint32_t val;
/* Create the attribute */
- attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
+ attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
pj_memcpy(attr, buf, ATTR_HDR_LEN);
/* Convert to host byte order */
@@ -626,7 +617,7 @@ static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
/* Get port and address */
pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
- attr->addr.ipv4.sin_port = getval16(buf, ATTR_HDR_LEN + 2);
+ pj_memcpy(&attr->addr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
pj_memcpy(&attr->addr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
/* Done */
@@ -636,23 +627,64 @@ static pj_status_t decode_ip_addr_attr(pj_pool_t *pool,
}
-static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf,
- unsigned len, unsigned *printed)
+static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
+ const pj_uint8_t *buf,
+ void **p_attr)
+{
+ pj_stun_sockaddr_attr *attr;
+ pj_uint32_t val;
+
+ /* Create the attribute */
+ attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
+ pj_memcpy(attr, buf, ATTR_HDR_LEN);
+
+ /* Convert to host byte order */
+ attr->hdr.type = pj_ntohs(attr->hdr.type);
+ attr->hdr.length = pj_ntohs(attr->hdr.length);
+
+ /* Check that the attribute length is valid */
+ if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
+ return PJLIB_UTIL_ESTUNINATTRLEN;
+
+ /* Check address family */
+ val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
+
+ /* Check address family is valid (only supports ipv4 for now) */
+ if (val != 1)
+ return PJLIB_UTIL_ESTUNIPV6NOTSUPP;
+
+ /* Get port and address */
+ pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
+ pj_memcpy(&attr->addr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
+ pj_memcpy(&attr->addr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
+
+ attr->addr.ipv4.sin_port ^= 0x2112;
+ attr->addr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
+
+ /* Done */
+ *p_attr = attr;
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
+ unsigned len, unsigned *printed)
{
enum {
ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IP_ADDR_LEN
};
pj_uint8_t *start_buf = buf;
- const pj_stun_ip_addr_attr *ca =
- (const pj_stun_ip_addr_attr *)a;
- pj_stun_ip_addr_attr *attr;
+ const pj_stun_sockaddr_attr *ca =
+ (const pj_stun_sockaddr_attr *)a;
+ pj_stun_sockaddr_attr *attr;
if (len < ATTR_LEN)
return PJ_ETOOSMALL;
/* Copy and convert headers to network byte order */
pj_memcpy(buf, a, ATTR_HDR_LEN);
- attr = (pj_stun_ip_addr_attr*) buf;
+ attr = (pj_stun_sockaddr_attr*) buf;
attr->hdr.type = pj_htons(attr->hdr.type);
attr->hdr.length = pj_htons((pj_uint16_t)STUN_GENERIC_IP_ADDR_LEN);
buf += ATTR_HDR_LEN;
@@ -664,13 +696,33 @@ static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf,
PJ_ASSERT_RETURN(ca->addr.addr.sa_family == PJ_AF_INET, PJ_EINVAL);
*buf++ = 1;
- /* Port */
- pj_memcpy(buf, &ca->addr.ipv4.sin_port, 2);
- buf += 2;
+ if (ca->xor_ed) {
+ pj_uint32_t addr;
+ pj_uint16_t port;
+
+ addr = ca->addr.ipv4.sin_addr.s_addr;
+ port = ca->addr.ipv4.sin_port;
- /* Address */
- pj_memcpy(buf, &ca->addr.ipv4.sin_addr, 4);
- buf += 4;
+ port ^= 0x2112;
+ addr ^= pj_htonl(0x2112A442);
+
+ /* Port */
+ pj_memcpy(buf, &port, 2);
+ buf += 2;
+
+ /* Address */
+ pj_memcpy(buf, &addr, 4);
+ buf += 4;
+
+ } else {
+ /* Port */
+ pj_memcpy(buf, &ca->addr.ipv4.sin_port, 2);
+ buf += 2;
+
+ /* Address */
+ pj_memcpy(buf, &ca->addr.ipv4.sin_addr, 4);
+ buf += 4;
+ }
pj_assert(buf - start_buf == ATTR_LEN);
diff --git a/pjlib-util/src/pjlib-util/stun_msg_dump.c b/pjlib-util/src/pjlib-util/stun_msg_dump.c
index e599856b..0ee0ebe4 100644
--- a/pjlib-util/src/pjlib-util/stun_msg_dump.c
+++ b/pjlib-util/src/pjlib-util/stun_msg_dump.c
@@ -76,9 +76,9 @@ static int print_attr(char *buffer, unsigned length,
case PJ_STUN_ATTR_XOR_INTERNAL_ADDR:
case PJ_STUN_ATTR_ALTERNATE_SERVER:
{
- const pj_stun_ip_addr_attr *attr;
+ const pj_stun_sockaddr_attr *attr;
- attr = (const pj_stun_ip_addr_attr*)ahdr;
+ attr = (const pj_stun_sockaddr_attr*)ahdr;
if (attr->addr.addr.sa_family == PJ_AF_INET) {
len = pj_ansi_snprintf(p, end-p,
diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c
index c5c73441..be65b516 100644
--- a/pjlib-util/src/pjstun-client/client_main.c
+++ b/pjlib-util/src/pjstun-client/client_main.c
@@ -21,8 +21,9 @@
#define THIS_FILE "client_main.c"
+#define LOCAL_PORT 1998
#define BANDWIDTH 64 /* -1 to disable */
-#define LIFETIME 30 /* -1 to disable */
+#define LIFETIME 600 /* -1 to disable */
#define REQ_TRANSPORT -1 /* 0: udp, 1: tcp, -1: disable */
#define REQ_PORT_PROPS -1 /* -1 to disable */
#define REQ_IP NULL /* IP address string */
@@ -39,8 +40,10 @@ static struct global
pj_thread_t *thread;
pj_bool_t quit;
pj_sockaddr_in peer_addr;
- pj_sockaddr_in srv_addr; /**< server addr */
-
+ pj_sockaddr_in srv_addr;
+ pj_sockaddr_in relay_addr;
+ char data_buf[256];
+ char *data;
} g;
static struct options
@@ -51,10 +54,14 @@ static struct options
char *user_name;
char *password;
char *nonce;
+ char *peer_addr;
pj_bool_t use_fingerprint;
} o;
+static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr);
+
+
static my_perror(const char *title, pj_status_t status)
{
char errmsg[PJ_ERR_MSG_SIZE];
@@ -87,7 +94,26 @@ static void on_request_complete(pj_stun_session *sess,
const pj_stun_msg *response)
{
if (status == PJ_SUCCESS) {
- puts("Client transaction completes");
+ switch (response->hdr.type) {
+ case PJ_STUN_ALLOCATE_RESPONSE:
+ {
+ pj_stun_relay_addr_attr *ar;
+
+ ar = (pj_stun_relay_addr_attr*)
+ pj_stun_msg_find_attr(response,
+ PJ_STUN_ATTR_RELAY_ADDR, 0);
+ if (ar) {
+ pj_memcpy(&g.relay_addr, &ar->addr.ipv4,
+ sizeof(pj_sockaddr_in));
+ PJ_LOG(3,(THIS_FILE, "Relay address is %s:%d",
+ pj_inet_ntoa(g.relay_addr.sin_addr),
+ (int)pj_ntohs(g.relay_addr.sin_port)));
+ } else {
+ pj_memset(&g.relay_addr, 0, sizeof(g.relay_addr));
+ }
+ }
+ break;
+ }
} else {
my_perror("Client transaction error", status);
}
@@ -119,12 +145,19 @@ static int worker_thread(void *unused)
len = sizeof(buffer);
addrlen = sizeof(addr);
rc = pj_sock_recvfrom(g.sock, buffer, &len, 0, &addr, &addrlen);
- if (rc == PJ_SUCCESS && len > 0) {
+ if (rc != PJ_SUCCESS || len <= 0)
+ continue;
+
+ if (pj_stun_msg_check(buffer, len, PJ_STUN_IS_DATAGRAM)==PJ_SUCCESS) {
rc = pj_stun_session_on_rx_pkt(g.sess, buffer, len,
- PJ_STUN_IS_DATAGRAM|PJ_STUN_CHECK_PACKET,
+ 0,
NULL, &addr, addrlen);
if (rc != PJ_SUCCESS)
my_perror("Error processing packet", rc);
+
+ } else {
+ buffer[len] = '\0';
+ PJ_LOG(3,(THIS_FILE, "Received data: %s", (char*)buffer));
}
}
} else if (n < 0)
@@ -138,6 +171,7 @@ static int init()
{
pj_sockaddr_in addr;
pj_stun_session_cb stun_cb;
+ int len;
pj_status_t status;
g.sock = PJ_INVALID_SOCKET;
@@ -182,6 +216,20 @@ static int init()
status = pj_sockaddr_in_init(&addr, NULL, 0);
pj_assert(status == PJ_SUCCESS);
+ addr.sin_port = pj_htons((pj_uint16_t)LOCAL_PORT);
+ status = pj_sock_bind(g.sock, &addr, sizeof(addr));
+ pj_assert(status == PJ_SUCCESS);
+
+ len = sizeof(addr);
+ status = pj_sock_getsockname(g.sock, &addr, &len);
+ pj_assert(status == PJ_SUCCESS);
+
+ PJ_LOG(3,(THIS_FILE, "Listening on port %d", (int)pj_ntohs(addr.sin_port)));
+
+ pj_memcpy(&g.peer_addr, &addr, sizeof(pj_sockaddr_in));
+ if (g.peer_addr.sin_addr.s_addr == 0)
+ pj_gethostip(&g.peer_addr.sin_addr);
+
pj_memset(&stun_cb, 0, sizeof(stun_cb));
stun_cb.on_send_msg = &on_send_msg;
stun_cb.on_request_complete = &on_request_complete;
@@ -208,6 +256,11 @@ static int init()
puts("Credential not set");
}
+ if (o.peer_addr) {
+ if (parse_addr(o.peer_addr, &g.peer_addr)!=PJ_SUCCESS)
+ return -1;
+ }
+
status = pj_thread_create(g.pool, "stun", &worker_thread, NULL,
0, 0, &g.thread);
if (status != PJ_SUCCESS)
@@ -296,7 +349,7 @@ static void send_allocate_request(pj_bool_t allocate)
pj_str_t tmp;
pj_sockaddr_in_init(&addr, pj_cstr(&tmp, REQ_IP), 0);
- pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_REQ_IP, PJ_FALSE,
&addr, sizeof(addr));
}
@@ -320,11 +373,11 @@ static void send_sad_request(pj_bool_t set)
return;
}
- rc = pj_stun_session_create_req(g.sess, PJ_STUN_ALLOCATE_REQUEST, &tdata);
+ rc = pj_stun_session_create_req(g.sess, PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST, &tdata);
pj_assert(rc == PJ_SUCCESS);
if (set) {
- pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
&g.peer_addr, sizeof(g.peer_addr));
}
@@ -337,18 +390,117 @@ static void send_sad_request(pj_bool_t set)
static void send_send_ind(void)
{
+ pj_stun_tx_data *tdata;
+ int len;
+ pj_status_t rc;
+
+ if (g.peer_addr.sin_addr.s_addr == 0 ||
+ g.peer_addr.sin_port == 0)
+ {
+ puts("Error: peer address is not set");
+ return;
+ }
+
+ len = strlen(g.data);
+ if (len==0) {
+ puts("Error: data is not set");
+ return;
+ }
+
+ rc = pj_stun_session_create_ind(g.sess, PJ_STUN_SEND_INDICATION, &tdata);
+ pj_assert(rc == PJ_SUCCESS);
+
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
+ &g.peer_addr, sizeof(g.peer_addr));
+ pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_DATA, g.data, len);
+
+ rc = pj_stun_session_send_msg(g.sess, PJ_FALSE,
+ &g.srv_addr, sizeof(g.srv_addr),
+ tdata);
+ pj_assert(rc == PJ_SUCCESS);
+
+}
+
+static void send_raw_data_to_srv(void)
+{
+ pj_ssize_t len;
+
+ if (g.srv_addr.sin_addr.s_addr == 0 ||
+ g.srv_addr.sin_port == 0)
+ {
+ puts("Error: server address is not set");
+ return;
+ }
+
+ len = strlen(g.data);
+ if (len==0) {
+ puts("Error: data is not set");
+ return;
+ }
+
+ len = strlen(g.data);
+ pj_sock_sendto(g.sock, g.data, &len, 0, &g.srv_addr, sizeof(g.srv_addr));
+}
+
+static void send_raw_data_to_relay(void)
+{
+ pj_ssize_t len;
+
+ if (g.relay_addr.sin_addr.s_addr == 0 ||
+ g.relay_addr.sin_port == 0)
+ {
+ puts("Error: relay address is not set");
+ return;
+ }
+
+ len = strlen(g.data);
+ if (len==0) {
+ puts("Error: data is not set");
+ return;
+ }
+
+ len = strlen(g.data);
+ pj_sock_sendto(g.sock, g.data, &len, 0, &g.relay_addr, sizeof(g.relay_addr));
}
-static void send_raw_data(void)
+static pj_status_t parse_addr(const char *input,
+ pj_sockaddr_in *addr)
{
+ const char *pos;
+ pj_str_t ip;
+ pj_uint16_t port;
+ pj_sockaddr_in tmp_addr;
+
+ pos = pj_ansi_strchr(input, ':');
+ if (pos==NULL) {
+ puts("Invalid format");
+ return -1;
+ }
+
+ ip.ptr = (char*)input;
+ ip.slen = pos - input;
+ port = (pj_uint16_t)atoi(pos+1);
+
+ if (port==0) {
+ puts("Invalid port");
+ return -1;
+ }
+
+ if (pj_sockaddr_in_init(&tmp_addr, &ip, port)!=PJ_SUCCESS) {
+ puts("Invalid address");
+ return -1;
+ }
+
+ pj_memcpy(addr, &tmp_addr, sizeof(tmp_addr));
+
+ return PJ_SUCCESS;
}
static void set_peer_addr(void)
{
- char ip_addr[64];
- pj_str_t tmp;
- pj_sockaddr_in addr;
- int port;
+ char addr[64];
printf("Current peer address: %s:%d\n",
pj_inet_ntoa(g.peer_addr.sin_addr),
@@ -356,18 +508,12 @@ static void set_peer_addr(void)
printf("Input peer address in IP:PORT format: ");
fflush(stdout);
+ gets(addr);
- if (scanf("%s:%d", ip_addr, &port) != 2) {
- puts("Error.");
+ if (parse_addr(addr, &g.peer_addr) != PJ_SUCCESS) {
return;
}
- if (pj_sockaddr_in_init(&addr, pj_cstr(&tmp,ip_addr), (pj_uint16_t)port) != PJ_SUCCESS) {
- puts("Error: invalid address");
- return;
- }
-
- g.peer_addr = addr;
}
static void menu(void)
@@ -375,14 +521,15 @@ static void menu(void)
puts("Menu:");
printf(" pr Set peer address (currently %s:%d)\n",
pj_inet_ntoa(g.peer_addr.sin_addr), pj_ntohs(g.peer_addr.sin_port));
- puts("");
+ printf(" dt Set data (currently \"%s\")\n", g.data);
puts(" br Send Bind request");
puts(" ar Send Allocate request");
puts(" dr Send de-Allocate request");
- puts(" sr Send Set Active Indication request");
- puts(" cr Send clear Active Indication request");
+ puts(" sr Send Set Active Destination request");
+ puts(" cr Send clear Active Destination request");
puts(" si Send data with Send Indication");
- puts(" rw Send raw data");
+ puts(" rw Send raw data to TURN server");
+ puts(" rW Send raw data to relay address");
puts(" q Quit");
puts("");
printf("Choice: ");
@@ -398,7 +545,16 @@ static void console_main(void)
fgets(input, sizeof(input), stdin);
- if (input[0]=='b' && input[1]=='r') {
+ if (0) {
+
+ } else if (input[0]=='d' && input[1]=='t') {
+ printf("Input data: ");
+ gets(g.data);
+
+ } else if (input[0]=='p' && input[1]=='r') {
+ set_peer_addr();
+
+ } else if (input[0]=='b' && input[1]=='r') {
send_bind_request();
} else if (input[0]=='a' && input[1]=='r') {
@@ -417,10 +573,10 @@ static void console_main(void)
send_send_ind();
} else if (input[0]=='r' && input[1]=='w') {
- send_raw_data();
+ send_raw_data_to_srv();
- } else if (input[0]=='p' && input[1]=='r') {
- set_peer_addr();
+ } else if (input[0]=='r' && input[1]=='W') {
+ send_raw_data_to_relay();
} else if (input[0]=='q') {
g.quit = 1;
@@ -441,6 +597,8 @@ static void usage(void)
puts(" --password, -p Set password of the credential");
puts(" --nonce, -N Set NONCE");
puts(" --fingerprint, -F Use fingerprint for outgoing requests");
+ puts(" --peer, -P Set peer address (address is in HOST:PORT format)");
+ puts(" --data, -D Set data");
puts(" --help, -h");
}
@@ -452,12 +610,16 @@ int main(int argc, char *argv[])
{ "password", 1, 0, 'p'},
{ "nonce", 1, 0, 'N'},
{ "fingerprint",0, 0, 'F'},
+ { "peer", 1, 0, 'P'},
+ { "data", 1, 0, 'D'},
{ "help", 0, 0, 'h'}
};
int c, opt_id;
char *pos;
pj_status_t status;
+ g.data = g.data_buf;
+
while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
switch (c) {
case 'r':
@@ -478,6 +640,13 @@ int main(int argc, char *argv[])
case 'F':
o.use_fingerprint = PJ_TRUE;
break;
+ case 'P':
+ o.peer_addr = pj_optarg;
+ break;
+ case 'D':
+ g.data = pj_optarg;
+ break;
+
default:
printf("Argument \"%s\" is not valid. Use -h to see help",
argv[pj_optind]);
diff --git a/pjlib-util/src/pjstun-srv-test/bind_usage.c b/pjlib-util/src/pjstun-srv-test/bind_usage.c
index b49441c6..fc10fb91 100644
--- a/pjlib-util/src/pjstun-srv-test/bind_usage.c
+++ b/pjlib-util/src/pjstun-srv-test/bind_usage.c
@@ -162,10 +162,10 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
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);
+ status = pj_stun_msg_add_sockaddr_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);
@@ -175,10 +175,10 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
/* 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_ADDR,
- PJ_TRUE,
- src_addr, src_addr_len);
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+ 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);
diff --git a/pjlib-util/src/pjstun-srv-test/main.c b/pjlib-util/src/pjstun-srv-test/main.c
index 13d64bca..c462d47e 100644
--- a/pjlib-util/src/pjstun-srv-test/main.c
+++ b/pjlib-util/src/pjstun-srv-test/main.c
@@ -122,11 +122,20 @@ int main(int argc, char *argv[])
return 1;
}
+ /*
status = pj_stun_bind_usage_create(srv, NULL, 3478, NULL);
if (status != PJ_SUCCESS) {
pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
return 1;
}
+ */
+
+ status = pj_stun_turn_usage_create(srv, PJ_SOCK_DGRAM, NULL,
+ 3478, NULL);
+ if (status != PJ_SUCCESS) {
+ pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
+ return 1;
+ }
server_main(srv);
diff --git a/pjlib-util/src/pjstun-srv-test/server.h b/pjlib-util/src/pjstun-srv-test/server.h
index 491a1af3..a88d87c2 100644
--- a/pjlib-util/src/pjstun-srv-test/server.h
+++ b/pjlib-util/src/pjstun-srv-test/server.h
@@ -112,11 +112,16 @@ PJ_DECL(pj_status_t) pj_stun_usage_sendto(pj_stun_usage *usage,
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);
-
+PJ_DECL(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_DECL(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
+ int type,
+ const pj_str_t *ip_addr,
+ unsigned port,
+ pj_stun_usage **p_bu);
pj_status_t pj_stun_server_register_usage(pj_stun_server *srv,
diff --git a/pjlib-util/src/pjstun-srv-test/turn_usage.c b/pjlib-util/src/pjstun-srv-test/turn_usage.c
index f82d5149..e3d2e595 100644
--- a/pjlib-util/src/pjstun-srv-test/turn_usage.c
+++ b/pjlib-util/src/pjstun-srv-test/turn_usage.c
@@ -49,6 +49,11 @@ static pj_status_t tu_sess_on_rx_request(pj_stun_session *sess,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len);
+static pj_status_t handle_binding_req(pj_stun_session *session,
+ const pj_stun_msg *msg,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
+
static pj_status_t client_create(struct turn_usage *tu,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len,
@@ -90,11 +95,13 @@ struct turn_client
pj_stun_session *session;
pj_mutex_t *mutex;
+ pj_sockaddr_in client_src_addr;
+
/* Socket and socket address of the allocated port */
int sock_type;
pj_sock_t sock;
pj_ioqueue_key_t *key;
- pj_sockaddr_in client_addr;
+ pj_sockaddr_in alloc_addr;
/* Allocation properties */
unsigned bw_kbps;
@@ -149,8 +156,8 @@ PJ_DEF(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
pj_sockaddr_in local_addr;
pj_status_t status;
- PJ_ASSERT_RETURN(srv && (type==PJ_SOCK_DGRAM||type==PJ_SOCK_STREAM) &&
- p_bu, PJ_EINVAL);
+ PJ_ASSERT_RETURN(srv && (type==PJ_SOCK_DGRAM||type==PJ_SOCK_STREAM),
+ PJ_EINVAL);
si = pj_stun_server_get_info(srv);
pool = pj_pool_create(si->pf, "turn%p", 4000, 4000, NULL);
@@ -159,8 +166,11 @@ PJ_DEF(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
tu->type = type;
tu->pf = si->pf;
tu->endpt = si->endpt;
+ tu->ioqueue = si->ioqueue;
tu->timer_heap = si->timer_heap;
tu->next_port = START_PORT;
+ tu->max_bw_kbps = 64;
+ tu->max_lifetime = 10 * 60;
status = pj_sockaddr_in_init(&local_addr, ip_addr, (pj_uint16_t)port);
if (status != PJ_SUCCESS)
@@ -205,7 +215,9 @@ PJ_DEF(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
return status;
}
- *p_bu = tu->usage;
+ if (p_bu) {
+ *p_bu = tu->usage;
+ }
return PJ_SUCCESS;
}
@@ -223,14 +235,16 @@ static void tu_on_destroy(pj_stun_usage *usage)
tu = (struct turn_usage*) pj_stun_usage_get_user_data(usage);
/* Destroy all clients */
- it = pj_hash_first(tu->client_htable, &hit);
- while (it) {
- struct turn_client *client;
+ if (tu->client_htable) {
+ it = pj_hash_first(tu->client_htable, &hit);
+ while (it) {
+ struct turn_client *client;
- client = (struct turn_client *)pj_hash_this(tu->client_htable, it);
- client_destroy(client, PJ_SUCCESS);
+ client = (struct turn_client *)pj_hash_this(tu->client_htable, it);
+ client_destroy(client, PJ_SUCCESS);
- it = pj_hash_next(tu->client_htable, it);
+ it = pj_hash_first(tu->client_htable, &hit);
+ }
}
pj_stun_session_destroy(tu->default_session);
@@ -391,6 +405,7 @@ static pj_status_t tu_alloc_port(struct turn_usage *tu,
return status;
}
+ *p_sock = sock;
return PJ_SUCCESS;
}
}
@@ -419,7 +434,10 @@ static pj_status_t tu_sess_on_rx_request(pj_stun_session *sess,
pj_assert(sd->client == NULL);
- if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
+ if (msg->hdr.type == PJ_STUN_BINDING_REQUEST) {
+ return handle_binding_req(sess, msg, src_addr, src_addr_len);
+
+ } else if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
status = pj_stun_session_create_response(sess, msg,
PJ_STUN_SC_NO_BINDING,
@@ -505,9 +523,9 @@ static struct peer* client_add_peer(struct turn_client *client,
static const char *get_tp_type(int type)
{
- if (type==0)
+ if (type==PJ_SOCK_DGRAM)
return "udp";
- else if (type==1)
+ else if (type==PJ_SOCK_STREAM)
return "tcp";
else
return "???";
@@ -519,12 +537,12 @@ static const char *get_tp_type(int type)
* in the TURN usage. This is called from by tu_on_rx_data() when
* the packet is handed over to the client.
*/
-static pj_status_t client_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)
+static pj_status_t client_sess_on_rx_msg(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 session_data *sd;
@@ -576,12 +594,17 @@ static pj_status_t client_create(struct turn_usage *tu,
struct session_data *sd;
pj_status_t status;
+ PJ_ASSERT_RETURN(src_addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
+
pool = pj_pool_create(tu->pf, "turnc%p", 4000, 4000, NULL);
client = PJ_POOL_ZALLOC_T(pool, struct turn_client);
client->pool = pool;
client->tu = tu;
client->sock = PJ_INVALID_SOCKET;
+ pj_memcpy(&client->client_src_addr, src_addr,
+ sizeof(client->client_src_addr));
+
if (src_addr) {
const pj_sockaddr_in *a4 = (const pj_sockaddr_in *)src_addr;
pj_ansi_snprintf(client->obj_name, sizeof(client->obj_name),
@@ -595,7 +618,8 @@ static pj_status_t client_create(struct turn_usage *tu,
/* Create session */
pj_bzero(&sess_cb, sizeof(sess_cb));
sess_cb.on_send_msg = &client_sess_on_send_msg;
- sess_cb.on_rx_request = &client_sess_on_rx_request;
+ sess_cb.on_rx_request = &client_sess_on_rx_msg;
+ sess_cb.on_rx_indication = &client_sess_on_rx_msg;
status = pj_stun_session_create(tu->endpt, client->obj_name,
&sess_cb, PJ_FALSE,
&client->session);
@@ -667,7 +691,8 @@ static pj_status_t client_destroy(struct turn_client *client,
/* Unregister client from hash table */
pj_mutex_lock(tu->mutex);
pj_hash_set(NULL, tu->client_htable,
- &client->client_addr, sizeof(client->client_addr), 0, NULL);
+ &client->client_src_addr, sizeof(client->client_src_addr),
+ 0, NULL);
pj_mutex_unlock(tu->mutex);
/* Destroy STUN session */
@@ -709,7 +734,7 @@ static pj_status_t client_create_relay(struct turn_client *client)
/* Update address */
addrlen = sizeof(pj_sockaddr_in);
- status = pj_sock_getsockname(client->sock, &client->client_addr,
+ status = pj_sock_getsockname(client->sock, &client->alloc_addr,
&addrlen);
if (status != PJ_SUCCESS) {
pj_sock_close(client->sock);
@@ -717,6 +742,15 @@ static pj_status_t client_create_relay(struct turn_client *client)
return status;
}
+ if (client->alloc_addr.sin_addr.s_addr == 0) {
+ status = pj_gethostip(&client->alloc_addr.sin_addr);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(client->sock);
+ client->sock = PJ_INVALID_SOCKET;
+ return status;
+ }
+ }
+
/* Register to ioqueue */
pj_bzero(&client_ioq_cb, sizeof(client_ioq_cb));
client_ioq_cb.on_read_complete = &client_on_read_complete;
@@ -740,8 +774,8 @@ static pj_status_t client_create_relay(struct turn_client *client)
PJ_LOG(4,(THIS_FILE, "TURN client %s: relay allocated on %s:%s:%d",
client->obj_name,
get_tp_type(client->sock_type),
- pj_inet_ntoa(client->client_addr.sin_addr),
- (int)pj_ntohs(client->client_addr.sin_port)));
+ pj_inet_ntoa(client->alloc_addr.sin_addr),
+ (int)pj_ntohs(client->alloc_addr.sin_port)));
return PJ_SUCCESS;
}
@@ -766,8 +800,8 @@ static pj_status_t client_destroy_relay(struct turn_client *client)
PJ_LOG(4,(THIS_FILE, "TURN client %s: relay allocation %s:%s:%d destroyed",
client->obj_name,
get_tp_type(client->sock_type),
- pj_inet_ntoa(client->client_addr.sin_addr),
- (int)pj_ntohs(client->client_addr.sin_port)));
+ pj_inet_ntoa(client->alloc_addr.sin_addr),
+ (int)pj_ntohs(client->alloc_addr.sin_port)));
return PJ_SUCCESS;
}
@@ -795,15 +829,15 @@ static struct peer* client_add_peer(struct turn_client *client,
peer = PJ_POOL_ZALLOC_T(client->pool, struct peer);
peer->client = client;
- pj_memcpy(&peer->addr, peer_addr, sizeof(*peer_addr));
+ pj_memcpy(&peer->addr, peer_addr, sizeof(peer->addr));
pj_hash_set(client->pool, client->peer_htable,
- peer_addr, sizeof(*peer_addr), hval, peer);
+ &peer->addr, sizeof(peer->addr), hval, peer);
PJ_LOG(4,(THIS_FILE, "TURN client %s: peer %s:%s:%d added",
client->obj_name, get_tp_type(client->sock_type),
- pj_inet_ntoa(peer_addr->sin_addr),
- (int)pj_ntohs(peer_addr->sin_port)));
+ pj_inet_ntoa(peer->addr.sin_addr),
+ (int)pj_ntohs(peer->addr.sin_port)));
return peer;
}
@@ -975,7 +1009,7 @@ static pj_status_t client_handle_allocate_req(struct turn_client *client,
timeout.sec = client->lifetime;
timeout.msec = 0;
pj_timer_heap_schedule(client->tu->timer_heap, &client->expiry_timer, &timeout);
-
+ client->expiry_timer.id = PJ_TRUE;
/* Done successfully, create and send success response */
status = pj_stun_session_create_response(client->session, msg,
@@ -988,18 +1022,18 @@ static pj_status_t client_handle_allocate_req(struct turn_client *client,
PJ_STUN_ATTR_BANDWIDTH, client->bw_kbps);
pj_stun_msg_add_uint_attr(response->pool, response->msg,
PJ_STUN_ATTR_LIFETIME, client->lifetime);
- pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+ pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_MAPPED_ADDR, PJ_FALSE,
src_addr, src_addr_len);
- pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+ pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
src_addr, src_addr_len);
addr_len = sizeof(req_addr);
pj_sock_getsockname(client->sock, &req_addr, &addr_len);
- pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+ pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_RELAY_ADDR, PJ_FALSE,
- &req_addr, addr_len);
+ &client->alloc_addr, addr_len);
PJ_LOG(4,(THIS_FILE, "TURN client %s: relay allocated or refreshed, "
"internal address is %s:%s:%d",
@@ -1013,6 +1047,46 @@ static pj_status_t client_handle_allocate_req(struct turn_client *client,
}
+/*
+ * Handle incoming Binding request.
+ * This function is called by client_handle_stun_msg() below.
+ */
+static pj_status_t handle_binding_req(pj_stun_session *session,
+ 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(session, msg, 0, NULL,
+ &tdata);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Create MAPPED-ADDRESS attribute */
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_MAPPED_ADDR,
+ PJ_FALSE,
+ src_addr, src_addr_len);
+
+ /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
+ if (msg->hdr.magic == PJ_STUN_MAGIC) {
+ status =
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+ PJ_TRUE,
+ src_addr, src_addr_len);
+ }
+
+ /* Send */
+ status = pj_stun_session_send_msg(session, PJ_TRUE,
+ src_addr, src_addr_len, tdata);
+ return status;
+}
+
+
/*
* client handling incoming STUN Set Active Destination request
* This function is called by client_handle_stun_msg() below.
@@ -1058,10 +1132,16 @@ static pj_status_t client_handle_sad(struct turn_client *client,
client->active_peer = peer;
}
- PJ_LOG(4,(THIS_FILE, "TURN client %s: active destination set to %s:%d",
- client->obj_name,
- pj_inet_ntoa(client->active_peer->addr.sin_addr),
- (int)pj_ntohs(client->active_peer->addr.sin_port)));
+ if (client->active_peer) {
+ PJ_LOG(4,(THIS_FILE,
+ "TURN client %s: active destination set to %s:%d",
+ client->obj_name,
+ pj_inet_ntoa(client->active_peer->addr.sin_addr),
+ (int)pj_ntohs(client->active_peer->addr.sin_port)));
+ } else {
+ PJ_LOG(4,(THIS_FILE, "TURN client %s: active destination cleared",
+ client->obj_name));
+ }
/* Respond with successful response */
client_respond(client, msg, 0, NULL, src_addr, src_addr_len);
@@ -1162,17 +1242,27 @@ static pj_status_t client_handle_stun_msg(struct turn_client *client,
switch (msg->hdr.type) {
case PJ_STUN_SEND_INDICATION:
status = client_handle_send_ind(client, msg);
+ break;
case PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST:
status = client_handle_sad(client, msg,
src_addr, src_addr_len);
+ break;
+
case PJ_STUN_ALLOCATE_REQUEST:
status = client_handle_allocate_req(client, msg,
src_addr, src_addr_len);
+ break;
+
+ case PJ_STUN_BINDING_REQUEST:
+ status = handle_binding_req(client->session, msg,
+ src_addr, src_addr_len);
+ break;
default:
status = client_handle_unknown_msg(client, msg,
src_addr, src_addr_len);
+ break;
}
return status;
@@ -1203,6 +1293,11 @@ static void client_handle_peer_data(struct turn_client *client,
peer = client_get_peer(client, &client->pkt_src_addr, NULL);
if (peer == NULL) {
/* Nope. Discard packet */
+ PJ_LOG(5,(THIS_FILE,
+ "TURN client %s: discarded data from %s:%d",
+ client->obj_name,
+ pj_inet_ntoa(client->pkt_src_addr.sin_addr),
+ (int)pj_ntohs(client->pkt_src_addr.sin_port)));
return;
}
@@ -1225,10 +1320,10 @@ static void client_handle_peer_data(struct turn_client *client,
if (status != PJ_SUCCESS)
return;
- pj_stun_msg_add_ip_addr_attr(data_ind->pool, data_ind->msg,
- PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
- &client->pkt_src_addr,
- client->pkt_src_addr_len);
+ pj_stun_msg_add_sockaddr_attr(data_ind->pool, data_ind->msg,
+ PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
+ &client->pkt_src_addr,
+ client->pkt_src_addr_len);
pj_stun_msg_add_binary_attr(data_ind->pool, data_ind->msg,
PJ_STUN_ATTR_DATA,
client->pkt, bytes_read);
diff --git a/pjlib-util/src/pjstun-srv-test/usage.c b/pjlib-util/src/pjstun-srv-test/usage.c
index 198e0313..a8a5c274 100644
--- a/pjlib-util/src/pjstun-srv-test/usage.c
+++ b/pjlib-util/src/pjstun-srv-test/usage.c
@@ -82,8 +82,6 @@ PJ_DEF(pj_status_t) pj_stun_usage_create( pj_stun_server *srv,
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)
@@ -133,6 +131,12 @@ PJ_DEF(pj_status_t) pj_stun_usage_create( pj_stun_server *srv,
pj_stun_server_register_usage(srv, usage);
+ /* Only after everything has been initialized we copy the callback,
+ * to prevent callback from being called when we encounter error
+ * during initialiation (decendant would not expect this).
+ */
+ pj_memcpy(&usage->cb, cb, sizeof(*cb));
+
*p_usage = usage;
return PJ_SUCCESS;
diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h
index da768519..ed1805d7 100644
--- a/pjlib/include/pj/hash.h
+++ b/pjlib/include/pj/hash.h
@@ -119,7 +119,8 @@ PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
* @param pool the pool to allocate the new entry if a new entry has to be
* created.
* @param ht the hash table.
- * @param key the key.
+ * @param key the key, which MUST point to buffer that remains valid
+ * for the duration of the entry.
* @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
* string length of the key.
* @param hval if the value is not zero, then the hash table will use
diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c
index 04c0152b..9e64378b 100644
--- a/pjlib/src/pj/addr_resolv_sock.c
+++ b/pjlib/src/pj/addr_resolv_sock.c
@@ -55,7 +55,7 @@ PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
}
/* Resolve the IP address of local machine */
-pj_status_t pj_gethostip(pj_in_addr *addr)
+PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr)
{
const pj_str_t *hostname = pj_gethostname();
struct pj_hostent he;