From 320ebe471866fd5c1ca2406e28aaa1fdce7695ef Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Thu, 1 Mar 2007 00:08:27 +0000 Subject: More work on STUN session framework git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1021 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/src/pjlib-util/stun_msg.c | 76 +++-- pjlib-util/src/pjlib-util/stun_session.c | 444 +++++++++++++++++++-------- pjlib-util/src/pjstun-srv-test/server.h | 61 ---- pjlib-util/src/pjstun-srv-test/server_main.c | 324 ++++++++++--------- 4 files changed, 529 insertions(+), 376 deletions(-) delete mode 100644 pjlib-util/src/pjstun-srv-test/server.h (limited to 'pjlib-util/src') diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c index 47d70dc0..e8153e10 100644 --- a/pjlib-util/src/pjlib-util/stun_msg.c +++ b/pjlib-util/src/pjlib-util/stun_msg.c @@ -517,8 +517,8 @@ PJ_DEF(pj_status_t) pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool, int attr_type, pj_bool_t xor_ed, - unsigned addr_len, const pj_sockaddr_t *addr, + unsigned addr_len, pj_stun_generic_ip_addr_attr **p_attr) { pj_stun_generic_ip_addr_attr *attr; @@ -559,14 +559,14 @@ pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool, pj_stun_msg *msg, int attr_type, pj_bool_t xor_ed, - unsigned addr_len, - const pj_sockaddr_t *addr) + const pj_sockaddr_t *addr, + unsigned addr_len) { pj_stun_generic_ip_addr_attr *attr; pj_status_t status; status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed, - addr_len, addr, &attr); + addr, addr_len, &attr); if (status != PJ_SUCCESS) return status; @@ -1434,17 +1434,15 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg, PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos) { - pj_uint16_t val = (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); - return pj_ntohs(val); + return (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); } PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos) { - pj_uint32_t val = (pdu[pos+0] << 24) + - (pdu[pos+1] << 16) + - (pdu[pos+2] << 8) + - (pdu[pos+3]); - return pj_ntohl(val); + return (pdu[pos+0] << 24) + + (pdu[pos+1] << 16) + + (pdu[pos+2] << 8) + + (pdu[pos+3]); } @@ -1465,34 +1463,34 @@ PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len, if (*pdu != 0x00 && *pdu != 0x01) return PJLIB_UTIL_ESTUNINMSGTYPE; - /* If magic is set, then there is great possibility that this is - * a STUN message. - */ - if (GET_VAL32(pdu, 4) != PJ_STUN_MAGIC) - return PJLIB_UTIL_ESTUNNOTMAGIC; - /* Check the PDU length */ msg_len = GET_VAL16(pdu, 2); - if ((msg_len > pdu_len) || - ((options & PJ_STUN_IS_DATAGRAM) && msg_len != pdu_len)) + if ((msg_len + 20 > pdu_len) || + ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len)) { return PJLIB_UTIL_ESTUNINMSGLEN; } - /* Check if FINGERPRINT attribute is present */ - if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) { - pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22); - pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24); - pj_uint32_t crc; + /* If magic is set, then there is great possibility that this is + * a STUN message. + */ + if (GET_VAL32(pdu, 4) == PJ_STUN_MAGIC) { + + /* Check if FINGERPRINT attribute is present */ + if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) { + pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22); + pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24); + pj_uint32_t crc; - if (attr_len != 4) - return PJLIB_UTIL_ESTUNINATTRLEN; + if (attr_len != 4) + return PJLIB_UTIL_ESTUNINATTRLEN; - crc = pj_crc32_calc(pdu, msg_len + 20); - crc ^= STUN_XOR_FINGERPRINT; + crc = pj_crc32_calc(pdu, msg_len + 20); + crc ^= STUN_XOR_FINGERPRINT; - if (crc != fingerprint) - return PJLIB_UTIL_ESTUNFINGERPRINT; + if (crc != fingerprint) + return PJLIB_UTIL_ESTUNFINGERPRINT; + } } /* Could be a STUN message */ @@ -1819,7 +1817,7 @@ static void calc_md5_key(pj_uint8_t digest[16], /* * Print the message structure to a buffer. */ -PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, +PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, pj_uint8_t *buf, unsigned buf_size, unsigned options, const pj_str_t *password, @@ -1833,7 +1831,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, pj_stun_fingerprint_attr *afingerprint = NULL; unsigned printed; pj_status_t status; - unsigned i, length; + unsigned i; PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL); @@ -1898,18 +1896,18 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, * Note that length is not including the 20 bytes header. */ if (amsg_integrity && afingerprint) { - length = (pj_uint16_t)((buf - start) - 20 + 24 + 8); + msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24 + 8); } else if (amsg_integrity) { - length = (pj_uint16_t)((buf - start) - 20 + 24); + msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24); } else if (afingerprint) { - length = (pj_uint16_t)((buf - start) - 20 + 8); + msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 8); } else { - length = (pj_uint16_t)((buf - start) - 20); + msg->hdr.length = (pj_uint16_t)((buf - start) - 20); } /* hdr->length = pj_htons(length); */ - *(buf+2) = (pj_uint8_t)((length >> 8) & 0x00FF); - *(buf+3) = (pj_uint8_t)(length & 0x00FF); + start[2] = (pj_uint8_t)((msg->hdr.length >> 8) & 0x00FF); + start[3] = (pj_uint8_t)(msg->hdr.length & 0x00FF); /* Calculate message integrity, if present */ if (amsg_integrity != NULL) { @@ -2088,7 +2086,7 @@ PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_uint8_t *pkt, if (p_response) *p_response = NULL; - if (PJ_STUN_IS_REQUEST(msg->hdr.type)) + if (!PJ_STUN_IS_REQUEST(msg->hdr.type)) p_response = NULL; /* Get realm and nonce */ diff --git a/pjlib-util/src/pjlib-util/stun_session.c b/pjlib-util/src/pjlib-util/stun_session.c index ce15a610..579f0aca 100644 --- a/pjlib-util/src/pjlib-util/stun_session.c +++ b/pjlib-util/src/pjlib-util/stun_session.c @@ -23,6 +23,7 @@ struct pj_stun_session { pj_stun_endpoint *endpt; pj_pool_t *pool; + pj_mutex_t *mutex; pj_stun_session_cb cb; void *user_data; @@ -47,7 +48,7 @@ struct pj_stun_session #endif #if PJ_LOG_MAX_LEVEL >= 4 -# define LOG_ERR_(sess, title, rc) +# define LOG_ERR_(sess, title, rc) stun_perror(sess, title, rc) static void stun_perror(pj_stun_session *sess, const char *title, pj_status_t status) { @@ -59,7 +60,7 @@ static void stun_perror(pj_stun_session *sess, const char *title, } #else -# define ERR_(sess, title, rc) +# define LOG_ERR_(sess, title, rc) #endif #define TDATA_POOL_SIZE 1024 @@ -115,12 +116,10 @@ static pj_stun_tx_data* tsx_lookup(pj_stun_session *sess, } static pj_status_t create_tdata(pj_stun_session *sess, - unsigned msg_type, void *user_data, pj_stun_tx_data **p_tdata) { pj_pool_t *pool; - pj_status_t status; pj_stun_tx_data *tdata; /* Create pool and initialize basic tdata attributes */ @@ -133,22 +132,35 @@ static pj_status_t create_tdata(pj_stun_session *sess, tdata->sess = sess; tdata->user_data = user_data; + *p_tdata = tdata; + + return PJ_SUCCESS; +} + +static pj_status_t create_request_tdata(pj_stun_session *sess, + unsigned msg_type, + void *user_data, + pj_stun_tx_data **p_tdata) +{ + pj_status_t status; + pj_stun_tx_data *tdata; + + status = create_tdata(sess, user_data, &tdata); + if (status != PJ_SUCCESS) + return status; + /* Create STUN message */ - status = pj_stun_msg_create(pool, msg_type, PJ_STUN_MAGIC, + status = pj_stun_msg_create(tdata->pool, msg_type, PJ_STUN_MAGIC, NULL, &tdata->msg); if (status != PJ_SUCCESS) { - pj_pool_release(pool); + pj_pool_release(tdata->pool); return status; } - /* If this is a request, then copy the request's transaction ID - * as the transaction key. - */ - if (PJ_STUN_IS_REQUEST(msg_type)) { - pj_assert(sizeof(tdata->client_key)==sizeof(tdata->msg->hdr.tsx_id)); - pj_memcpy(tdata->client_key, tdata->msg->hdr.tsx_id, - sizeof(tdata->msg->hdr.tsx_id)); - } + /* copy the request's transaction ID as the transaction key. */ + pj_assert(sizeof(tdata->client_key)==sizeof(tdata->msg->hdr.tsx_id)); + pj_memcpy(tdata->client_key, tdata->msg->hdr.tsx_id, + sizeof(tdata->msg->hdr.tsx_id)); *p_tdata = tdata; @@ -166,10 +178,21 @@ static void destroy_tdata(pj_stun_tx_data *tdata) pj_pool_release(tdata->pool); } -static pj_status_t session_apply_req(pj_stun_session *sess, +/* + * Destroy the transmit data. + */ +PJ_DEF(void) pj_stun_msg_destroy_tdata( pj_stun_session *sess, + pj_stun_tx_data *tdata) +{ + PJ_UNUSED_ARG(sess); + destroy_tdata(tdata); +} + +static pj_status_t apply_msg_options(pj_stun_session *sess, pj_pool_t *pool, unsigned options, - pj_stun_msg *msg) + pj_stun_msg *msg, + pj_str_t **p_passwd) { pj_status_t status; @@ -181,8 +204,10 @@ static pj_status_t session_apply_req(pj_stun_session *sess, pj_stun_msg_integrity_attr *amsgi; pj_stun_generic_string_attr *arealm; + *p_passwd = &sess->l_password; + /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(sess->pool, + status = pj_stun_generic_string_attr_create(pool, PJ_STUN_ATTR_USERNAME, &sess->l_username, &auname); @@ -192,7 +217,7 @@ static pj_status_t session_apply_req(pj_stun_session *sess, PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); /* Add REALM only when long term credential is used */ - status = pj_stun_generic_string_attr_create(sess->pool, + status = pj_stun_generic_string_attr_create(pool, PJ_STUN_ATTR_REALM, &sess->l_realm, &arealm); @@ -202,20 +227,20 @@ static pj_status_t session_apply_req(pj_stun_session *sess, PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi); + status = pj_stun_msg_integrity_attr_create(pool, &amsgi); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); status = pj_stun_msg_add_attr(msg, &amsgi->hdr); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - PJ_TODO(COMPUTE_MESSAGE_INTEGRITY1); - } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) { pj_stun_generic_string_attr *auname; pj_stun_msg_integrity_attr *amsgi; + *p_passwd = &sess->s_password; + /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(sess->pool, + status = pj_stun_generic_string_attr_create(pool, PJ_STUN_ATTR_USERNAME, &sess->s_username, &auname); @@ -225,20 +250,21 @@ static pj_status_t session_apply_req(pj_stun_session *sess, PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi); + status = pj_stun_msg_integrity_attr_create(pool, &amsgi); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); status = pj_stun_msg_add_attr(msg, &amsgi->hdr); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - PJ_TODO(COMPUTE_MESSAGE_INTEGRITY2); + } else { + *p_passwd = NULL; } /* Add FINGERPRINT attribute if necessary */ if (options & PJ_STUN_USE_FINGERPRINT) { pj_stun_fingerprint_attr *af; - status = pj_stun_generic_uint_attr_create(sess->pool, + status = pj_stun_generic_uint_attr_create(pool, PJ_STUN_ATTR_FINGERPRINT, 0, &af); PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); @@ -259,25 +285,9 @@ static void tsx_on_complete(pj_stun_client_tsx *tsx, tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); - switch (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)) { - case PJ_STUN_BINDING_METHOD: - tdata->sess->cb.on_bind_response(tdata->sess, status, tdata, response); - break; - case PJ_STUN_ALLOCATE_METHOD: - tdata->sess->cb.on_allocate_response(tdata->sess, status, - tdata, response); - break; - case PJ_STUN_SET_ACTIVE_DESTINATION_METHOD: - tdata->sess->cb.on_set_active_destination_response(tdata->sess, status, - tdata, response); - break; - case PJ_STUN_CONNECT_METHOD: - tdata->sess->cb.on_connect_response(tdata->sess, status, tdata, - response); - break; - default: - pj_assert(!"Unknown method"); - break; + if (tdata->sess->cb.on_request_complete) { + (*tdata->sess->cb.on_request_complete)(tdata->sess, status, tdata, + response); } } @@ -289,8 +299,8 @@ static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); - return tdata->sess->cb.on_send_msg(tdata, stun_pkt, pkt_size, - tdata->addr_len, tdata->dst_addr); + return tdata->sess->cb.on_send_msg(tdata->sess, stun_pkt, pkt_size, + tdata->dst_addr, tdata->addr_len); } /* **************************************************************************/ @@ -302,9 +312,13 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, { pj_pool_t *pool; pj_stun_session *sess; + pj_status_t status; PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL); + if (name==NULL) + name = "sess%p"; + pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); @@ -315,9 +329,13 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, pj_list_init(&sess->pending_request_list); - *p_sess = sess; + status = pj_mutex_create_recursive(pool, name, &sess->mutex); + if (status != PJ_SUCCESS) { + pj_pool_release(pool); + return status; + } - PJ_TODO(MUTEX_PROTECTION); + *p_sess = sess; return PJ_SUCCESS; } @@ -326,6 +344,7 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) { PJ_ASSERT_RETURN(sess, PJ_EINVAL); + pj_mutex_destroy(sess->mutex); pj_pool_release(sess->pool); return PJ_SUCCESS; @@ -336,7 +355,9 @@ PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess, void *user_data) { PJ_ASSERT_RETURN(sess, PJ_EINVAL); + pj_mutex_lock(sess->mutex); sess->user_data = user_data; + pj_mutex_unlock(sess->mutex); return PJ_SUCCESS; } @@ -355,9 +376,12 @@ pj_stun_session_set_long_term_credential(pj_stun_session *sess, pj_str_t nil = { NULL, 0 }; PJ_ASSERT_RETURN(sess, PJ_EINVAL); + + pj_mutex_lock(sess->mutex); pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil); pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil); pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil); + pj_mutex_unlock(sess->mutex); return PJ_SUCCESS; } @@ -371,8 +395,11 @@ pj_stun_session_set_short_term_credential(pj_stun_session *sess, pj_str_t nil = { NULL, 0 }; PJ_ASSERT_RETURN(sess, PJ_EINVAL); + + pj_mutex_lock(sess->mutex); pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); + pj_mutex_unlock(sess->mutex); return PJ_SUCCESS; } @@ -386,7 +413,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); - status = create_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, &tdata); + status = create_request_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, + &tdata); if (status != PJ_SUCCESS) return status; @@ -397,6 +425,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, PJ_DEF(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } @@ -405,12 +435,16 @@ PJ_DEF(pj_status_t) pj_stun_session_create_set_active_destination_req(pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } PJ_DEF(pj_status_t) pj_stun_session_create_connect_req( pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } @@ -418,27 +452,102 @@ PJ_DEF(pj_status_t) pj_stun_session_create_connection_status_ind(pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } PJ_DEF(pj_status_t) pj_stun_session_create_send_ind( pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } PJ_DEF(pj_status_t) pj_stun_session_create_data_ind( pj_stun_session *sess, pj_stun_tx_data **p_tdata) { + PJ_UNUSED_ARG(sess); + PJ_UNUSED_ARG(p_tdata); PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); } + +/* + * Create a STUN response message. + */ +PJ_DEF(pj_status_t) pj_stun_session_create_response( pj_stun_session *sess, + const pj_stun_msg *req, + unsigned err_code, + const pj_str_t *err_msg, + pj_stun_tx_data **p_tdata) +{ + pj_status_t status; + pj_stun_tx_data *tdata; + + status = create_tdata(sess, NULL, &tdata); + if (status != PJ_SUCCESS) + return status; + + /* Create STUN response message */ + status = pj_stun_msg_create_response(tdata->pool, req, err_code, err_msg, + &tdata->msg); + if (status != PJ_SUCCESS) { + pj_pool_release(tdata->pool); + return status; + } + + /* copy the request's transaction ID as the transaction key. */ + pj_assert(sizeof(tdata->client_key)==sizeof(req->hdr.tsx_id)); + pj_memcpy(tdata->client_key, req->hdr.tsx_id, sizeof(req->hdr.tsx_id)); + + *p_tdata = tdata; + + return PJ_SUCCESS; +} + + +/* Print outgoing message to log */ +static void dump_tx_msg(pj_stun_session *sess, const pj_stun_msg *msg, + unsigned pkt_size, const pj_sockaddr_t *addr) +{ + const char *dst_name; + int dst_port; + const pj_sockaddr *dst = (const pj_sockaddr*)addr; + char buf[512]; + + if (dst->sa_family == PJ_AF_INET) { + const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst; + dst_name = pj_inet_ntoa(dst4->sin_addr); + dst_port = pj_ntohs(dst4->sin_port); + } else if (dst->sa_family == PJ_AF_INET6) { + const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst; + dst_name = "IPv6"; + dst_port = pj_ntohs(dst6->sin6_port); + } else { + LOG_ERR_(sess, "Invalid address family", PJ_EINVAL); + return; + } + + PJ_LOG(5,(SNAME(sess), + "TX %d bytes STUN message to %s:%d:\n" + "--- begin STUN message ---\n" + "%s" + "--- end of STUN message ---\n", + pkt_size, dst_name, dst_port, + pj_stun_msg_dump(msg, buf, sizeof(buf), NULL))); + +} + + PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, unsigned options, - unsigned addr_len, const pj_sockaddr_t *server, + unsigned addr_len, pj_stun_tx_data *tdata) { + pj_str_t *password; pj_status_t status; PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); @@ -447,39 +556,16 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, tdata->max_len = PJ_STUN_MAX_PKT_LEN; tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len); - if (PJ_LOG_MAX_LEVEL >= 5) { - char *buf = (char*) tdata->pkt; - const char *dst_name; - int dst_port; - const pj_sockaddr *dst = (const pj_sockaddr*)server; - - if (dst->sa_family == PJ_AF_INET) { - const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst; - dst_name = pj_inet_ntoa(dst4->sin_addr); - dst_port = pj_ntohs(dst4->sin_port); - } else if (dst->sa_family == PJ_AF_INET6) { - const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst; - dst_name = "IPv6"; - dst_port = pj_ntohs(dst6->sin6_port); - } else { - LOG_ERR_(sess, "Invalid address family", PJ_EINVAL); - return PJ_EINVAL; - } - - PJ_LOG(5,(SNAME(sess), - "Sending STUN message to %s:%d:\n" - "--- begin STUN message ---\n" - "%s" - "--- end of STUN message ---\n", - dst_name, dst_port, - pj_stun_msg_dump(tdata->msg, buf, tdata->max_len, NULL))); - } + /* Start locking the session now */ + pj_mutex_lock(sess->mutex); /* Apply options */ - status = session_apply_req(sess, tdata->pool, options, tdata->msg); + status = apply_msg_options(sess, tdata->pool, options, + tdata->msg, &password); if (status != PJ_SUCCESS) { + pj_stun_msg_destroy_tdata(sess, tdata); + pj_mutex_unlock(sess->mutex); LOG_ERR_(sess, "Error applying options", status); - destroy_tdata(tdata); return status; } @@ -487,11 +573,15 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, 0, NULL, &tdata->pkt_size); if (status != PJ_SUCCESS) { + pj_stun_msg_destroy_tdata(sess, tdata); + pj_mutex_unlock(sess->mutex); LOG_ERR_(sess, "STUN encode() error", status); - destroy_tdata(tdata); return status; } + /* Dump packet */ + dump_tx_msg(sess, tdata->msg, tdata->pkt_size, server); + /* If this is a STUN request message, then send the request with * a new STUN client transaction. */ @@ -511,8 +601,9 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE, tdata->pkt, tdata->pkt_size); if (status != PJ_SUCCESS && status != PJ_EPENDING) { + pj_stun_msg_destroy_tdata(sess, tdata); + pj_mutex_unlock(sess->mutex); LOG_ERR_(sess, "Error sending STUN request", status); - destroy_tdata(tdata); return status; } @@ -521,25 +612,151 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, } else { /* Otherwise for non-request message, send directly to transport. */ - status = sess->cb.on_send_msg(tdata, tdata->pkt, tdata->pkt_size, - addr_len, server); + status = sess->cb.on_send_msg(sess, tdata->pkt, tdata->pkt_size, + server, addr_len); if (status != PJ_SUCCESS && status != PJ_EPENDING) { LOG_ERR_(sess, "Error sending STUN request", status); - destroy_tdata(tdata); - return status; } + + /* Destroy */ + pj_stun_msg_destroy_tdata(sess, tdata); } + pj_mutex_unlock(sess->mutex); return status; } +/* Handle incoming response */ +static pj_status_t on_incoming_response(pj_stun_session *sess, + pj_stun_msg *msg) +{ + pj_stun_tx_data *tdata; + pj_status_t status; + + /* Lookup pending client transaction */ + tdata = tsx_lookup(sess, msg); + if (tdata == NULL) { + LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND); + return PJ_ENOTFOUND; + } + + /* Pass the response to the transaction. + * If the message is accepted, transaction callback will be called, + * and this will call the session callback too. + */ + status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg); + if (status != PJ_SUCCESS) { + return status; + } + + /* If transaction has completed, destroy the transmit data. + * This will remove the transaction from the pending list too. + */ + if (pj_stun_client_tsx_is_complete(tdata->client_tsx)) { + pj_stun_msg_destroy_tdata(sess, tdata); + tdata = NULL; + } + + return PJ_SUCCESS; +} + + +/* Send response */ +static pj_status_t send_response(pj_stun_session *sess, unsigned options, + pj_pool_t *pool, pj_stun_msg *response, + const pj_sockaddr_t *addr, unsigned addr_len) +{ + pj_uint8_t *out_pkt; + unsigned out_max_len, out_len; + pj_str_t *passwd; + pj_status_t status; + + /* Alloc packet buffer */ + out_max_len = PJ_STUN_MAX_PKT_LEN; + out_pkt = pj_pool_alloc(pool, out_max_len); + + /* Apply options */ + apply_msg_options(sess, pool, options, response, &passwd); + + /* Encode */ + status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0, + passwd, &out_len); + if (status != PJ_SUCCESS) { + LOG_ERR_(sess, "Error encoding message", status); + return status; + } + + /* Print log */ + dump_tx_msg(sess, response, out_len, addr); + + /* Send packet */ + status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); + + return status; +} + +/* Handle incoming request */ +static pj_status_t on_incoming_request(pj_stun_session *sess, + pj_pool_t *tmp_pool, + const pj_uint8_t *in_pkt, + unsigned in_pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + pj_status_t status; + + /* Distribute to handler, or respond with Bad Request */ + if (sess->cb.on_rx_request) { + status = (*sess->cb.on_rx_request)(sess, in_pkt, in_pkt_len, msg, + src_addr, src_addr_len); + } else { + pj_stun_msg *response = NULL; + + status = pj_stun_msg_create_response(tmp_pool, msg, + PJ_STUN_STATUS_BAD_REQUEST, NULL, + &response); + if (status == PJ_SUCCESS && response) { + status = send_response(sess, 0, tmp_pool, response, + src_addr, src_addr_len); + } + } + + return status; +} + + +/* Handle incoming indication */ +static pj_status_t on_incoming_indication(pj_stun_session *sess, + pj_pool_t *tmp_pool, + const pj_uint8_t *in_pkt, + unsigned in_pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + PJ_UNUSED_ARG(tmp_pool); + + /* Distribute to handler */ + if (sess->cb.on_rx_indication) { + return (*sess->cb.on_rx_indication)(sess, in_pkt, in_pkt_len, msg, + src_addr, src_addr_len); + } else { + return PJ_SUCCESS; + } +} + + PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, const void *packet, pj_size_t pkt_size, - unsigned *parsed_len) + unsigned options, + unsigned *parsed_len, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) { pj_stun_msg *msg, *response; pj_pool_t *tmp_pool; @@ -554,12 +771,13 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, /* Try to parse the message */ status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet, - pkt_size, 0, &msg, parsed_len, - &response); + pkt_size, options, + &msg, parsed_len, &response); if (status != PJ_SUCCESS) { LOG_ERR_(sess, "STUN msg_decode() error", status); if (response) { - PJ_TODO(SEND_RESPONSE); + send_response(sess, 0, tmp_pool, response, + src_addr, src_addr_len); } pj_pool_release(tmp_pool); return status; @@ -567,61 +785,39 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN); - PJ_LOG(4,(SNAME(sess), + PJ_LOG(4,(SNAME(sess), "RX STUN message:\n" - "--- begin STUN message ---" + "--- begin STUN message ---\n" "%s" "--- end of STUN message ---\n", pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); + pj_mutex_lock(sess->mutex); if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) { - pj_stun_tx_data *tdata; - - /* Lookup pending client transaction */ - tdata = tsx_lookup(sess, msg); - if (tdata == NULL) { - LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND); - pj_pool_release(tmp_pool); - return PJ_ENOTFOUND; - } - - /* Pass the response to the transaction. - * If the message is accepted, transaction callback will be called, - * and this will call the session callback too. - */ - status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg); - if (status != PJ_SUCCESS) { - pj_pool_release(tmp_pool); - return status; - } - - /* If transaction has completed, destroy the transmit data. - * This will remove the transaction from the pending list too. - */ - if (pj_stun_client_tsx_is_complete(tdata->client_tsx)) { - destroy_tdata(tdata); - tdata = NULL; - } - - pj_pool_release(tmp_pool); - return PJ_SUCCESS; + status = on_incoming_response(sess, msg); } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { - PJ_TODO(HANDLE_INCOMING_STUN_REQUEST); + status = on_incoming_request(sess, tmp_pool, packet, pkt_size, msg, + src_addr, src_addr_len); } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) { - PJ_TODO(HANDLE_INCOMING_STUN_INDICATION); + status = on_incoming_indication(sess, tmp_pool, packet, pkt_size, + msg, src_addr, src_addr_len); } else { pj_assert(!"Unexpected!"); + status = PJ_EBUG; } + pj_mutex_unlock(sess->mutex); + pj_pool_release(tmp_pool); - return PJ_ENOTSUP; + return status; } + diff --git a/pjlib-util/src/pjstun-srv-test/server.h b/pjlib-util/src/pjstun-srv-test/server.h deleted file mode 100644 index 9de5adce..00000000 --- a/pjlib-util/src/pjstun-srv-test/server.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2005 Benny Prijono - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __PJSTUN_SERVER_H__ -#define __PJSTUN_SERVER_H__ - - -#define MAX_SERVICE 16 -#define MAX_PKT_LEN 512 - -struct service -{ - unsigned index; - pj_uint16_t port; - pj_bool_t is_stream; - pj_sock_t sock; - pj_ioqueue_key_t *key; - pj_ioqueue_op_key_t recv_opkey, - send_opkey; - - int src_addr_len; - pj_sockaddr_in src_addr; - pj_ssize_t rx_pkt_len; - pj_uint8_t rx_pkt[MAX_PKT_LEN]; - pj_uint8_t tx_pkt[MAX_PKT_LEN]; -}; - -struct stun_server_tag -{ - pj_caching_pool cp; - pj_pool_t *pool; - pj_ioqueue_t *ioqueue; - unsigned service_cnt; - struct service services[MAX_SERVICE]; - - pj_bool_t thread_quit_flag; - unsigned thread_cnt; - pj_thread_t *threads[16]; - -}; - -extern struct stun_server_tag server; - - -#endif /* __PJSTUN_SERVER_H__ */ - diff --git a/pjlib-util/src/pjstun-srv-test/server_main.c b/pjlib-util/src/pjstun-srv-test/server_main.c index 46dc2752..6c15b5ff 100644 --- a/pjlib-util/src/pjstun-srv-test/server_main.c +++ b/pjlib-util/src/pjstun-srv-test/server_main.c @@ -18,7 +18,6 @@ */ #include #include -#include "server.h" #include #include @@ -26,12 +25,47 @@ #define THIS_FILE "server_main.c" #define MAX_THREADS 8 +#define MAX_SERVICE 16 +#define MAX_PKT_LEN 512 -struct stun_server_tag server; +struct service +{ + unsigned index; + pj_uint16_t port; + pj_bool_t is_stream; + pj_sock_t sock; + pj_ioqueue_key_t *key; + pj_ioqueue_op_key_t recv_opkey, + send_opkey; + + pj_stun_session *sess; + + int src_addr_len; + pj_sockaddr_in src_addr; + pj_ssize_t rx_pkt_len; + pj_uint8_t rx_pkt[MAX_PKT_LEN]; + pj_uint8_t tx_pkt[MAX_PKT_LEN]; +}; + +static struct stun_server +{ + pj_caching_pool cp; + pj_pool_t *pool; + pj_stun_endpoint *endpt; + pj_ioqueue_t *ioqueue; + pj_timer_heap_t *timer_heap; + unsigned service_cnt; + struct service services[MAX_SERVICE]; + + pj_bool_t thread_quit_flag; + unsigned thread_cnt; + pj_thread_t *threads[16]; +} server; -pj_status_t server_perror(const char *sender, const char *title, - pj_status_t status) + +static pj_status_t server_perror(const char *sender, const char *title, + pj_status_t status) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); @@ -42,209 +76,168 @@ pj_status_t server_perror(const char *sender, const char *title, } -static pj_status_t create_response(pj_pool_t *pool, - const pj_stun_msg *req_msg, - unsigned err_code, - unsigned uattr_cnt, - pj_uint16_t uattr_types[], - pj_stun_msg **p_response) -{ - pj_uint32_t msg_type = req_msg->hdr.type; - pj_stun_msg *response; - pj_status_t status; - - status = pj_stun_msg_create_response(pool, req_msg, err_code, NULL, - &response); - if (status != PJ_SUCCESS) - return status; - - /* Add unknown_attribute attributes if err_code is 420 */ - if (err_code == PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE) { - pj_stun_unknown_attr *uattr; - - status = pj_stun_unknown_attr_create(pool, uattr_cnt, uattr_types, - &uattr); - if (status != PJ_SUCCESS) - return status; - - pj_stun_msg_add_attr(response, &uattr->hdr); - } - - *p_response = response; - return PJ_SUCCESS; -} - - -static pj_status_t send_msg(struct service *svc, const pj_stun_msg *msg) +/* Callback to be called to send outgoing message */ +static pj_status_t on_send_msg(pj_stun_session *sess, + const void *pkt, + pj_size_t pkt_size, + const pj_sockaddr_t *dst_addr, + unsigned addr_len) { - unsigned tx_pkt_len; + struct service *svc; pj_ssize_t length; pj_status_t status; - /* Print to log */ - PJ_LOG(4,(THIS_FILE, "TX STUN message: \n" - "--- begin STUN message ---\n" - "%s" - "--- end of STUN message ---\n", - pj_stun_msg_dump(msg, svc->tx_pkt, sizeof(svc->tx_pkt), NULL))); - - /* Encode packet */ - tx_pkt_len = sizeof(svc->tx_pkt); - status = pj_stun_msg_encode(msg, svc->tx_pkt, tx_pkt_len, 0, - NULL, &tx_pkt_len); - if (status != PJ_SUCCESS) - return status; - - length = tx_pkt_len; + svc = (struct service*) pj_stun_session_get_user_data(sess); /* Send packet */ + length = pkt_size; if (svc->is_stream) { - status = pj_ioqueue_send(svc->key, &svc->send_opkey, svc->tx_pkt, - &length, 0); + status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0); } else { - status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, svc->tx_pkt, - &length, 0, &svc->src_addr, - svc->src_addr_len); +#if 0 + pj_pool_t *pool; + char *buf; + pj_stun_msg *msg; + + pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL); + status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL); + buf = pj_pool_alloc(pool, 512); + PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL))); +#endif + status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length, + 0, dst_addr, addr_len); } - PJ_LOG(4,(THIS_FILE, "Sending STUN %s %s", - pj_stun_get_method_name(msg->hdr.type), - pj_stun_get_class_name(msg->hdr.type))); - return (status == PJ_SUCCESS || status == PJ_EPENDING) ? PJ_SUCCESS : status; } -static pj_status_t err_respond(struct service *svc, - pj_pool_t *pool, - const pj_stun_msg *req_msg, - unsigned err_code, - unsigned uattr_cnt, - pj_uint16_t uattr_types[]) +/* Handle STUN binding request */ +static pj_status_t on_rx_binding_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) { - pj_stun_msg *response; + struct service *svc = (struct service *) pj_stun_session_get_user_data(sess); + pj_stun_tx_data *tdata; + pj_stun_auth_policy pol; pj_status_t status; - /* Create the error response */ - status = create_response(pool, req_msg, err_code, - uattr_cnt, uattr_types, &response); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error creating response", status); + /* Create response */ + status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); + if (status != PJ_SUCCESS) return status; - } - /* Send response */ - status = send_msg(svc, response); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error sending response", status); +#if 1 + pj_memset(&pol, 0, sizeof(pol)); + pol.type = PJ_STUN_POLICY_STATIC_LONG_TERM; + pol.user_data = NULL; + pol.data.static_long_term.realm = pj_str("realm"); + pol.data.static_long_term.username = pj_str("user"); + pol.data.static_long_term.password = pj_str("password"); + pol.data.static_long_term.nonce = pj_str("nonce"); + status = pj_stun_verify_credential(pkt, pkt_len, msg, &pol, tdata->pool, + &tdata->msg); + if (!tdata->msg) return status; - } - - return PJ_SUCCESS; -} - - -static void handle_binding_request(struct service *svc, pj_pool_t *pool, - const pj_stun_msg *rx_msg) -{ - pj_stun_msg *response; - pj_stun_generic_ip_addr_attr *m_attr; - pj_status_t status; - - status = create_response(pool, rx_msg, 0, 0, NULL, &response); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error creating response", status); - return; - } +#endif /* Create MAPPED-ADDRESS attribute */ - status = pj_stun_generic_ip_addr_attr_create(pool, - PJ_STUN_ATTR_MAPPED_ADDR, - PJ_FALSE, - svc->src_addr_len, - &svc->src_addr, &m_attr); + status = pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_MAPPED_ADDR, + PJ_FALSE, + src_addr, src_addr_len); if (status != PJ_SUCCESS) { server_perror(THIS_FILE, "Error creating response", status); - return; + pj_stun_msg_destroy_tdata(sess, tdata); + return status; } - pj_stun_msg_add_attr(response, &m_attr->hdr); /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ - if (rx_msg->hdr.magic == PJ_STUN_MAGIC) { + if (msg->hdr.magic == PJ_STUN_MAGIC) { status = - pj_stun_generic_ip_addr_attr_create(pool, - PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, - PJ_TRUE, - svc->src_addr_len, - &svc->src_addr, &m_attr); + pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, + PJ_TRUE, + src_addr, src_addr_len); if (status != PJ_SUCCESS) { server_perror(THIS_FILE, "Error creating response", status); - return; + pj_stun_msg_destroy_tdata(sess, tdata); + return status; } } /* Send */ - status = send_msg(svc, response); - if (status != PJ_SUCCESS) - server_perror(THIS_FILE, "Error sending response", status); + status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); + return status; } -static void handle_unknown_request(struct service *svc, pj_pool_t *pool, - pj_stun_msg *rx_msg) +/* Handle unknown request */ +static pj_status_t on_rx_unknown_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) { - err_respond(svc, pool, rx_msg, PJ_STUN_STATUS_BAD_REQUEST, 0, NULL); + pj_stun_tx_data *tdata; + pj_status_t status; + + /* Create response */ + status = pj_stun_session_create_response(sess, msg, + PJ_STUN_STATUS_BAD_REQUEST, + NULL, &tdata); + if (status != PJ_SUCCESS) + return status; + + /* Send */ + status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); + return status; +} + +/* Callback to be called by STUN session on incoming STUN requests */ +static pj_status_t 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) +{ + switch (PJ_STUN_GET_METHOD(msg->hdr.type)) { + case PJ_STUN_BINDING_METHOD: + return on_rx_binding_request(sess, pkt, pkt_len, msg, + src_addr, src_addr_len); + default: + return on_rx_unknown_request(sess, pkt, pkt_len, msg, + src_addr, src_addr_len); + } } +/* Callback on ioqueue read completion */ static void on_read_complete(pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read) { struct service *svc = (struct service *) pj_ioqueue_get_user_data(key); - pj_pool_t *pool = NULL; - pj_stun_msg *rx_msg, *response; - char dump[512]; pj_status_t status; if (bytes_read <= 0) goto next_read; - pool = pj_pool_create(&server.cp.factory, "service", 4000, 4000, NULL); - - rx_msg = NULL; - status = pj_stun_msg_decode(pool, svc->rx_pkt, bytes_read, 0, &rx_msg, - NULL, &response); + /* Handle packet to session */ + status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read, + PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, + NULL, &svc->src_addr, svc->src_addr_len); if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "STUN msg_decode() error", status); - if (response) { - send_msg(svc, response); - } - goto next_read; - } - - PJ_LOG(4,(THIS_FILE, "RX STUN message: \n" - "--- begin STUN message ---\n" - "%s" - "--- end of STUN message ---\n", - pj_stun_msg_dump(rx_msg, dump, sizeof(dump), NULL))); - - if (PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) { - switch (rx_msg->hdr.type) { - case PJ_STUN_BINDING_REQUEST: - handle_binding_request(svc, pool, rx_msg); - break; - default: - handle_unknown_request(svc, pool, rx_msg); - } - + server_perror(THIS_FILE, "Error processing incoming packet", status); } next_read: - if (pool != NULL) - pj_pool_release(pool); - if (bytes_read < 0) { server_perror(THIS_FILE, "on_read_complete()", -bytes_read); } @@ -265,6 +258,7 @@ static pj_status_t init_service(struct service *svc) { pj_status_t status; pj_ioqueue_callback service_callback; + pj_stun_session_cb sess_cb; pj_sockaddr_in addr; status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &svc->sock); @@ -279,6 +273,16 @@ static pj_status_t init_service(struct service *svc) if (status != PJ_SUCCESS) goto on_error; + pj_bzero(&sess_cb, sizeof(sess_cb)); + sess_cb.on_send_msg = &on_send_msg; + sess_cb.on_rx_request = &on_rx_request; + status = pj_stun_session_create(server.endpt, "session", + &sess_cb, &svc->sess); + if (status != PJ_SUCCESS) + goto on_error; + + pj_stun_session_set_user_data(svc->sess, (void*)svc); + pj_bzero(&service_callback, sizeof(service_callback)); service_callback.on_read_complete = &on_read_complete; @@ -316,6 +320,7 @@ static int worker_thread(void *p) while (!server.thread_quit_flag) { pj_time_val timeout = { 0, 50 }; + pj_timer_heap_poll(server.timer_heap, NULL); pj_ioqueue_poll(server.ioqueue, &timeout); } @@ -347,6 +352,16 @@ pj_status_t server_init(void) if (status != PJ_SUCCESS) return server_perror(THIS_FILE, "pj_ioqueue_create()", status); + status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "Error creating timer heap", status); + + status = pj_stun_endpoint_create(&server.cp.factory, 0, + server.ioqueue, server.timer_heap, + &server.endpt); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "Error creating endpoint", status); + server.service_cnt = 1; server.services[0].index = 0; server.services[0].port = PJ_STUN_PORT; @@ -361,9 +376,10 @@ pj_status_t server_init(void) pj_status_t server_main(void) { -#if 1 +#if 0 for (;;) { pj_time_val timeout = { 0, 50 }; + pj_timer_heap_poll(server.timer_heap, NULL); pj_ioqueue_poll(server.ioqueue, &timeout); if (kbhit() && _getch()==27) @@ -413,8 +429,12 @@ pj_status_t server_destroy(void) } } + pj_stun_session_destroy(server.services[0].sess); + pj_stun_endpoint_destroy(server.endpt); pj_ioqueue_destroy(server.ioqueue); pj_pool_release(server.pool); + + pj_pool_factory_dump(&server.cp.factory, PJ_TRUE); pj_caching_pool_destroy(&server.cp); pj_shutdown(); -- cgit v1.2.3