Compare commits
4 Commits
master
...
ice-turn07
Author | SHA1 | Date |
---|---|---|
|
20d443d87b | |
|
eb7693143c | |
|
b3535a4eb2 | |
|
540f7b7842 |
|
@ -776,9 +776,22 @@ PJ_DECL(unsigned) pj_sockaddr_get_len(const pj_sockaddr_t *addr);
|
|||
*
|
||||
* @param dst Destination socket address.
|
||||
* @param src Source socket address.
|
||||
*
|
||||
* @see @pj_sockaddr_cp()
|
||||
*/
|
||||
PJ_DECL(void) pj_sockaddr_copy_addr(pj_sockaddr *dst,
|
||||
const pj_sockaddr *src);
|
||||
/**
|
||||
* Copy socket address. This will copy the whole structure depending
|
||||
* on the address family of the source socket address.
|
||||
*
|
||||
* @param dst Destination socket address.
|
||||
* @param src Source socket address.
|
||||
*
|
||||
* @see @pj_sockaddr_copy_addr()
|
||||
*/
|
||||
PJ_DECL(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src);
|
||||
|
||||
/**
|
||||
* Get the IP address of an IPv4 socket address.
|
||||
* The address is returned as 32bit value in host byte order.
|
||||
|
|
|
@ -389,6 +389,14 @@ PJ_DEF(void) pj_sockaddr_copy_addr( pj_sockaddr *dst,
|
|||
pj_sockaddr_get_addr_len(src));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy socket address.
|
||||
*/
|
||||
PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
|
||||
{
|
||||
pj_memcpy(dst, src, pj_sockaddr_get_len(src));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set port number of pj_sockaddr_in
|
||||
*/
|
||||
|
|
|
@ -62,7 +62,7 @@ typedef struct pjmedia_ice_cb
|
|||
* @param name Optional name to identify this ICE media transport
|
||||
* for logging purposes.
|
||||
* @param comp_cnt Number of components to be created.
|
||||
* @param stun_cfg Pointer to STUN configuration settings.
|
||||
* @param cfg Pointer to configuration settings.
|
||||
* @param cb Optional callbacks.
|
||||
* @param p_tp Pointer to receive the media transport instance.
|
||||
*
|
||||
|
@ -71,7 +71,7 @@ typedef struct pjmedia_ice_cb
|
|||
PJ_DECL(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
|
||||
const char *name,
|
||||
unsigned comp_cnt,
|
||||
pj_stun_config *stun_cfg,
|
||||
const pj_ice_strans_cfg *cfg,
|
||||
const pjmedia_ice_cb *cb,
|
||||
pjmedia_transport **p_tp);
|
||||
|
||||
|
@ -104,19 +104,13 @@ PJ_DECL(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
|
|||
* socket to this particular interface only, and
|
||||
* no other host candidates will be added for this
|
||||
* socket.
|
||||
* @param stun_srv Address of the STUN server, or NULL if STUN server
|
||||
* reflexive mapping is not to be used.
|
||||
* @param turn_srv Address of the TURN server, or NULL if TURN relay
|
||||
* is not to be used.
|
||||
*
|
||||
* @return PJ_SUCCESS when the initialization process has started
|
||||
* successfully, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_ice_start_init(pjmedia_transport *tp,
|
||||
unsigned options,
|
||||
const pj_sockaddr_in *start_addr,
|
||||
const pj_sockaddr_in *stun_srv,
|
||||
const pj_sockaddr_in *turn_srv);
|
||||
const pj_sockaddr_in *start_addr);
|
||||
|
||||
/**
|
||||
* Poll the initialization status of this media transport.
|
||||
|
|
|
@ -128,7 +128,7 @@ static const pj_str_t STR_ICE_MISMATCH = {"ice-mismatch", 12};
|
|||
PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
|
||||
const char *name,
|
||||
unsigned comp_cnt,
|
||||
pj_stun_config *stun_cfg,
|
||||
const pj_ice_strans_cfg *cfg,
|
||||
const pjmedia_ice_cb *cb,
|
||||
pjmedia_transport **p_tp)
|
||||
{
|
||||
|
@ -145,8 +145,8 @@ PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
|
|||
ice_st_cb.on_rx_data = &ice_on_rx_data;
|
||||
|
||||
/* Create ICE */
|
||||
status = pj_ice_strans_create(stun_cfg, name, comp_cnt, NULL,
|
||||
&ice_st_cb, &ice_st);
|
||||
status = pj_ice_strans_create(cfg, name, comp_cnt, NULL,
|
||||
&ice_st_cb, &ice_st);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
@ -176,17 +176,11 @@ PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_ice_start_init( pjmedia_transport *tp,
|
||||
unsigned options,
|
||||
const pj_sockaddr_in *start_addr,
|
||||
const pj_sockaddr_in *stun_srv,
|
||||
const pj_sockaddr_in *turn_srv)
|
||||
const pj_sockaddr_in *start_addr)
|
||||
{
|
||||
struct transport_ice *tp_ice = (struct transport_ice*)tp;
|
||||
pj_status_t status;
|
||||
|
||||
status = pj_ice_strans_set_stun_srv(tp_ice->ice_st, stun_srv, turn_srv);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pj_ice_strans_create_comp(tp_ice->ice_st, 1, options, start_addr);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
@ -349,7 +343,7 @@ static pj_status_t transport_media_create(pjmedia_transport *tp,
|
|||
case PJ_ICE_CAND_TYPE_RELAYED:
|
||||
PJ_TODO(RELATED_ADDR_FOR_RELAYED_ADDR);
|
||||
len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
|
||||
"srflx raddr %s rport %d",
|
||||
"relay raddr %s rport %d",
|
||||
pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
|
||||
(int)pj_ntohs(cand->base_addr.ipv4.sin_port));
|
||||
break;
|
||||
|
|
|
@ -430,12 +430,14 @@ typedef struct pj_ice_sess_cb
|
|||
*
|
||||
* @param ice The ICE session.
|
||||
* @param comp_id ICE component ID.
|
||||
* @param cand_id ICE candidate ID.
|
||||
* @param pkt The STUN packet.
|
||||
* @param size The size of the packet.
|
||||
* @param dst_addr Packet destination address.
|
||||
* @param dst_addr_len Length of destination address.
|
||||
*/
|
||||
pj_status_t (*on_tx_pkt)(pj_ice_sess *ice, unsigned comp_id,
|
||||
unsigned cand_id,
|
||||
const void *pkt, pj_size_t size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned dst_addr_len);
|
||||
|
@ -797,6 +799,14 @@ PJ_DECL(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
*
|
||||
* @param ice The ICE session.
|
||||
* @param comp_id Component ID.
|
||||
* @param cand_id The candidate ID where this packet was received
|
||||
* from. This parameter will be returned back to
|
||||
* application in \a on_tx_pkt() callback, and
|
||||
* application may use it to determine whether to
|
||||
* send outgoing packet using local socket or with
|
||||
* the TURN relay. The ICE session will not use
|
||||
* this information to determine the local candidate
|
||||
* for this packet.
|
||||
* @param pkt Incoming packet.
|
||||
* @param pkt_size Size of incoming packet.
|
||||
* @param src_addr Source address of the packet.
|
||||
|
@ -806,6 +816,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned cand_id,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
* @brief ICE Stream Transport
|
||||
*/
|
||||
#include <pjnath/ice_session.h>
|
||||
#include <pjnath/turn_sock.h>
|
||||
#include <pjlib-util/resolver.h>
|
||||
#include <pj/ioqueue.h>
|
||||
#include <pj/timer.h>
|
||||
|
@ -91,11 +92,6 @@ PJ_BEGIN_DECL
|
|||
* \a on_ice_complete() to notify application that ICE negotiation
|
||||
* has completed, either successfully or with failure.
|
||||
*
|
||||
* After the ICE stream transport is created, application may set up the
|
||||
* STUN servers to be used to obtain STUN server reflexive and relayed
|
||||
* candidate, by calling #pj_ice_strans_set_stun_domain() or
|
||||
* #pj_ice_strans_set_stun_srv().
|
||||
*
|
||||
* Application then creates each component by calling
|
||||
* #pj_ice_strans_create_comp(); this would create an actual socket
|
||||
* which listens to the specified local address, and it would also
|
||||
|
@ -335,6 +331,8 @@ typedef struct pj_ice_strans_comp
|
|||
pj_stun_session *stun_sess; /**< STUN session. */
|
||||
pj_uint8_t ka_tsx_id[12]; /**< ID for keep STUN alives */
|
||||
|
||||
pj_turn_sock *turn_relay; /**< TURN relay object. */
|
||||
|
||||
pj_sockaddr local_addr; /**< Local/base address. */
|
||||
|
||||
unsigned pending_cnt; /**< Pending resolution cnt. */
|
||||
|
@ -354,6 +352,54 @@ typedef struct pj_ice_strans_comp
|
|||
} pj_ice_strans_comp;
|
||||
|
||||
|
||||
/**
|
||||
* This structure describes ICE stream transport configuration.
|
||||
*/
|
||||
typedef struct pj_ice_strans_cfg
|
||||
{
|
||||
/**
|
||||
* STUN config. This setting is mandatory.
|
||||
*/
|
||||
pj_stun_config stun_cfg;
|
||||
|
||||
/**
|
||||
* STUN server address, if STUN is enabled.
|
||||
*
|
||||
* Default is to have no TURN server.
|
||||
*/
|
||||
pj_sockaddr stun_srv;
|
||||
|
||||
/**
|
||||
* TURN server address, if TURN is enabled.
|
||||
*
|
||||
* Default is to have no TURN server.
|
||||
*/
|
||||
pj_sockaddr turn_srv;
|
||||
|
||||
/**
|
||||
* Type of connection to the TURN server.
|
||||
*
|
||||
* Default is PJ_TURN_TP_UDP.
|
||||
*/
|
||||
pj_turn_tp_type turn_conn_type;
|
||||
|
||||
/**
|
||||
* Credential to be used for the TURN session.
|
||||
*
|
||||
* Default is to have no credential.
|
||||
*/
|
||||
pj_stun_auth_cred turn_cred;
|
||||
|
||||
/**
|
||||
* Optional TURN Allocate parameter.
|
||||
*
|
||||
* Default is all empty.
|
||||
*/
|
||||
pj_turn_alloc_param turn_alloc_param;
|
||||
|
||||
} pj_ice_strans_cfg;
|
||||
|
||||
|
||||
/**
|
||||
* This structure represents the ICE stream transport.
|
||||
*/
|
||||
|
@ -363,7 +409,7 @@ struct pj_ice_strans
|
|||
|
||||
pj_pool_t *pool; /**< Pool used by this object. */
|
||||
void *user_data; /**< Application data. */
|
||||
pj_stun_config stun_cfg; /**< STUN settings. */
|
||||
pj_ice_strans_cfg cfg; /**< Configuration. */
|
||||
pj_ice_strans_cb cb; /**< Application callback. */
|
||||
|
||||
pj_ice_sess *ice; /**< ICE session. */
|
||||
|
@ -371,11 +417,6 @@ struct pj_ice_strans
|
|||
unsigned comp_cnt; /**< Number of components. */
|
||||
pj_ice_strans_comp **comp; /**< Components array. */
|
||||
|
||||
pj_dns_resolver *resolver; /**< The resolver instance. */
|
||||
pj_bool_t has_rjob; /**< Has pending resolve? */
|
||||
pj_sockaddr_in stun_srv; /**< STUN server address. */
|
||||
pj_sockaddr_in turn_srv; /**< TURN server address. */
|
||||
|
||||
pj_timer_entry ka_timer; /**< STUN keep-alive timer. */
|
||||
};
|
||||
|
||||
|
@ -387,7 +428,7 @@ struct pj_ice_strans
|
|||
* initialize each components by calling #pj_ice_strans_create_comp()
|
||||
* function.
|
||||
*
|
||||
* @param stun_cfg The STUN settings.
|
||||
* @param cfg Configuration.
|
||||
* @param name Optional name for logging identification.
|
||||
* @param comp_cnt Number of components.
|
||||
* @param user_data Arbitrary user data to be associated with this
|
||||
|
@ -399,7 +440,7 @@ struct pj_ice_strans
|
|||
* @return PJ_SUCCESS if ICE stream transport is created
|
||||
* successfully.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_create(pj_stun_config *stun_cfg,
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_create(const pj_ice_strans_cfg *cfg,
|
||||
const char *name,
|
||||
unsigned comp_cnt,
|
||||
void *user_data,
|
||||
|
@ -417,50 +458,6 @@ PJ_DECL(pj_status_t) pj_ice_strans_create(pj_stun_config *stun_cfg,
|
|||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st);
|
||||
|
||||
|
||||
/**
|
||||
* Set the domain to be used when resolving the STUN servers. If application
|
||||
* wants to utillize STUN, then STUN server must be specified, either by
|
||||
* calling this function or by calling #pj_ice_strans_set_stun_srv().
|
||||
*
|
||||
* If application calls this function, then the STUN/TURN servers will
|
||||
* be resolved by querying DNS SRV records for the specified domain.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param resolver The resolver instance that will be used to
|
||||
* resolve the STUN/TURN servers.
|
||||
* @param domain The target domain.
|
||||
*
|
||||
* @return PJ_SUCCESS if DNS SRV resolution job can be
|
||||
* started. The resolution process itself will
|
||||
* complete asynchronously.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_ice_strans_set_stun_domain(pj_ice_strans *ice_st,
|
||||
pj_dns_resolver *resolver,
|
||||
const pj_str_t *domain);
|
||||
|
||||
/**
|
||||
* Set the STUN and TURN server addresses. If application
|
||||
* wants to utillize STUN, then STUN server must be specified, either by
|
||||
* calling this function or by calling #pj_ice_strans_set_stun_domain().
|
||||
*
|
||||
* With this function, the STUN and TURN server addresses will be
|
||||
* assigned immediately, that is no DNS resolution will need to be
|
||||
* performed.
|
||||
*
|
||||
* @param ice_st The ICE stream transport.
|
||||
* @param stun_srv The STUN server address, or NULL if STUN
|
||||
* reflexive candidate is not to be used.
|
||||
* @param turn_srv The TURN server address, or NULL if STUN
|
||||
* relay candidate is not to be used.
|
||||
*
|
||||
* @return PJ_SUCCESS, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st,
|
||||
const pj_sockaddr_in *stun_srv,
|
||||
const pj_sockaddr_in *turn_srv);
|
||||
|
||||
/**
|
||||
* Create and initialize the specified component. This function will
|
||||
* instantiate the socket descriptor for this component, optionally
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
*/
|
||||
|
||||
#include <pjnath/stun_msg.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/errno.h>
|
||||
#include <pj/string.h>
|
||||
|
||||
|
||||
|
@ -102,6 +104,17 @@ PJ_INLINE(void) pj_stun_config_init(pj_stun_config *cfg,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that STUN config is valid.
|
||||
*/
|
||||
PJ_INLINE(pj_status_t) pj_stun_config_check_valid(const pj_stun_config *cfg)
|
||||
{
|
||||
PJ_ASSERT_RETURN(cfg->ioqueue && cfg->pf && cfg->timer_heap &&
|
||||
cfg->rto_msec && cfg->res_cache_msec, PJ_EINVAL);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -176,7 +176,7 @@ typedef struct pj_turn_session_cb
|
|||
* This callback is optional.
|
||||
*/
|
||||
void (*on_rx_data)(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
@ -257,7 +257,7 @@ PJ_DECL(const char*) pj_turn_state_name(pj_turn_state_t state);
|
|||
/**
|
||||
* Create TURN client session.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_create(pj_stun_config *cfg,
|
||||
PJ_DECL(pj_status_t) pj_turn_session_create(const pj_stun_config *cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
pj_turn_tp_type conn_type,
|
||||
|
@ -340,7 +340,7 @@ PJ_DECL(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
|
|||
* The packet maybe a STUN packet or ChannelData packet.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
pj_bool_t is_datagram);
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __PJNATH_turn_sock_H__
|
||||
#define __PJNATH_turn_sock_H__
|
||||
#ifndef __PJNATH_TURN_SOCK_H__
|
||||
#define __PJNATH_TURN_SOCK_H__
|
||||
|
||||
/**
|
||||
* @file turn_sock.h
|
||||
|
@ -53,7 +53,7 @@ typedef struct pj_turn_sock_cb
|
|||
* This callback is mandatory.
|
||||
*/
|
||||
void (*on_rx_data)(pj_turn_sock *turn_sock,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
@ -103,6 +103,19 @@ PJ_DECL(void*) pj_turn_sock_get_user_data(pj_turn_sock *turn_sock);
|
|||
PJ_DECL(pj_status_t) pj_turn_sock_get_info(pj_turn_sock *turn_sock,
|
||||
pj_turn_session_info *info);
|
||||
|
||||
/**
|
||||
* Lock the TURN socket. Application may need to call this function to
|
||||
* synchronize access to other objects to avoid deadlock.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_lock(pj_turn_sock *turn_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Unlock the TURN socket.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_turn_sock_unlock(pj_turn_sock *turn_sock);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
|
@ -138,5 +151,5 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock,
|
|||
PJ_END_DECL
|
||||
|
||||
|
||||
#endif /* __PJNATH_turn_sock_H__ */
|
||||
#endif /* __PJNATH_TURN_SOCK_H__ */
|
||||
|
||||
|
|
|
@ -101,6 +101,24 @@ typedef struct timer_data
|
|||
} timer_data;
|
||||
|
||||
|
||||
/* This is the data that will be attached as token to outgoing
|
||||
* STUN messages.
|
||||
*/
|
||||
struct msg_data
|
||||
{
|
||||
pj_bool_t is_request;
|
||||
unsigned cand_id;
|
||||
|
||||
union data {
|
||||
struct request_data {
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_checklist *clist;
|
||||
unsigned ckid;
|
||||
} req;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
static void destroy_ice(pj_ice_sess *ice,
|
||||
pj_status_t reason);
|
||||
|
@ -1345,26 +1363,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
|
|||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* This is the data that will be attached as user data to outgoing
|
||||
* STUN requests, and it will be given back when we receive completion
|
||||
* status of the request.
|
||||
*/
|
||||
struct req_data
|
||||
{
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_checklist *clist;
|
||||
unsigned ckid;
|
||||
};
|
||||
|
||||
|
||||
/* Perform check on the specified candidate pair */
|
||||
static pj_status_t perform_check(pj_ice_sess *ice,
|
||||
pj_ice_sess_checklist *clist,
|
||||
unsigned check_id)
|
||||
{
|
||||
pj_ice_sess_comp *comp;
|
||||
struct req_data *rd;
|
||||
struct msg_data *msg_data;
|
||||
pj_ice_sess_check *check;
|
||||
const pj_ice_sess_cand *lcand;
|
||||
const pj_ice_sess_cand *rcand;
|
||||
|
@ -1392,10 +1397,12 @@ static pj_status_t perform_check(pj_ice_sess *ice,
|
|||
/* Attach data to be retrieved later when STUN request transaction
|
||||
* completes and on_stun_request_complete() callback is called.
|
||||
*/
|
||||
rd = PJ_POOL_ZALLOC_T(check->tdata->pool, struct req_data);
|
||||
rd->ice = ice;
|
||||
rd->clist = clist;
|
||||
rd->ckid = check_id;
|
||||
msg_data = PJ_POOL_ZALLOC_T(ice->pool, struct msg_data);
|
||||
msg_data->is_request = PJ_TRUE;
|
||||
msg_data->cand_id = lcand - ice->lcand;
|
||||
msg_data->data.req.ice = ice;
|
||||
msg_data->data.req.clist = clist;
|
||||
msg_data->data.req.ckid = check_id;
|
||||
|
||||
/* Add PRIORITY */
|
||||
prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535,
|
||||
|
@ -1427,7 +1434,7 @@ static pj_status_t perform_check(pj_ice_sess *ice,
|
|||
*/
|
||||
|
||||
/* Initiate STUN transaction to send the request */
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, (void*)rd, PJ_FALSE,
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
|
||||
PJ_TRUE, &rcand->addr,
|
||||
sizeof(pj_sockaddr_in), check->tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -1655,12 +1662,13 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
|
|||
{
|
||||
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
|
||||
pj_ice_sess *ice = sd->ice;
|
||||
struct msg_data *msg_data = (struct msg_data*) token;
|
||||
unsigned cand_id;
|
||||
|
||||
cand_id = msg_data->cand_id;
|
||||
|
||||
PJ_UNUSED_ARG(token);
|
||||
|
||||
return (*ice->cb.on_tx_pkt)(ice, sd->comp_id,
|
||||
pkt, pkt_size,
|
||||
dst_addr, addr_len);
|
||||
return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, cand_id,
|
||||
pkt, pkt_size, dst_addr, addr_len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1673,7 +1681,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
struct req_data *rd = (struct req_data*) token;
|
||||
struct msg_data *msg_data = (struct msg_data*) token;
|
||||
pj_ice_sess *ice;
|
||||
pj_ice_sess_check *check, *new_check;
|
||||
pj_ice_sess_cand *lcand;
|
||||
|
@ -1684,9 +1692,12 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
PJ_UNUSED_ARG(stun_sess);
|
||||
PJ_UNUSED_ARG(src_addr_len);
|
||||
|
||||
ice = rd->ice;
|
||||
check = &rd->clist->checks[rd->ckid];
|
||||
clist = rd->clist;
|
||||
pj_assert(msg_data->is_request);
|
||||
|
||||
ice = msg_data->data.req.ice;
|
||||
clist = msg_data->data.req.clist;
|
||||
check = &clist->checks[msg_data->data.req.ckid];
|
||||
|
||||
|
||||
/* Mark STUN transaction as complete */
|
||||
pj_assert(tdata == check->tdata);
|
||||
|
@ -1739,7 +1750,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
|
|||
/* Resend request */
|
||||
LOG4((ice->obj_name, "Resending check because of role conflict"));
|
||||
check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0);
|
||||
perform_check(ice, clist, rd->ckid);
|
||||
perform_check(ice, clist, msg_data->data.req.ckid);
|
||||
pj_mutex_unlock(ice->mutex);
|
||||
return;
|
||||
}
|
||||
|
@ -1918,7 +1929,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
unsigned src_addr_len)
|
||||
{
|
||||
stun_data *sd;
|
||||
//unsigned *param_cand_id;
|
||||
const pj_stun_msg *msg = rdata->msg;
|
||||
struct msg_data *msg_data;
|
||||
pj_ice_sess *ice;
|
||||
pj_stun_priority_attr *prio_attr;
|
||||
pj_stun_use_candidate_attr *uc_attr;
|
||||
|
@ -1929,7 +1942,16 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
|
||||
PJ_UNUSED_ARG(pkt);
|
||||
PJ_UNUSED_ARG(pkt_len);
|
||||
PJ_UNUSED_ARG(token);
|
||||
|
||||
/*
|
||||
* Note about candidate ID parameter:
|
||||
* This parameter is given by us by user, and it cannot be used to
|
||||
* distinguish local and server reflexive candidate. Just about the
|
||||
* only thing that we can do with it is to return it back to user
|
||||
* in the on_tx_pkt(). The user needs this information to determine
|
||||
* whether to send packet using local socket or the relay.
|
||||
*/
|
||||
//param_cand_id = (unsigned*)token;
|
||||
|
||||
/* Reject any requests except Binding request */
|
||||
if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
|
||||
|
@ -2034,11 +2056,18 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Add XOR-MAPPED-ADDRESS attribute */
|
||||
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE, src_addr, src_addr_len);
|
||||
|
||||
status = pj_stun_session_send_msg(sess, NULL, PJ_TRUE, PJ_TRUE,
|
||||
/* Create a msg_data to be associated with this response */
|
||||
msg_data = PJ_POOL_ZALLOC_T(ice->pool, struct msg_data);
|
||||
msg_data->is_request = PJ_FALSE;
|
||||
msg_data->cand_id = ((struct msg_data*)token)->cand_id;
|
||||
|
||||
/* Send the response */
|
||||
status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
|
||||
src_addr, src_addr_len, tdata);
|
||||
|
||||
|
||||
|
@ -2090,7 +2119,6 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
pj_ice_sess_cand *lcand = NULL;
|
||||
pj_ice_sess_cand *rcand;
|
||||
unsigned i;
|
||||
pj_bool_t is_relayed;
|
||||
|
||||
comp = find_comp(ice, rcheck->comp_id);
|
||||
|
||||
|
@ -2170,11 +2198,6 @@ static void handle_incoming_check(pj_ice_sess *ice,
|
|||
/*
|
||||
* Create candidate pair for this request.
|
||||
*/
|
||||
/* First check if the source address is the source address of the
|
||||
* STUN relay, to determine if local candidate is relayed candidate.
|
||||
*/
|
||||
PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE);
|
||||
is_relayed = PJ_FALSE;
|
||||
|
||||
/*
|
||||
* 7.2.1.4. Triggered Checks
|
||||
|
@ -2309,6 +2332,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
{
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
pj_ice_sess_comp *comp;
|
||||
unsigned cand_id;
|
||||
|
||||
PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
|
||||
|
||||
|
@ -2332,7 +2356,9 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
status = (*ice->cb.on_tx_pkt)(ice, comp_id, data, data_len,
|
||||
cand_id = comp->valid_check->lcand - ice->lcand;
|
||||
|
||||
status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand_id, data, data_len,
|
||||
&comp->valid_check->rcand->addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
|
||||
|
@ -2344,6 +2370,7 @@ on_return:
|
|||
|
||||
PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned cand_id,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
|
@ -2351,6 +2378,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
|||
{
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
pj_ice_sess_comp *comp;
|
||||
struct msg_data *msg_data;
|
||||
pj_status_t stun_status;
|
||||
|
||||
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
|
||||
|
@ -2363,11 +2391,15 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
|
|||
goto on_return;
|
||||
}
|
||||
|
||||
msg_data = PJ_POOL_ZALLOC_T(ice->pool, struct msg_data);
|
||||
msg_data->is_request = PJ_FALSE;
|
||||
msg_data->cand_id = cand_id;
|
||||
|
||||
stun_status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size,
|
||||
PJ_STUN_IS_DATAGRAM);
|
||||
if (stun_status == PJ_SUCCESS) {
|
||||
status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
|
||||
PJ_STUN_IS_DATAGRAM, NULL,
|
||||
PJ_STUN_IS_DATAGRAM, msg_data,
|
||||
NULL, src_addr, src_addr_len);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_strerror(status, ice->tmp.errmsg, sizeof(ice->tmp.errmsg));
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
|
||||
static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned cand_id,
|
||||
const void *pkt, pj_size_t size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned dst_addr_len);
|
||||
|
@ -73,6 +74,16 @@ static void stun_on_request_complete(pj_stun_session *sess,
|
|||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
|
||||
/* TURN callbacks */
|
||||
static void turn_on_rx_data(pj_turn_sock *turn_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state);
|
||||
|
||||
|
||||
/* Keep-alive timer */
|
||||
static void start_ka_timer(pj_ice_strans *ice_st);
|
||||
static void stop_ka_timer(pj_ice_strans *ice_st);
|
||||
|
@ -80,10 +91,28 @@ static void stop_ka_timer(pj_ice_strans *ice_st);
|
|||
/* Utility: print error */
|
||||
#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
|
||||
|
||||
/* Validate configuration */
|
||||
static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
status = pj_stun_config_check_valid(&cfg->stun_cfg);
|
||||
if (!status)
|
||||
return status;
|
||||
|
||||
/* If TURN is specified then TURN credential must be specified */
|
||||
PJ_ASSERT_RETURN(!pj_sockaddr_has_addr(&cfg->turn_srv) ||
|
||||
cfg->turn_cred.type != PJ_STUN_AUTH_NONE,
|
||||
PJ_EINVAL);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create ICE stream transport
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_ice_strans_create( pj_stun_config *stun_cfg,
|
||||
PJ_DEF(pj_status_t) pj_ice_strans_create( const pj_ice_strans_cfg *cfg,
|
||||
const char *name,
|
||||
unsigned comp_cnt,
|
||||
void *user_data,
|
||||
|
@ -92,17 +121,23 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( pj_stun_config *stun_cfg,
|
|||
{
|
||||
pj_pool_t *pool;
|
||||
pj_ice_strans *ice_st;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL);
|
||||
status = pj_ice_strans_cfg_check_valid(cfg);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st, PJ_EINVAL);
|
||||
|
||||
if (name == NULL)
|
||||
name = "icstr%p";
|
||||
|
||||
pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_STRANS,
|
||||
pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS,
|
||||
PJNATH_POOL_INC_ICE_STRANS, NULL);
|
||||
ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans);
|
||||
ice_st->pool = pool;
|
||||
pj_memcpy(&ice_st->cfg, cfg, sizeof(*cfg));
|
||||
pj_stun_auth_cred_dup(pool, &ice_st->cfg.turn_cred, &cfg->turn_cred);
|
||||
pj_memcpy(ice_st->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);
|
||||
ice_st->user_data = user_data;
|
||||
|
||||
|
@ -111,7 +146,6 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( pj_stun_config *stun_cfg,
|
|||
sizeof(void*));
|
||||
|
||||
pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
|
||||
pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg));
|
||||
|
||||
|
||||
PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created"));
|
||||
|
@ -180,32 +214,6 @@ PJ_DEF(pj_status_t) pj_ice_strans_set_stun_domain(pj_ice_strans *ice_st,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set STUN server address.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st,
|
||||
const pj_sockaddr_in *stun_srv,
|
||||
const pj_sockaddr_in *turn_srv)
|
||||
{
|
||||
PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
|
||||
/* Must not have pending resolver job */
|
||||
PJ_ASSERT_RETURN(ice_st->has_rjob==PJ_FALSE, PJ_EINVALIDOP);
|
||||
|
||||
if (stun_srv) {
|
||||
pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in));
|
||||
} else {
|
||||
pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in));
|
||||
}
|
||||
|
||||
if (turn_srv) {
|
||||
pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in));
|
||||
} else {
|
||||
pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in));
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Add new candidate */
|
||||
static pj_status_t add_cand( pj_ice_strans *ice_st,
|
||||
pj_ice_strans_comp *comp,
|
||||
|
@ -327,7 +335,8 @@ static pj_status_t create_component(pj_ice_strans *ice_st,
|
|||
/* Register to ioqueue */
|
||||
pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
|
||||
ioqueue_cb.on_read_complete = &on_read_complete;
|
||||
status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue,
|
||||
status = pj_ioqueue_register_sock(ice_st->pool,
|
||||
ice_st->cfg.stun_cfg.ioqueue,
|
||||
comp->sock, comp, &ioqueue_cb,
|
||||
&comp->key);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -387,7 +396,9 @@ static pj_status_t create_component(pj_ice_strans *ice_st,
|
|||
/* If the IP address is equal to local address, assign it
|
||||
* as default candidate.
|
||||
*/
|
||||
if (ifs[i].ipv4.sin_addr.s_addr == comp->local_addr.ipv4.sin_addr.s_addr) {
|
||||
if (ifs[i].ipv4.sin_addr.s_addr ==
|
||||
comp->local_addr.ipv4.sin_addr.s_addr)
|
||||
{
|
||||
set_default = PJ_TRUE;
|
||||
local_pref = 65535;
|
||||
} else {
|
||||
|
@ -463,24 +474,33 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
* address of this component, or b) subsequent request to keep
|
||||
* the binding alive.
|
||||
*
|
||||
* 2) this could be a packet (STUN or not STUN) sent from the STUN
|
||||
* relay server. In this case, still there are few options to do
|
||||
* for this packet: a) process this locally if this packet is
|
||||
* related to TURN session management (e.g. Allocate response),
|
||||
* b) forward this packet to ICE if this is related to ICE
|
||||
* 2) this could be a STUN request or response sent as part of ICE
|
||||
* discovery process.
|
||||
*
|
||||
* 3) this could be a STUN request or response sent as part of ICE
|
||||
* discovery process.
|
||||
*
|
||||
* 4) this could be application's packet, e.g. when ICE processing
|
||||
* 3) this could be application's packet, e.g. when ICE processing
|
||||
* is done and agents start sending RTP/RTCP packets to each
|
||||
* other, or when ICE processing is not done and this ICE stream
|
||||
* transport decides to allow sending data.
|
||||
*
|
||||
* So far we don't have good solution for this.
|
||||
* The process below is just a workaround.
|
||||
*/
|
||||
unsigned cand_id;
|
||||
|
||||
/* Find candidate ID for this packet */
|
||||
for (cand_id=0; cand_id<comp->cand_cnt; ++cand_id) {
|
||||
if (comp->cand_list[cand_id].type != PJ_ICE_CAND_TYPE_RELAYED)
|
||||
break;
|
||||
}
|
||||
if (cand_id == comp->cand_cnt) {
|
||||
//pj_assert(!"We should have at least one host/srflx candidate");
|
||||
//cand_id = 0;
|
||||
PJ_LOG(2,(ice_st->obj_name,
|
||||
"Received pkt on comp %d which doesn't have host/srflx "
|
||||
"candidate",
|
||||
comp->comp_id));
|
||||
goto next_packet;
|
||||
}
|
||||
|
||||
/* Is this a STUN message? */
|
||||
status = pj_stun_msg_check(comp->pkt, bytes_read,
|
||||
PJ_STUN_IS_DATAGRAM);
|
||||
|
||||
|
@ -495,8 +515,6 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
NULL, &comp->src_addr,
|
||||
comp->src_addr_len);
|
||||
} else if (ice_st->ice) {
|
||||
PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY);
|
||||
|
||||
TRACE_PKT((comp->ice_st->obj_name,
|
||||
"Component %d RX packet from %s:%d",
|
||||
comp->comp_id,
|
||||
|
@ -504,7 +522,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
(int)pj_ntohs(comp->src_addr.ipv4.sin_port)));
|
||||
|
||||
status = pj_ice_sess_on_rx_pkt(ice_st->ice, comp->comp_id,
|
||||
comp->pkt, bytes_read,
|
||||
cand_id, comp->pkt, bytes_read,
|
||||
&comp->src_addr,
|
||||
comp->src_addr_len);
|
||||
} else {
|
||||
|
@ -524,6 +542,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
}
|
||||
|
||||
/* Read next packet */
|
||||
next_packet:
|
||||
for (retry=0; retry<RETRY;) {
|
||||
pkt_size = sizeof(comp->pkt);
|
||||
comp->src_addr_len = sizeof(comp->src_addr);
|
||||
|
@ -551,6 +570,11 @@ static void on_read_complete(pj_ioqueue_key_t *key,
|
|||
*/
|
||||
static void destroy_component(pj_ice_strans_comp *comp)
|
||||
{
|
||||
if (comp->turn_relay) {
|
||||
pj_turn_sock_destroy(comp->turn_relay);
|
||||
comp->turn_relay = NULL;
|
||||
}
|
||||
|
||||
if (comp->stun_sess) {
|
||||
pj_stun_session_destroy(comp->stun_sess);
|
||||
comp->stun_sess = NULL;
|
||||
|
@ -610,7 +634,8 @@ static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
|
|||
pj_inet_ntoa(comp->local_addr.ipv4.sin_addr),
|
||||
pj_ntohs(comp->local_addr.ipv4.sin_port)));
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, &comp->cand_list[j],
|
||||
PJ_FALSE, PJ_TRUE, &ice_st->stun_srv,
|
||||
PJ_FALSE, PJ_TRUE,
|
||||
&ice_st->cfg.stun_srv,
|
||||
sizeof(pj_sockaddr_in), tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
--comp->pending_cnt;
|
||||
|
@ -637,7 +662,7 @@ static void start_ka_timer(pj_ice_strans *ice_st)
|
|||
ice_st->ka_timer.cb = &ka_timer_cb;
|
||||
ice_st->ka_timer.user_data = ice_st;
|
||||
|
||||
if (pj_timer_heap_schedule(ice_st->stun_cfg.timer_heap,
|
||||
if (pj_timer_heap_schedule(ice_st->cfg.stun_cfg.timer_heap,
|
||||
&ice_st->ka_timer, &delay)==PJ_SUCCESS)
|
||||
{
|
||||
ice_st->ka_timer.id = PJ_TRUE;
|
||||
|
@ -652,7 +677,7 @@ static void stop_ka_timer(pj_ice_strans *ice_st)
|
|||
if (ice_st->ka_timer.id == PJ_FALSE)
|
||||
return;
|
||||
|
||||
pj_timer_heap_cancel(ice_st->stun_cfg.timer_heap, &ice_st->ka_timer);
|
||||
pj_timer_heap_cancel(ice_st->cfg.stun_cfg.timer_heap, &ice_st->ka_timer);
|
||||
ice_st->ka_timer.id = PJ_FALSE;
|
||||
}
|
||||
|
||||
|
@ -670,12 +695,8 @@ static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st,
|
|||
|
||||
PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL);
|
||||
|
||||
/* Bail out if STUN server is still being resolved */
|
||||
if (ice_st->has_rjob)
|
||||
return PJ_EBUSY;
|
||||
|
||||
/* Just return (successfully) if STUN server is not configured */
|
||||
if (ice_st->stun_srv.sin_family == 0)
|
||||
if (ice_st->cfg.stun_srv.addr.sa_family == 0)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
|
||||
|
@ -683,7 +704,7 @@ static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st,
|
|||
pj_bzero(&sess_cb, sizeof(sess_cb));
|
||||
sess_cb.on_request_complete = &stun_on_request_complete;
|
||||
sess_cb.on_send_msg = &stun_on_send_msg;
|
||||
status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name,
|
||||
status = pj_stun_session_create(&ice_st->cfg.stun_cfg, ice_st->obj_name,
|
||||
&sess_cb, PJ_FALSE, &comp->stun_sess);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
@ -710,7 +731,7 @@ static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st,
|
|||
|
||||
/* Add new alias to this component */
|
||||
cand->type = PJ_ICE_CAND_TYPE_SRFLX;
|
||||
cand->status = PJ_EPENDING;
|
||||
cand->status = PJ_SUCCESS;
|
||||
cand->ice_cand_id = -1;
|
||||
cand->local_pref = 65535;
|
||||
pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
|
||||
|
@ -720,7 +741,7 @@ static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st,
|
|||
|
||||
/* Send STUN binding request */
|
||||
status = pj_stun_session_send_msg(comp->stun_sess, (void*)cand, PJ_FALSE,
|
||||
PJ_TRUE, &ice_st->stun_srv,
|
||||
PJ_TRUE, &ice_st->cfg.stun_srv,
|
||||
sizeof(pj_sockaddr_in), tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
--comp->pending_cnt;
|
||||
|
@ -752,16 +773,16 @@ PJ_DEF(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st,
|
|||
/* Can't add new component while ICE is running */
|
||||
PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY);
|
||||
|
||||
/* Can't add new component while resolver is running */
|
||||
PJ_ASSERT_RETURN(ice_st->has_rjob == PJ_FALSE, PJ_EBUSY);
|
||||
|
||||
|
||||
/* Create component */
|
||||
status = create_component(ice_st, comp_id, options, addr, &comp);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) {
|
||||
/* Start STUN mapped address resolution */
|
||||
if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0 &&
|
||||
pj_sockaddr_has_addr(&ice_st->cfg.stun_srv))
|
||||
{
|
||||
status = get_stun_mapped_addr(ice_st, comp);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_component(comp);
|
||||
|
@ -769,6 +790,52 @@ PJ_DEF(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st,
|
|||
}
|
||||
}
|
||||
|
||||
/* Create TURN relay if wanted. */
|
||||
if ((options & PJ_ICE_ST_OPT_DISABLE_RELAY) == 0 &&
|
||||
pj_sockaddr_has_addr(&ice_st->cfg.turn_srv))
|
||||
{
|
||||
pj_turn_sock_cb turn_sock_cb;
|
||||
char ipaddr[PJ_INET6_ADDRSTRLEN+8];
|
||||
pj_str_t s;
|
||||
|
||||
pj_assert(comp->cand_cnt < PJ_ICE_ST_MAX_CAND);
|
||||
|
||||
/* Init TURN socket */
|
||||
pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
|
||||
turn_sock_cb.on_rx_data = &turn_on_rx_data;
|
||||
turn_sock_cb.on_state = &turn_on_state;
|
||||
|
||||
status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, pj_AF_INET(),
|
||||
ice_st->cfg.turn_conn_type,
|
||||
&turn_sock_cb, 0, comp,
|
||||
&comp->turn_relay);
|
||||
if (status != PJ_SUCCESS) {
|
||||
destroy_component(comp);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_sockaddr_print(&ice_st->cfg.turn_srv, ipaddr, sizeof(ipaddr), 0);
|
||||
|
||||
++comp->pending_cnt;
|
||||
|
||||
/* Start allocation */
|
||||
status = pj_turn_sock_init(comp->turn_relay, pj_cstr(&s, ipaddr),
|
||||
pj_sockaddr_get_port(&ice_st->cfg.turn_srv),
|
||||
NULL, &ice_st->cfg.turn_cred,
|
||||
&ice_st->cfg.turn_alloc_param);
|
||||
if (status != PJ_SUCCESS) {
|
||||
if (comp->turn_relay) {
|
||||
pj_turn_sock_destroy(comp->turn_relay);
|
||||
}
|
||||
comp->turn_relay = NULL;
|
||||
--comp->pending_cnt;
|
||||
destroy_component(comp);
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Store this component */
|
||||
ice_st->comp[comp_id-1] = comp;
|
||||
|
||||
|
@ -848,7 +915,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
|
|||
ice_cb.on_tx_pkt = &ice_tx_pkt;
|
||||
|
||||
/* Create! */
|
||||
status = pj_ice_sess_create(&ice_st->stun_cfg, ice_st->obj_name, role,
|
||||
status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
|
||||
ice_st->comp_cnt, &ice_cb,
|
||||
local_ufrag, local_passwd, &ice_st->ice);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -876,6 +943,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
|
|||
|
||||
for (j=0; j<comp->cand_cnt; ++j) {
|
||||
pj_ice_strans_cand *cand = &comp->cand_list[j];
|
||||
pj_sockaddr_t *local_addr, *relay_addr;
|
||||
|
||||
/* Skip if candidate is not ready */
|
||||
if (cand->status != PJ_SUCCESS) {
|
||||
|
@ -885,10 +953,25 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Skip if candidate has no address */
|
||||
if (!pj_sockaddr_has_addr(&cand->addr)) {
|
||||
PJ_LOG(5,(ice_st->obj_name,
|
||||
"Candidate %d in component %d is not added",
|
||||
j, i));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cand->type == PJ_ICE_CAND_TYPE_RELAYED) {
|
||||
local_addr = &cand->addr;
|
||||
relay_addr = &cand->addr;
|
||||
} else {
|
||||
local_addr = &comp->local_addr;
|
||||
relay_addr = NULL;
|
||||
}
|
||||
status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
|
||||
cand->type, cand->local_pref,
|
||||
&cand->foundation, &cand->addr,
|
||||
&comp->local_addr, NULL,
|
||||
local_addr, relay_addr,
|
||||
sizeof(pj_sockaddr_in),
|
||||
(unsigned*)&cand->ice_cand_id);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -977,7 +1060,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
|
|||
}
|
||||
|
||||
/*
|
||||
* Send packet using non-ICE means (e.g. when ICE was not negotiated).
|
||||
* Application wants to send outgoing packet.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
|
||||
unsigned comp_id,
|
||||
|
@ -997,7 +1080,14 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
|
|||
|
||||
/* If ICE is available, send data with ICE */
|
||||
if (ice_st->ice) {
|
||||
return pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
|
||||
if (comp->turn_relay) {
|
||||
pj_turn_sock_lock(comp->turn_relay);
|
||||
}
|
||||
status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
|
||||
if (comp->turn_relay) {
|
||||
pj_turn_sock_unlock(comp->turn_relay);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Otherwise send direcly with the socket. This is for compatibility
|
||||
|
@ -1028,30 +1118,40 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
|
|||
*/
|
||||
static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
|
||||
unsigned comp_id,
|
||||
unsigned cand_id,
|
||||
const void *pkt, pj_size_t size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned dst_addr_len)
|
||||
{
|
||||
pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
|
||||
pj_ice_strans_comp *comp = NULL;
|
||||
pj_ssize_t pkt_size;
|
||||
pj_ice_strans_comp *comp;
|
||||
pj_ice_strans_cand *cand;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_TODO(TX_TO_RELAY);
|
||||
|
||||
PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
|
||||
|
||||
comp = ice_st->comp[comp_id-1];
|
||||
cand = &comp->cand_list[cand_id];
|
||||
|
||||
TRACE_PKT((comp->ice_st->obj_name,
|
||||
"Component %d TX packet to %s:%d",
|
||||
comp_id,
|
||||
"Component %d candidate %d TX packet to %s:%d",
|
||||
comp_id, cand_id,
|
||||
pj_inet_ntoa(((pj_sockaddr_in*)dst_addr)->sin_addr),
|
||||
(int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port)));
|
||||
|
||||
pkt_size = size;
|
||||
status = pj_ioqueue_sendto(comp->key, &comp->write_op,
|
||||
pkt, &pkt_size, 0,
|
||||
dst_addr, dst_addr_len);
|
||||
if (cand->type == PJ_ICE_CAND_TYPE_RELAYED) {
|
||||
if (comp->turn_relay) {
|
||||
status = pj_turn_sock_sendto(comp->turn_relay, pkt, size,
|
||||
dst_addr, dst_addr_len);
|
||||
} else {
|
||||
status = PJ_EINVALIDOP;
|
||||
}
|
||||
} else {
|
||||
pj_ssize_t pkt_size = size;
|
||||
status = pj_ioqueue_sendto(comp->key, &comp->write_op,
|
||||
pkt, &pkt_size, 0,
|
||||
dst_addr, dst_addr_len);
|
||||
}
|
||||
|
||||
return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
|
||||
}
|
||||
|
@ -1206,3 +1306,108 @@ static void stun_on_request_complete(pj_stun_session *sess,
|
|||
(cand - comp->cand_list));
|
||||
}
|
||||
|
||||
|
||||
/* Callback when TURN client has received a packet */
|
||||
static void turn_on_rx_data(pj_turn_sock *turn_sock,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
pj_ice_strans_comp *comp;
|
||||
unsigned cand_id;
|
||||
pj_status_t status;
|
||||
|
||||
comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
|
||||
if (comp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (comp->ice_st->ice == NULL) {
|
||||
/* The session is gone */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find candidate ID for this packet */
|
||||
for (cand_id=0; cand_id<comp->cand_cnt; ++cand_id) {
|
||||
if (comp->cand_list[cand_id].type == PJ_ICE_CAND_TYPE_RELAYED)
|
||||
break;
|
||||
}
|
||||
if (cand_id == comp->cand_cnt) {
|
||||
pj_assert(!"Missing relay candidate");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hand over the packet to ICE */
|
||||
status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
|
||||
cand_id, pkt, pkt_len,
|
||||
peer_addr, addr_len);
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
ice_st_perror(comp->ice_st, "Error processing packet from TURN relay",
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Callback when TURN client state has changed */
|
||||
static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
|
||||
pj_turn_state_t new_state)
|
||||
{
|
||||
pj_ice_strans_comp *comp;
|
||||
|
||||
comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
|
||||
if (comp == NULL) {
|
||||
/* Not interested in further state notification once the relay is
|
||||
* disconnecting.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
|
||||
pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
|
||||
|
||||
if (old_state < PJ_TURN_STATE_READY &&
|
||||
new_state >= PJ_TURN_STATE_READY)
|
||||
{
|
||||
pj_assert(comp->pending_cnt > 0);
|
||||
comp->pending_cnt--;
|
||||
}
|
||||
|
||||
if (new_state == PJ_TURN_STATE_READY) {
|
||||
pj_turn_session_info rel_info;
|
||||
char ipaddr[PJ_INET6_ADDRSTRLEN+8];
|
||||
pj_ice_strans_cand *cand;
|
||||
|
||||
/* Get allocation info */
|
||||
pj_turn_sock_get_info(turn_sock, &rel_info);
|
||||
|
||||
/* Add a relay candidate to this component */
|
||||
pj_assert(comp->cand_cnt < PJ_ICE_ST_MAX_CAND);
|
||||
cand = &comp->cand_list[comp->cand_cnt++];
|
||||
|
||||
/* Add new candidate to this component */
|
||||
cand->type = PJ_ICE_CAND_TYPE_RELAYED;
|
||||
cand->status = PJ_SUCCESS;
|
||||
cand->ice_cand_id = -1;
|
||||
cand->local_pref = 65535;
|
||||
pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
|
||||
pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,
|
||||
PJ_ICE_CAND_TYPE_RELAYED,
|
||||
&rel_info.relay_addr);
|
||||
|
||||
PJ_LOG(4,(comp->ice_st->obj_name,
|
||||
"Component %d cand %d: relay address: %s",
|
||||
comp->comp_id, cand - comp->cand_list,
|
||||
pj_sockaddr_print(&rel_info.relay_addr, ipaddr,
|
||||
sizeof(ipaddr), 3)));
|
||||
|
||||
} else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
|
||||
/* Unregister ourself from the TURN relay */
|
||||
pj_turn_sock_set_user_data(turn_sock, NULL);
|
||||
comp->turn_relay = NULL;
|
||||
|
||||
PJ_LOG(4,(comp->ice_st->obj_name, "Relay destroyed"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ struct pj_turn_session
|
|||
const char *obj_name;
|
||||
pj_turn_session_cb cb;
|
||||
void *user_data;
|
||||
pj_stun_config stun_cfg;
|
||||
|
||||
pj_lock_t *lock;
|
||||
int busy;
|
||||
|
@ -176,7 +177,7 @@ PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state)
|
|||
/*
|
||||
* Create TURN client session.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
||||
PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
|
||||
const char *name,
|
||||
int af,
|
||||
pj_turn_tp_type tp_type,
|
||||
|
@ -211,6 +212,9 @@ PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
|||
sess->user_data = user_data;
|
||||
sess->next_ch = PJ_TURN_CHANNEL_MIN;
|
||||
|
||||
/* Copy STUN session */
|
||||
pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config));
|
||||
|
||||
/* Copy callback */
|
||||
pj_memcpy(&sess->cb, cb, sizeof(*cb));
|
||||
|
||||
|
@ -233,8 +237,8 @@ PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
|
|||
stun_cb.on_send_msg = &stun_on_send_msg;
|
||||
stun_cb.on_request_complete = &stun_on_request_complete;
|
||||
stun_cb.on_rx_indication = &stun_on_rx_indication;
|
||||
status = pj_stun_session_create(cfg, sess->obj_name, &stun_cb, PJ_FALSE,
|
||||
&sess->stun);
|
||||
status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb,
|
||||
PJ_FALSE, &sess->stun);
|
||||
if (status != PJ_SUCCESS) {
|
||||
do_destroy(sess);
|
||||
return status;
|
||||
|
@ -849,7 +853,7 @@ on_return:
|
|||
* The packet maybe a STUN packet or ChannelData packet.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
pj_bool_t is_datagram)
|
||||
{
|
||||
|
@ -864,13 +868,13 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
|||
pj_lock_acquire(sess->lock);
|
||||
|
||||
/* Quickly check if this is STUN message */
|
||||
is_stun = ((pkt[0] & 0xC0) == 0);
|
||||
is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0);
|
||||
|
||||
if (is_stun) {
|
||||
/* This looks like STUN, give it to the STUN session */
|
||||
unsigned options;
|
||||
|
||||
options = PJ_STUN_CHECK_PACKET;
|
||||
options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
|
||||
if (is_datagram)
|
||||
options |= PJ_STUN_IS_DATAGRAM;
|
||||
status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
|
||||
|
@ -905,8 +909,8 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
|
|||
}
|
||||
|
||||
/* Notify application */
|
||||
(*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), cd.length,
|
||||
&peer->addr,
|
||||
(*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd),
|
||||
cd.length, &peer->addr,
|
||||
pj_sockaddr_get_len(&peer->addr));
|
||||
|
||||
status = PJ_SUCCESS;
|
||||
|
|
|
@ -71,7 +71,7 @@ static void turn_on_channel_bound(pj_turn_session *sess,
|
|||
unsigned addr_len,
|
||||
unsigned ch_num);
|
||||
static void turn_on_rx_data(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len);
|
||||
|
@ -309,6 +309,24 @@ PJ_DEF(pj_status_t) pj_turn_sock_get_info(pj_turn_sock *turn_sock,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the TURN socket. Application may need to call this function to
|
||||
* synchronize access to other objects to avoid deadlock.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_lock(pj_turn_sock *turn_sock)
|
||||
{
|
||||
return pj_lock_acquire(turn_sock->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the TURN socket.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_turn_sock_unlock(pj_turn_sock *turn_sock)
|
||||
{
|
||||
return pj_lock_release(turn_sock->lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
|
@ -524,7 +542,7 @@ static void turn_on_channel_bound(pj_turn_session *sess,
|
|||
* Callback from TURN session upon incoming data.
|
||||
*/
|
||||
static void turn_on_rx_data(pj_turn_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
void *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_sockaddr_t *peer_addr,
|
||||
unsigned addr_len)
|
||||
|
|
|
@ -35,8 +35,7 @@ static struct cred_t
|
|||
{
|
||||
{ "100", "100" },
|
||||
{ "700", "700" },
|
||||
{ "701", "701" },
|
||||
{ "702", "702" }
|
||||
{ "701", "701" }
|
||||
};
|
||||
|
||||
#define THE_NONCE "pjnath"
|
||||
|
|
|
@ -22,6 +22,25 @@
|
|||
#define THIS_FILE "pjsua_app.c"
|
||||
#define NO_LIMIT (int)0x7FFFFFFF
|
||||
|
||||
#if 0
|
||||
#define TURN_SERVER "turn.pjsip.org"
|
||||
#define TURN_PORT 34780
|
||||
#define TURN_REALM "pjsip.org"
|
||||
#define TURN_USER "700"
|
||||
#define TURN_PASSWD "700"
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
/* Eyeball test */
|
||||
#define TURN_SERVER "216.187.87.78"
|
||||
#define TURN_PORT 3478
|
||||
#define TURN_REALM "test.eyeball.com"
|
||||
#define TURN_USER "sipit6"
|
||||
#define TURN_PASSWD "password"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//#define STEREO_DEMO
|
||||
|
||||
/* Call specific data */
|
||||
|
@ -55,6 +74,8 @@ static struct app_config
|
|||
pj_pool_t *pool;
|
||||
/* Compatibility with older pjsua */
|
||||
|
||||
pj_bool_t use_turn;
|
||||
|
||||
unsigned codec_cnt;
|
||||
pj_str_t codec_arg[32];
|
||||
unsigned codec_dis_cnt;
|
||||
|
@ -171,6 +192,10 @@ static void usage(void)
|
|||
puts ("");
|
||||
puts ("Media Options:");
|
||||
puts (" --use-ice Enable ICE (default:no)");
|
||||
puts (" --use-turn Enable experimantal TURN (default:no)");
|
||||
puts (" --ice-no-host Disable ICE host candidates");
|
||||
puts (" --ice-no-srflx Disable ICE srflx candidates");
|
||||
puts (" --ice-no-rtcp Disable RTCP in ICE");
|
||||
puts (" --add-codec=name Manually add codec (default is to enable all)");
|
||||
puts (" --dis-codec=name Disable codec (can be specified multiple times)");
|
||||
puts (" --clock-rate=N Override conference bridge clock rate");
|
||||
|
@ -223,11 +248,11 @@ static void usage(void)
|
|||
/* Set default config. */
|
||||
static void default_config(struct app_config *cfg)
|
||||
{
|
||||
char tmp[80];
|
||||
char tmp[120];
|
||||
unsigned i;
|
||||
|
||||
pjsua_config_default(&cfg->cfg);
|
||||
pj_ansi_sprintf(tmp, "PJSUA v%s/%s", pj_get_version(), PJ_OS_NAME);
|
||||
pj_ansi_sprintf(tmp, "PJSUA v%s/%s (http://pjsip.org)", pj_get_version(), PJ_OS_NAME);
|
||||
pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp);
|
||||
|
||||
pjsua_logging_config_default(&cfg->log_cfg);
|
||||
|
@ -391,7 +416,8 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
|
||||
OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
|
||||
OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO,
|
||||
OPT_USE_ICE, OPT_USE_SRTP, OPT_SRTP_SECURE,
|
||||
OPT_USE_ICE, OPT_USE_TURN, OPT_ICE_NO_HOST, OPT_ICE_NO_SRFLX,
|
||||
OPT_ICE_NO_RTCP, OPT_USE_SRTP, OPT_SRTP_SECURE,
|
||||
OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,
|
||||
OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
|
||||
OPT_COMPLEXITY, OPT_QUALITY, OPT_PTIME, OPT_NO_VAD,
|
||||
|
@ -452,6 +478,10 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
{ "rec-file", 1, 0, OPT_REC_FILE},
|
||||
{ "rtp-port", 1, 0, OPT_RTP_PORT},
|
||||
{ "use-ice", 0, 0, OPT_USE_ICE},
|
||||
{ "use-turn", 0, 0, OPT_USE_TURN},
|
||||
{ "ice-no-host",0, 0, OPT_ICE_NO_HOST},
|
||||
{ "ice-no-srflx",0,0, OPT_ICE_NO_SRFLX},
|
||||
{ "ice-no-rtcp",0, 0, OPT_ICE_NO_RTCP},
|
||||
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
|
||||
{ "use-srtp", 1, 0, OPT_USE_SRTP},
|
||||
{ "srtp-secure",1, 0, OPT_SRTP_SECURE},
|
||||
|
@ -825,6 +855,22 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
cfg->media_cfg.enable_ice = PJ_TRUE;
|
||||
break;
|
||||
|
||||
case OPT_USE_TURN:
|
||||
cfg->use_turn = PJ_TRUE;
|
||||
break;
|
||||
|
||||
case OPT_ICE_NO_HOST:
|
||||
cfg->media_cfg.ice_options |= PJ_ICE_ST_OPT_DONT_ADD_CAND;
|
||||
break;
|
||||
|
||||
case OPT_ICE_NO_SRFLX:
|
||||
cfg->media_cfg.ice_options |= PJ_ICE_ST_OPT_DISABLE_STUN;
|
||||
break;
|
||||
|
||||
case OPT_ICE_NO_RTCP:
|
||||
cfg->media_cfg.ice_no_rtcp = PJ_TRUE;
|
||||
break;
|
||||
|
||||
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
|
||||
case OPT_USE_SRTP:
|
||||
app_config.cfg.use_srtp = my_atoi(pj_optarg);
|
||||
|
@ -3466,6 +3512,20 @@ pj_status_t app_init(int argc, char *argv[])
|
|||
app_config.cfg.cb.on_call_replaced = &on_call_replaced;
|
||||
app_config.cfg.cb.on_nat_detect = &on_nat_detect;
|
||||
|
||||
/* Init TURN settings */
|
||||
#ifdef TURN_SERVER
|
||||
if (app_config.use_turn) {
|
||||
app_config.cfg.turn_host = pj_str(TURN_SERVER);
|
||||
app_config.cfg.turn_port = TURN_PORT;
|
||||
app_config.cfg.turn_tcp = 0;
|
||||
app_config.cfg.turn_cred.type = PJ_STUN_AUTH_CRED_STATIC;
|
||||
app_config.cfg.turn_cred.data.static_cred.realm = pj_str(TURN_REALM);
|
||||
app_config.cfg.turn_cred.data.static_cred.username = pj_str(TURN_USER);
|
||||
app_config.cfg.turn_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN;
|
||||
app_config.cfg.turn_cred.data.static_cred.data = pj_str(TURN_PASSWD);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize pjsua */
|
||||
status = pjsua_init(&app_config.cfg, &app_config.log_cfg,
|
||||
&app_config.media_cfg);
|
||||
|
|
|
@ -1043,9 +1043,24 @@ typedef struct pjsua_config
|
|||
pj_str_t stun_host;
|
||||
|
||||
/**
|
||||
* Specify STUN relay server to be used.
|
||||
* Specify TURN server to be used.
|
||||
*/
|
||||
pj_str_t stun_relay_host;
|
||||
pj_str_t turn_host;
|
||||
|
||||
/**
|
||||
* Specify TURN server port number.
|
||||
*/
|
||||
pj_uint16_t turn_port;
|
||||
|
||||
/**
|
||||
* Specify if TCP connection to TURN server should be used.
|
||||
*/
|
||||
pj_bool_t turn_tcp;
|
||||
|
||||
/**
|
||||
* Specify STUN credential for the TURN connection.
|
||||
*/
|
||||
pj_stun_auth_cred turn_cred;
|
||||
|
||||
/**
|
||||
* Support for adding and parsing NAT type in the SDP to assist
|
||||
|
@ -3886,9 +3901,14 @@ struct pjsua_media_config
|
|||
pj_bool_t enable_ice;
|
||||
|
||||
/**
|
||||
* Enable ICE media relay.
|
||||
* ICE options.
|
||||
*/
|
||||
pj_bool_t enable_relay;
|
||||
unsigned ice_options;
|
||||
|
||||
/**
|
||||
* Disable RTCP in ICE.
|
||||
*/
|
||||
pj_bool_t ice_no_rtcp;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -565,6 +565,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
|
|||
if (acc->regc != NULL) {
|
||||
pjsip_regc_destroy(acc->regc);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
}
|
||||
|
||||
/* Update account's Contact header */
|
||||
|
@ -853,6 +854,7 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
|
|||
param->status);
|
||||
pjsip_regc_destroy(acc->regc);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
|
||||
/* Stop keep-alive timer if any. */
|
||||
update_keep_alive(acc, PJ_FALSE, NULL);
|
||||
|
@ -863,6 +865,7 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
|
|||
(int)param->reason.slen, param->reason.ptr));
|
||||
pjsip_regc_destroy(acc->regc);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
|
||||
/* Stop keep-alive timer if any. */
|
||||
update_keep_alive(acc, PJ_FALSE, NULL);
|
||||
|
@ -872,6 +875,7 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
|
|||
if (param->expiration < 1) {
|
||||
pjsip_regc_destroy(acc->regc);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
|
||||
/* Stop keep-alive timer if any. */
|
||||
update_keep_alive(acc, PJ_FALSE, NULL);
|
||||
|
@ -940,6 +944,7 @@ static pj_status_t pjsua_regc_init(int acc_id)
|
|||
if (acc->regc) {
|
||||
pjsip_regc_destroy(acc->regc);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
}
|
||||
|
||||
/* initialize SIP registration if registrar is configured */
|
||||
|
@ -986,6 +991,7 @@ static pj_status_t pjsua_regc_init(int acc_id)
|
|||
pjsip_regc_destroy(acc->regc);
|
||||
pj_pool_release(pool);
|
||||
acc->regc = NULL;
|
||||
acc->contact.slen = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -405,13 +405,20 @@ PJ_DEF(pj_status_t) pjsua_call_make_call( pjsua_acc_id acc_id,
|
|||
/* Reset first response time */
|
||||
call->res_time.sec = 0;
|
||||
|
||||
/* Create suitable Contact header */
|
||||
status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
|
||||
acc_id, dest_uri);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
|
||||
PJSUA_UNLOCK();
|
||||
return status;
|
||||
/* Create suitable Contact header unless a Contact header has been
|
||||
* set in the account.
|
||||
*/
|
||||
if (acc->contact.slen) {
|
||||
contact = acc->contact;
|
||||
} else {
|
||||
status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
|
||||
acc_id, dest_uri);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header",
|
||||
status);
|
||||
PJSUA_UNLOCK();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create outgoing dialog: */
|
||||
|
@ -787,15 +794,20 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
|
|||
|
||||
|
||||
/* Get suitable Contact header */
|
||||
status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,
|
||||
acc_id, rdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
|
||||
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
|
||||
NULL, NULL);
|
||||
pjsua_media_channel_deinit(call->index);
|
||||
PJSUA_UNLOCK();
|
||||
return PJ_TRUE;
|
||||
if (pjsua_var.acc[acc_id].contact.slen) {
|
||||
contact = pjsua_var.acc[acc_id].contact;
|
||||
} else {
|
||||
status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,
|
||||
acc_id, rdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header",
|
||||
status);
|
||||
pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
|
||||
NULL, NULL);
|
||||
pjsua_media_channel_deinit(call->index);
|
||||
PJSUA_UNLOCK();
|
||||
return PJ_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create dialog: */
|
||||
|
|
|
@ -113,7 +113,8 @@ PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool,
|
|||
pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
|
||||
pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain);
|
||||
pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host);
|
||||
pj_strdup_with_null(pool, &dst->stun_relay_host, &src->stun_relay_host);
|
||||
pj_strdup_with_null(pool, &dst->turn_host, &src->turn_host);
|
||||
pj_stun_auth_cred_dup(pool, &dst->turn_cred, &src->turn_cred);
|
||||
}
|
||||
|
||||
PJ_DEF(void) pjsua_msg_data_init(pjsua_msg_data *msg_data)
|
||||
|
|
|
@ -624,6 +624,7 @@ static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
|
|||
{
|
||||
unsigned i;
|
||||
pj_sockaddr_in addr;
|
||||
pj_ice_strans_cfg ice_cfg;
|
||||
pj_status_t status;
|
||||
|
||||
/* Make sure STUN server resolution has completed */
|
||||
|
@ -635,25 +636,65 @@ static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
|
|||
|
||||
pj_sockaddr_in_init(&addr, 0, (pj_uint16_t)cfg->port);
|
||||
|
||||
/* Init ICE config */
|
||||
pj_bzero(&ice_cfg, sizeof(ice_cfg));
|
||||
|
||||
/* Duplicate STUN config */
|
||||
pj_memcpy(&ice_cfg.stun_cfg, &pjsua_var.stun_cfg, sizeof(pj_stun_config));
|
||||
|
||||
/* Set STUN server, if any */
|
||||
if (pj_sockaddr_has_addr(&pjsua_var.stun_srv))
|
||||
pj_sockaddr_cp(&ice_cfg.stun_srv, &pjsua_var.stun_srv);
|
||||
|
||||
if (pjsua_var.ua_cfg.turn_host.slen) {
|
||||
/* Set TURN server.
|
||||
* TODO: DNS SRV
|
||||
*/
|
||||
status = pj_sockaddr_in_init(&ice_cfg.turn_srv.ipv4,
|
||||
&pjsua_var.ua_cfg.turn_host,
|
||||
pjsua_var.ua_cfg.turn_port);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error resolving TURN server", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Copy TURN credential */
|
||||
pj_memcpy(&ice_cfg.turn_cred, &pjsua_var.ua_cfg.turn_cred,
|
||||
sizeof(pjsua_var.ua_cfg.turn_cred));
|
||||
|
||||
/* TURN connection type. */
|
||||
if (pjsua_var.ua_cfg.turn_tcp)
|
||||
ice_cfg.turn_conn_type = PJ_TURN_TP_TCP;
|
||||
else
|
||||
ice_cfg.turn_conn_type = PJ_TURN_TP_UDP;
|
||||
}
|
||||
|
||||
/* Create each media transport */
|
||||
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
|
||||
pj_ice_strans_comp comp;
|
||||
pjmedia_ice_cb ice_cb;
|
||||
int next_port;
|
||||
char name[32];
|
||||
#if PJMEDIA_ADVERTISE_RTCP
|
||||
enum { COMP_CNT=2 };
|
||||
unsigned options, comp_cnt;
|
||||
|
||||
#if PJMEDIA_ADVERTISE_RTCP==0
|
||||
comp_cnt = 1;
|
||||
#else
|
||||
enum { COMP_CNT=1 };
|
||||
if (pjsua_var.media_cfg.ice_no_rtcp)
|
||||
comp_cnt = 1;
|
||||
else
|
||||
comp_cnt = 2;
|
||||
#endif
|
||||
|
||||
options = pjsua_var.media_cfg.ice_options;
|
||||
|
||||
pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
|
||||
ice_cb.on_ice_complete = &on_ice_complete;
|
||||
|
||||
pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i);
|
||||
|
||||
status = pjmedia_ice_create(pjsua_var.med_endpt, name, COMP_CNT,
|
||||
&pjsua_var.stun_cfg, &ice_cb,
|
||||
status = pjmedia_ice_create(pjsua_var.med_endpt, name, comp_cnt,
|
||||
&ice_cfg, &ice_cb,
|
||||
&pjsua_var.calls[i].med_tp);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to create ICE media transport",
|
||||
|
@ -669,8 +710,8 @@ static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
|
|||
PJMEDIA_DIR_DECODING,
|
||||
pjsua_var.media_cfg.rx_drop_pct);
|
||||
|
||||
status = pjmedia_ice_start_init(pjsua_var.calls[i].med_tp, 0, &addr,
|
||||
&pjsua_var.stun_srv.ipv4, NULL);
|
||||
status = pjmedia_ice_start_init(pjsua_var.calls[i].med_tp, options,
|
||||
&addr);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Error starting ICE transport",
|
||||
status);
|
||||
|
|
|
@ -552,12 +552,17 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
|
|||
acc_id));
|
||||
|
||||
/* Create suitable Contact header */
|
||||
status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,
|
||||
acc_id, rdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
|
||||
PJSUA_UNLOCK();
|
||||
return PJ_TRUE;
|
||||
if (acc->contact.slen) {
|
||||
contact = acc->contact;
|
||||
} else {
|
||||
status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact,
|
||||
acc_id, rdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header",
|
||||
status);
|
||||
PJSUA_UNLOCK();
|
||||
return PJ_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create UAS dialog: */
|
||||
|
@ -1123,12 +1128,19 @@ static void subscribe_buddy_presence(unsigned index)
|
|||
PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription",
|
||||
acc_id, index));
|
||||
|
||||
/* Generate suitable Contact header */
|
||||
status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
|
||||
acc_id, &buddy->uri);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
|
||||
return;
|
||||
/* Generate suitable Contact header unless one is already set in
|
||||
* the account
|
||||
*/
|
||||
if (acc->contact.slen) {
|
||||
contact = acc->contact;
|
||||
} else {
|
||||
status = pjsua_acc_create_uac_contact(pjsua_var.pool, &contact,
|
||||
acc_id, &buddy->uri);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to generate Contact header",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create UAC dialog */
|
||||
|
|
Loading…
Reference in New Issue