diff options
Diffstat (limited to 'pjlib-util')
-rw-r--r-- | pjlib-util/include/pjlib-util/stun_msg.h | 46 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_msg.c | 200 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_msg_dump.c | 4 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-client/client_main.c | 229 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/bind_usage.c | 16 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/main.c | 9 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/server.h | 15 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/turn_usage.c | 181 | ||||
-rw-r--r-- | pjlib-util/src/pjstun-srv-test/usage.c | 8 |
9 files changed, 524 insertions, 184 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; |