From 57921286f7577dd670b905f85a4ef0271cfb2028 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 23 Mar 2007 19:09:54 +0000 Subject: ICE (work in progress): implemented server reflexive candidate git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1099 74dad513-b988-da41-8d7b-12977e46ad98 --- pjnath/include/pjnath/errno.h | 5 + pjnath/include/pjnath/ice_stream_transport.h | 26 ++-- pjnath/src/pjnath/ice.c | 13 +- pjnath/src/pjnath/ice_stream_transport.c | 215 +++++++++++++++++++++++---- pjnath/src/pjnath/stun_session.c | 16 +- 5 files changed, 221 insertions(+), 54 deletions(-) (limited to 'pjnath') diff --git a/pjnath/include/pjnath/errno.h b/pjnath/include/pjnath/errno.h index 9f45bc86..7fbd9837 100644 --- a/pjnath/include/pjnath/errno.h +++ b/pjnath/include/pjnath/errno.h @@ -133,6 +133,11 @@ * STUN transaction terminates with failure. */ #define PJNATH_ESTUNTSXFAILED (PJNATH_ERRNO_START+126)/* 370126 */ +/** + * @hideinitializer + * STUN mapped address attribute not found + */ +#define PJNATH_ESTUNNOMAPPEDADDR (PJNATH_ERRNO_START+127)/* 370127 */ //#define PJ_STATUS_FROM_STUN_CODE(code) (PJNATH_ERRNO_START+code) diff --git a/pjnath/include/pjnath/ice_stream_transport.h b/pjnath/include/pjnath/ice_stream_transport.h index 37ff5686..59207324 100644 --- a/pjnath/include/pjnath/ice_stream_transport.h +++ b/pjnath/include/pjnath/ice_stream_transport.h @@ -48,13 +48,6 @@ typedef struct pj_ice_st_cb void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len); - - void (*on_stun_srv_resolved)(pj_ice_st *ice_st, - pj_status_t status); - void (*on_interface_status)(pj_ice_st *ice_st, - void *notify_data, - pj_status_t status, - int itf_id); void (*on_ice_complete)(pj_ice_st *ice_st, pj_status_t status); @@ -85,6 +78,7 @@ typedef struct pj_ice_st_interface pj_ioqueue_op_key_t write_op; pj_sockaddr src_addr; int src_addr_len; + pj_stun_session *stun_sess; } pj_ice_st_interface; @@ -133,19 +127,14 @@ PJ_DECL(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, unsigned comp_id, pj_uint16_t local_pref, const pj_sockaddr_in *addr, - unsigned *p_itf_id, - pj_bool_t notify, - void *notify_data); + unsigned *p_itf_id); PJ_DECL(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, unsigned comp_id, - unsigned port, - pj_bool_t notify, - void *notify_data); + unsigned port); PJ_DECL(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st, unsigned comp_id, unsigned local_port, - pj_bool_t notify, - void *notify_data); + unsigned *p_itf_id); PJ_DECL(pj_status_t) pj_ice_st_add_relay_interface(pj_ice_st *ice_st, unsigned comp_id, unsigned local_port, @@ -171,6 +160,13 @@ PJ_DECL(pj_status_t) pj_ice_st_send_data(pj_ice_st *ice_st, unsigned comp_id, const void *data, pj_size_t data_len); +PJ_DECL(pj_status_t) pj_ice_st_sendto(pj_ice_st *ice_st, + unsigned comp_id, + unsigned itf_id, + const void *data, + pj_size_t data_len, + const pj_sockaddr_t *dst_addr, + int dst_addr_len); /** diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c index d2d2474d..9ab50262 100644 --- a/pjnath/src/pjnath/ice.c +++ b/pjnath/src/pjnath/ice.c @@ -56,11 +56,6 @@ static const char *clist_state_name[] = "Completed" }; -const pj_str_t host_foundation = {"host", 4}; -const pj_str_t mapped_foundation = {"srfx", 4}; -const pj_str_t relayed_foundation = {"rlyd", 4}; -const pj_str_t peer_mapped_foundation = {"peer", 4}; - #define CHECK_NAME_LEN 128 #define LOG(expr) PJ_LOG(4,expr) #define GET_LCAND_ID(cand) (cand - ice->lcand) @@ -1431,11 +1426,17 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, if (i == ice->lcand_cnt) { unsigned cand_id; + char buf[32]; + pj_str_t foundation; + + pj_ansi_snprintf(buf, sizeof(buf), "P%x", + lcand->base_addr.ipv4.sin_addr.s_addr); + foundation = pj_str(buf); /* Add new peer reflexive candidate */ status = pj_ice_add_cand(ice, lcand->comp_id, PJ_ICE_CAND_TYPE_PRFLX, - 65535, &peer_mapped_foundation, + 65535, &foundation, &xaddr->sockaddr, &lcand->base_addr, NULL, sizeof(pj_sockaddr_in), &cand_id); if (status != PJ_SUCCESS) { diff --git a/pjnath/src/pjnath/ice_stream_transport.c b/pjnath/src/pjnath/ice_stream_transport.c index e654fcf7..1462ff25 100644 --- a/pjnath/src/pjnath/ice_stream_transport.c +++ b/pjnath/src/pjnath/ice_stream_transport.c @@ -47,6 +47,18 @@ static void on_read_complete(pj_ioqueue_key_t *key, static void destroy_ice_interface(pj_ice_st_interface *is); static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason); +/* STUN session callback */ +static pj_status_t stun_on_send_msg(pj_stun_session *sess, + const void *pkt, + pj_size_t pkt_size, + const pj_sockaddr_t *dst_addr, + unsigned addr_len); +static void stun_on_request_complete(pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *tdata, + const pj_stun_msg *response); + +/* Utility: print error */ static void ice_st_perror(pj_ice_st *ice_st, const char *title, pj_status_t status) { @@ -160,6 +172,7 @@ static void on_read_complete(pj_ioqueue_key_t *key, { pj_ice_st_interface *is = (pj_ice_st_interface*) pj_ioqueue_get_user_data(key); + pj_ice_st *ice_st = is->ice_st; pj_ssize_t pkt_size; pj_status_t status; @@ -168,11 +181,29 @@ static void on_read_complete(pj_ioqueue_key_t *key, /* If we have an active ICE session, hand over all incoming * packets to the ICE session. Otherwise just drop the packet. */ - if (is->ice_st->ice) { - status = pj_ice_on_rx_pkt(is->ice_st->ice, + if (ice_st->ice) { + status = pj_ice_on_rx_pkt(ice_st->ice, is->comp_id, is->cand_id, is->pkt, bytes_read, &is->src_addr, is->src_addr_len); + } else if (is->stun_sess) { + status = pj_stun_msg_check(is->pkt, bytes_read, PJ_STUN_IS_DATAGRAM); + if (status == PJ_SUCCESS) { + status = pj_stun_session_on_rx_pkt(is->stun_sess, is->pkt, + bytes_read, + PJ_STUN_IS_DATAGRAM, NULL, + &is->src_addr, + is->src_addr_len); + } else { + (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id, + is->pkt, bytes_read, + &is->src_addr, is->src_addr_len); + + } + } else { + (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id, + is->pkt, bytes_read, + &is->src_addr, is->src_addr_len); } } else if (bytes_read < 0) { @@ -195,6 +226,11 @@ static void on_read_complete(pj_ioqueue_key_t *key, */ static void destroy_ice_interface(pj_ice_st_interface *is) { + if (is->stun_sess) { + pj_stun_session_destroy(is->stun_sess); + is->stun_sess = NULL; + } + if (is->key) { pj_ioqueue_unregister(is->key); is->key = NULL; @@ -344,8 +380,7 @@ PJ_DEF(pj_status_t) pj_ice_st_add_comp(pj_ice_st *ice_st, /* Add interface */ static void add_interface(pj_ice_st *ice_st, pj_ice_st_interface *is, - unsigned *p_itf_id, pj_bool_t notify, - void *notify_data) + unsigned *p_itf_id) { unsigned itf_id; @@ -354,11 +389,6 @@ static void add_interface(pj_ice_st *ice_st, pj_ice_st_interface *is, if (p_itf_id) *p_itf_id = itf_id; - - if (notify && ice_st->cb.on_interface_status) { - (*ice_st->cb.on_interface_status)(ice_st, notify_data, - PJ_SUCCESS, itf_id); - } } /* @@ -368,9 +398,7 @@ PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, unsigned comp_id, pj_uint16_t local_pref, const pj_sockaddr_in *addr, - unsigned *p_itf_id, - pj_bool_t notify, - void *notify_data) + unsigned *p_itf_id) { pj_ice_st_interface *is; pj_status_t status; @@ -394,7 +422,7 @@ PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, pj_memcpy(&is->addr, &is->base_addr, sizeof(is->addr)); /* Store this interface */ - add_interface(ice_st, is, p_itf_id, notify, notify_data); + add_interface(ice_st, is, p_itf_id); /* Set interface status to SUCCESS */ is->status = PJ_SUCCESS; @@ -407,9 +435,7 @@ PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, */ PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, unsigned comp_id, - unsigned port, - pj_bool_t notify, - void *notify_data) + unsigned port) { pj_sockaddr_in addr; pj_status_t status; @@ -423,8 +449,7 @@ PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, if (status != PJ_SUCCESS) return status; - return pj_ice_st_add_host_interface(ice_st, comp_id, 65535, &addr, - NULL, notify, notify_data); + return pj_ice_st_add_host_interface(ice_st, comp_id, 65535, &addr, NULL); } /* @@ -433,16 +458,61 @@ PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, PJ_DEF(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st, unsigned comp_id, unsigned local_port, - pj_bool_t notify, - void *notify_data) + unsigned *p_itf_id) { - /* Yeah, TODO */ - PJ_UNUSED_ARG(ice_st); - PJ_UNUSED_ARG(comp_id); - PJ_UNUSED_ARG(local_port); - PJ_UNUSED_ARG(notify); - PJ_UNUSED_ARG(notify_data); - return -1; + pj_ice_st_interface *is; + pj_sockaddr_in local_addr; + pj_stun_session_cb sess_cb; + pj_stun_tx_data *tdata; + pj_status_t status; + + PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); + + /* STUN server must have been configured */ + PJ_ASSERT_RETURN(ice_st->stun_srv.sin_family != 0, PJ_EINVALIDOP); + + + /* Create interface */ + pj_sockaddr_in_init(&local_addr, NULL, (pj_uint16_t)local_port); + status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_SRFLX, comp_id, + 65535, &local_addr, &is); + if (status != PJ_SUCCESS) + return status; + + /* Create STUN session */ + 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, + &sess_cb, PJ_FALSE, &is->stun_sess); + if (status != PJ_SUCCESS) + goto on_error; + + /* Associate interface with STUN session */ + pj_stun_session_set_user_data(is->stun_sess, (void*)is); + + /* Create and send STUN binding request */ + status = pj_stun_session_create_req(is->stun_sess, + PJ_STUN_BINDING_REQUEST, &tdata); + if (status != PJ_SUCCESS) + goto on_error; + + status = pj_stun_session_send_msg(is->stun_sess, PJ_FALSE, + &ice_st->stun_srv, + sizeof(pj_sockaddr_in), tdata); + if (status != PJ_SUCCESS) + goto on_error; + + /* Mark interface as pending */ + is->status = PJ_EPENDING; + + add_interface(ice_st, is, p_itf_id); + + return PJ_SUCCESS; + +on_error: + destroy_ice_interface(is); + return status; } /* @@ -623,6 +693,29 @@ PJ_DEF(pj_status_t) pj_ice_st_send_data( pj_ice_st *ice_st, return pj_ice_send_data(ice_st->ice, comp_id, data, data_len); } +/* + * Send packet using non-ICE means (e.g. when ICE was not negotiated). + */ +PJ_DEF(pj_status_t) pj_ice_st_sendto( pj_ice_st *ice_st, + unsigned comp_id, + unsigned itf_id, + const void *data, + pj_size_t data_len, + const pj_sockaddr_t *dst_addr, + int dst_addr_len) +{ + pj_ssize_t pkt_size; + pj_ice_st_interface *is = ice_st->itfs[itf_id]; + pj_status_t status; + + pkt_size = data_len; + status = pj_ioqueue_sendto(is->key, &is->write_op, + data, &pkt_size, 0, + dst_addr, dst_addr_len); + + return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; +} + /* * Callback called by ICE session when ICE processing is complete, either * successfully or with failure. @@ -687,4 +780,72 @@ static void on_rx_data(pj_ice *ice, } } +/* + * Callback called by STUN session to send outgoing packet. + */ +static pj_status_t stun_on_send_msg(pj_stun_session *sess, + const void *pkt, + pj_size_t size, + const pj_sockaddr_t *dst_addr, + unsigned dst_addr_len) +{ + pj_ice_st_interface *is; + pj_ssize_t pkt_size; + pj_status_t status; + + is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess); + pkt_size = size; + status = pj_ioqueue_sendto(is->key, &is->write_op, + pkt, &pkt_size, 0, + dst_addr, dst_addr_len); + + return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; +} + +/* + * Callback sent by STUN session when outgoing STUN request has + * completed. + */ +static void stun_on_request_complete(pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *tdata, + const pj_stun_msg *response) +{ + pj_ice_st_interface *is; + pj_stun_xor_mapped_addr_attr *xa; + pj_stun_mapped_addr_attr *ma; + pj_sockaddr *mapped_addr; + + PJ_UNUSED_ARG(tdata); + + is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess); + if (status != PJ_SUCCESS) { + is->status = status; + ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); + return; + } + + xa = (pj_stun_xor_mapped_addr_attr*) + pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0); + ma = (pj_stun_mapped_addr_attr*) + pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0); + + if (xa) + mapped_addr = &xa->sockaddr; + else if (ma) + mapped_addr = &ma->sockaddr; + else { + is->status = PJNATH_ESTUNNOMAPPEDADDR; + ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); + return; + } + + PJ_LOG(4,(is->ice_st->obj_name, + "STUN mapped address: %s:%d", + pj_inet_ntoa(mapped_addr->ipv4.sin_addr), + (int)pj_ntohs(mapped_addr->ipv4.sin_port))); + pj_memcpy(&is->addr, mapped_addr, sizeof(pj_sockaddr_in)); + is->status = PJ_SUCCESS; + +} diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c index 44493120..1a048f2c 100644 --- a/pjnath/src/pjnath/stun_session.c +++ b/pjnath/src/pjnath/stun_session.c @@ -280,10 +280,12 @@ static pj_status_t apply_msg_options(pj_stun_session *sess, /* Create and add USERNAME attribute */ - status = pj_stun_msg_add_string_attr(pool, msg, - PJ_STUN_ATTR_USERNAME, - &username); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + if (username.slen) { + status = pj_stun_msg_add_string_attr(pool, msg, + PJ_STUN_ATTR_USERNAME, + &username); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + } /* Add REALM only when long term credential is used */ if (realm.slen) { @@ -301,8 +303,10 @@ static pj_status_t apply_msg_options(pj_stun_session *sess, } /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_add_msgint_attr(pool, msg); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + if (username.slen) { + status = pj_stun_msg_add_msgint_attr(pool, msg); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + } /* Add FINGERPRINT attribute if necessary */ -- cgit v1.2.3