From 67e96a141bd1da5de2edba4a1b5d8527bbb6c855 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 26 Feb 2007 23:49:48 +0000 Subject: Moved stun_session from client to library git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1008 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/build/pjlib_util.dsp | 8 + pjlib-util/build/pjstun_client.dsp | 8 - pjlib-util/include/pjlib-util.h | 1 + pjlib-util/include/pjlib-util/stun_session.h | 419 ++++++++++++++++++ pjlib-util/src/pjlib-util/stun_session.c | 627 +++++++++++++++++++++++++++ pjlib-util/src/pjstun-client/client_main.c | 1 - pjlib-util/src/pjstun-client/stun_session.c | 626 -------------------------- pjlib-util/src/pjstun-client/stun_session.h | 419 ------------------ 8 files changed, 1055 insertions(+), 1054 deletions(-) create mode 100644 pjlib-util/include/pjlib-util/stun_session.h create mode 100644 pjlib-util/src/pjlib-util/stun_session.c delete mode 100644 pjlib-util/src/pjstun-client/stun_session.c delete mode 100644 pjlib-util/src/pjstun-client/stun_session.h diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp index 555a6c15..6aa10d11 100644 --- a/pjlib-util/build/pjlib_util.dsp +++ b/pjlib-util/build/pjlib_util.dsp @@ -161,6 +161,10 @@ SOURCE="..\src\pjlib-util\stun_server.c" # End Source File # Begin Source File +SOURCE="..\src\pjlib-util\stun_session.c" +# End Source File +# Begin Source File + SOURCE="..\src\pjlib-util\stun_simple.c" # End Source File # Begin Source File @@ -261,6 +265,10 @@ SOURCE="..\include\pjlib-util\stun_server.h" # End Source File # Begin Source File +SOURCE="..\include\pjlib-util\stun_session.h" +# End Source File +# Begin Source File + SOURCE="..\include\pjlib-util\stun_simple.h" # End Source File # Begin Source File diff --git a/pjlib-util/build/pjstun_client.dsp b/pjlib-util/build/pjstun_client.dsp index b4cbdb3a..2d5705b7 100644 --- a/pjlib-util/build/pjstun_client.dsp +++ b/pjlib-util/build/pjstun_client.dsp @@ -89,18 +89,10 @@ LINK32=link.exe SOURCE="..\src\pjstun-client\client_main.c" # End Source File -# Begin Source File - -SOURCE="..\src\pjstun-client\stun_session.c" -# End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE="..\src\pjstun-client\stun_session.h" -# End Source File # End Group # Begin Group "Resource Files" diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h index 2b3326b4..7c8e2ad4 100644 --- a/pjlib-util/include/pjlib-util.h +++ b/pjlib-util/include/pjlib-util.h @@ -52,6 +52,7 @@ #include #include #include +#include #include /* Old STUN */ diff --git a/pjlib-util/include/pjlib-util/stun_session.h b/pjlib-util/include/pjlib-util/stun_session.h new file mode 100644 index 00000000..057b35aa --- /dev/null +++ b/pjlib-util/include/pjlib-util/stun_session.h @@ -0,0 +1,419 @@ +/* $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 __PJLIB_UTIL_STUN_SESSION_H__ +#define __PJLIB_UTIL_STUN_SESSION_H__ + +#include +#include +#include +#include + + +/** Forward declaration for pj_stun_tx_data */ +typedef struct pj_stun_tx_data pj_stun_tx_data; + +/** Forward declaration for pj_stun_session */ +typedef struct pj_stun_session pj_stun_session; + +/** + * This is the callback to be registered to pj_stun_session, to send + * outgoing message and to receive various notifications from the STUN + * session. + */ +typedef struct pj_stun_session_cb +{ + /** + * Callback to be called by the STUN session to send outgoing message. + * + * @param tdata The STUN transmit data containing the original + * STUN message + * @param pkt Packet to be sent. + * @param pkt_size Size of the packet to be sent. + * @param addr_len Length of destination address. + * @param dst_addr The destination address. + * + * @return The callback should return the status of the + * packet sending. + */ + pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata, + const void *pkt, + pj_size_t pkt_size, + unsigned addr_len, + const pj_sockaddr_t *dst_addr); + + /** + * Callback to be called when Binding response is received or the + * transaction has timed out. + * + * @param sess The STUN session. + * @param status Status of the request. If the value if not + * PJ_SUCCESS, the transaction has timed-out + * or other error has occurred, and the response + * argument may be NULL. + * @param request The original STUN request. + * @param response The response message, on successful transaction. + */ + void (*on_bind_response)(pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *request, + const pj_stun_msg *response); + + /** + * Callback to be called when Allocate response is received or the + * transaction has timed out. + * + * @param sess The STUN session. + * @param status Status of the request. If the value if not + * PJ_SUCCESS, the transaction has timed-out + * or other error has occurred, and the response + * argument may be NULL. + * @param request The original STUN request. + * @param response The response message, on successful transaction. + */ + void (*on_allocate_response)(pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *request, + const pj_stun_msg *response); + + /** + * Callback to be called when Set Active Destination response is received + * or the transaction has timed out. + * + * @param sess The STUN session. + * @param status Status of the request. If the value if not + * PJ_SUCCESS, the transaction has timed-out + * or other error has occurred, and the response + * argument may be NULL. + * @param request The original STUN request. + * @param response The response message, on successful transaction. + */ + void (*on_set_active_destination_response)(pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *request, + const pj_stun_msg *response); + + /** + * Callback to be called when Connect response is received or the + * transaction has timed out. + * + * @param sess The STUN session. + * @param status Status of the request. If the value if not + * PJ_SUCCESS, the transaction has timed-out + * or other error has occurred, and the response + * argument may be NULL. + * @param request The original STUN request. + * @param response The response message, on successful transaction. + */ + void (*on_connect_response)( pj_stun_session *sess, + pj_status_t status, + pj_stun_tx_data *request, + const pj_stun_msg *response); +} pj_stun_session_cb; + + +/** + * This structure describe the outgoing STUN transmit data to carry the + * message to be sent. + */ +struct pj_stun_tx_data +{ + PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data); + + pj_pool_t *pool; /**< Pool. */ + pj_stun_session *sess; /**< The STUN session. */ + pj_stun_msg *msg; /**< The STUN message. */ + void *user_data; /**< Arbitrary user data. */ + + pj_stun_client_tsx *client_tsx; /**< Client STUN transaction. */ + pj_uint8_t client_key[12];/**< Client transaction key. */ + + void *pkt; /**< The STUN packet. */ + unsigned max_len; /**< Length of packet buffer. */ + unsigned pkt_size; /**< The actual length of STUN pkt. */ + + unsigned addr_len; /**< Length of destination address. */ + const pj_sockaddr_t *dst_addr; /**< Destination address. */ +}; + + +/** + * Options that can be specified when creating or sending outgoing STUN + * messages. These options may be specified as bitmask. + */ +enum pj_stun_session_option +{ + /** + * Add short term credential to the message. This option may not be used + * together with PJ_STUN_USE_LONG_TERM_CRED option. + */ + PJ_STUN_USE_SHORT_TERM_CRED = 1, + + /** + * Add long term credential to the message. This option may not be used + * together with PJ_STUN_USE_SHORT_TERM_CRED option. + */ + PJ_STUN_USE_LONG_TERM_CRED = 2, + + /** + * Add STUN fingerprint to the message. + */ + PJ_STUN_USE_FINGERPRINT = 4 +}; + + +/** + * Create a STUN session. + * + * @param endpt The STUN endpoint, to be used to register timers etc. + * @param name Optional name to be associated with this instance. The + * name will be used for example for logging purpose. + * @param cb Session callback. + * @param p_sess Pointer to receive STUN session instance. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt, + const char *name, + const pj_stun_session_cb *cb, + pj_stun_session **p_sess); + +/** + * Destroy the STUN session. + * + * @param sess The STUN session instance. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess); + +/** + * Associated an arbitrary data with this STUN session. The user data may + * be retrieved later with pj_stun_session_get_user_data() function. + * + * @param sess The STUN session instance. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess, + void *user_data); + +/** + * Retrieve the user data previously associated to this STUN session with + * pj_stun_session_set_user_data(). + * + * @param sess The STUN session instance. + * + * @return The user data associated with this STUN session. + */ +PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess); + +/** + * Save a long term credential to be used by this STUN session when sending + * outgoing messages. After long term credential is configured, application + * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN + * message to send the long term credential in the message. + * + * @param sess The STUN session instance. + * @param realm Realm of the long term credential. + * @param user The user name. + * @param passwd The pain-text password. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) +pj_stun_session_set_long_term_credential(pj_stun_session *sess, + const pj_str_t *realm, + const pj_str_t *user, + const pj_str_t *passwd); + + +/** + * Save a short term credential to be used by this STUN session when sending + * outgoing messages. After short term credential is configured, application + * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN + * message to send the short term credential in the message. + * + * @param sess The STUN session instance. + * @param user The user name. + * @param passwd The pain-text password. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) +pj_stun_session_set_short_term_credential(pj_stun_session *sess, + const pj_str_t *user, + const pj_str_t *passwd); + +/** + * Create a STUN Bind request message. After the message has been + * successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Allocate request message. After the message has been + * successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Set Active Destination request message. After the message + * has been successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) +pj_stun_session_create_set_active_destination_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Connect request message. After the message has been + * successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the request. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create_connect_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Connection Status Indication message. After the message + * has been successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the message. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) +pj_stun_session_create_connection_status_ind(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Send Indication message. After the message has been + * successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the message. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create_send_ind(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Create a STUN Data Indication message. After the message has been + * successfully created, application can send the message by calling + * pj_stun_session_send_msg(). + * + * @param sess The STUN session instance. + * @param p_tdata Pointer to receive STUN transmit data instance containing + * the message. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess, + pj_stun_tx_data **p_tdata); + +/** + * Send STUN message to the specified destination. This function will encode + * the pj_stun_msg instance to a packet buffer, and add credential or + * fingerprint if necessary. If the message is a request, the session will + * also create and manage a STUN client transaction to be used to manage the + * retransmission of the request. After the message has been encoded and + * transaction is setup, the \a on_send_msg() callback of pj_stun_session_cb + * (which is registered when the STUN session is created) will be called + * to actually send the message to the wire. + * + * @param sess The STUN session instance. + * @param options Optional flags, from pj_stun_session_option. + * @param addr_len Length of destination address. + * @param dst_addr The destination socket address. + * @param tdata The STUN transmit data containing the STUN message to + * be sent. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess, + unsigned options, + unsigned addr_len, + const pj_sockaddr_t *dst_addr, + pj_stun_tx_data *tdata); + +/** + * Application must call this function to notify the STUN session about + * the arrival of STUN packet. The STUN packet MUST have been checked + * first with #pj_stun_msg_check() to verify that this is indeed a valid + * STUN packet. + * + * The STUN session will decode the packet into pj_stun_msg, and process + * the message accordingly. If the message is a response, it will search + * through the outstanding STUN client transactions for a matching + * transaction ID and hand over the response to the transaction. + * + * On successful message processing, application will be notified about + * the message via one of the pj_stun_session_cb callback. + * + * @param sess The STUN session instance. + * @param packet The packet containing STUN message. + * @param pkt_size Size of the packet. + * @param parsed_len Optional pointer to receive the size of the parsed + * STUN message (useful if packet is received via a + * stream oriented protocol). + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, + const void *packet, + pj_size_t pkt_size, + unsigned *parsed_len); + + + +#endif /* __PJLIB_UTIL_STUN_SESSION_H__ */ + diff --git a/pjlib-util/src/pjlib-util/stun_session.c b/pjlib-util/src/pjlib-util/stun_session.c new file mode 100644 index 00000000..ce15a610 --- /dev/null +++ b/pjlib-util/src/pjlib-util/stun_session.c @@ -0,0 +1,627 @@ +/* $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 + */ +#include +#include + +struct pj_stun_session +{ + pj_stun_endpoint *endpt; + pj_pool_t *pool; + pj_stun_session_cb cb; + void *user_data; + + /* Long term credential */ + pj_str_t l_realm; + pj_str_t l_username; + pj_str_t l_password; + + /* Short term credential */ + pj_str_t s_username; + pj_str_t s_password; + + pj_stun_tx_data pending_request_list; +}; + +#define SNAME(s_) ((s_)->pool->obj_name) + +#if PJ_LOG_MAX_LEVEL >= 5 +# define TRACE_(expr) PJ_LOG(5,expr) +#else +# define TRACE_(expr) +#endif + +#if PJ_LOG_MAX_LEVEL >= 4 +# define LOG_ERR_(sess, title, rc) +static void stun_perror(pj_stun_session *sess, const char *title, + pj_status_t status) +{ + char errmsg[PJ_ERR_MSG_SIZE]; + + pj_strerror(status, errmsg, sizeof(errmsg)); + + PJ_LOG(4,(SNAME(sess), "%s: %s", title, errmsg)); +} + +#else +# define ERR_(sess, title, rc) +#endif + +#define TDATA_POOL_SIZE 1024 +#define TDATA_POOL_INC 1024 + + +static void tsx_on_complete(pj_stun_client_tsx *tsx, + pj_status_t status, + const pj_stun_msg *response); +static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, + const void *stun_pkt, + pj_size_t pkt_size); + +static pj_stun_tsx_cb tsx_cb = +{ + &tsx_on_complete, + &tsx_on_send_msg +}; + + +static pj_status_t tsx_add(pj_stun_session *sess, + pj_stun_tx_data *tdata) +{ + pj_list_push_back(&sess->pending_request_list, tdata); + return PJ_SUCCESS; +} + +static pj_status_t tsx_erase(pj_stun_session *sess, + pj_stun_tx_data *tdata) +{ + PJ_UNUSED_ARG(sess); + pj_list_erase(tdata); + return PJ_SUCCESS; +} + +static pj_stun_tx_data* tsx_lookup(pj_stun_session *sess, + const pj_stun_msg *msg) +{ + pj_stun_tx_data *tdata; + + tdata = sess->pending_request_list.next; + while (tdata != &sess->pending_request_list) { + pj_assert(sizeof(tdata->client_key)==sizeof(msg->hdr.tsx_id)); + if (pj_memcmp(tdata->client_key, msg->hdr.tsx_id, + sizeof(msg->hdr.tsx_id))==0) + { + return tdata; + } + tdata = tdata->next; + } + + return NULL; +} + +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 */ + pool = pj_pool_create(sess->endpt->pf, "tdata%p", + TDATA_POOL_SIZE, TDATA_POOL_INC, NULL); + PJ_ASSERT_RETURN(pool, PJ_ENOMEM); + + tdata = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_tx_data); + tdata->pool = pool; + tdata->sess = sess; + tdata->user_data = user_data; + + /* Create STUN message */ + status = pj_stun_msg_create(pool, msg_type, PJ_STUN_MAGIC, + NULL, &tdata->msg); + if (status != PJ_SUCCESS) { + pj_pool_release(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)); + } + + *p_tdata = tdata; + + return PJ_SUCCESS; +} + +static void destroy_tdata(pj_stun_tx_data *tdata) +{ + if (tdata->client_tsx) { + tsx_erase(tdata->sess, tdata); + pj_stun_client_tsx_destroy(tdata->client_tsx); + tdata->client_tsx = NULL; + } + + pj_pool_release(tdata->pool); +} + +static pj_status_t session_apply_req(pj_stun_session *sess, + pj_pool_t *pool, + unsigned options, + pj_stun_msg *msg) +{ + pj_status_t status; + + /* From draft-ietf-behave-rfc3489bis-05.txt + * Section 8.3.1. Formulating the Request Message + */ + if (options & PJ_STUN_USE_LONG_TERM_CRED) { + pj_stun_generic_string_attr *auname; + pj_stun_msg_integrity_attr *amsgi; + pj_stun_generic_string_attr *arealm; + + /* Create and add USERNAME attribute */ + status = pj_stun_generic_string_attr_create(sess->pool, + PJ_STUN_ATTR_USERNAME, + &sess->l_username, + &auname); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + status = pj_stun_msg_add_attr(msg, &auname->hdr); + 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, + PJ_STUN_ATTR_REALM, + &sess->l_realm, + &arealm); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + status = pj_stun_msg_add_attr(msg, &arealm->hdr); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + /* Add MESSAGE-INTEGRITY attribute */ + status = pj_stun_msg_integrity_attr_create(sess->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; + + /* Create and add USERNAME attribute */ + status = pj_stun_generic_string_attr_create(sess->pool, + PJ_STUN_ATTR_USERNAME, + &sess->s_username, + &auname); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + status = pj_stun_msg_add_attr(msg, &auname->hdr); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + /* Add MESSAGE-INTEGRITY attribute */ + status = pj_stun_msg_integrity_attr_create(sess->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); + } + + /* 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, + PJ_STUN_ATTR_FINGERPRINT, + 0, &af); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + status = pj_stun_msg_add_attr(msg, &af->hdr); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + } + + return PJ_SUCCESS; +} + + +static void tsx_on_complete(pj_stun_client_tsx *tsx, + pj_status_t status, + const pj_stun_msg *response) +{ + pj_stun_tx_data *tdata; + + 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; + } +} + +static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, + const void *stun_pkt, + pj_size_t pkt_size) +{ + pj_stun_tx_data *tdata; + + 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); +} + +/* **************************************************************************/ + +PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, + const char *name, + const pj_stun_session_cb *cb, + pj_stun_session **p_sess) +{ + pj_pool_t *pool; + pj_stun_session *sess; + + PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL); + + pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL); + PJ_ASSERT_RETURN(pool, PJ_ENOMEM); + + sess = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_session); + sess->endpt = endpt; + sess->pool = pool; + pj_memcpy(&sess->cb, cb, sizeof(*cb)); + + pj_list_init(&sess->pending_request_list); + + *p_sess = sess; + + PJ_TODO(MUTEX_PROTECTION); + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) +{ + PJ_ASSERT_RETURN(sess, PJ_EINVAL); + + pj_pool_release(sess->pool); + + return PJ_SUCCESS; +} + + +PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess, + void *user_data) +{ + PJ_ASSERT_RETURN(sess, PJ_EINVAL); + sess->user_data = user_data; + return PJ_SUCCESS; +} + +PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess) +{ + PJ_ASSERT_RETURN(sess, NULL); + return sess->user_data; +} + +PJ_DEF(pj_status_t) +pj_stun_session_set_long_term_credential(pj_stun_session *sess, + const pj_str_t *realm, + const pj_str_t *user, + const pj_str_t *passwd) +{ + pj_str_t nil = { NULL, 0 }; + + PJ_ASSERT_RETURN(sess, PJ_EINVAL); + 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); + + return PJ_SUCCESS; +} + + +PJ_DEF(pj_status_t) +pj_stun_session_set_short_term_credential(pj_stun_session *sess, + const pj_str_t *user, + const pj_str_t *passwd) +{ + pj_str_t nil = { NULL, 0 }; + + PJ_ASSERT_RETURN(sess, PJ_EINVAL); + pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); + pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); + + return PJ_SUCCESS; +} + + +PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata) +{ + pj_stun_tx_data *tdata; + pj_status_t status; + + PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); + + status = create_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, &tdata); + if (status != PJ_SUCCESS) + return status; + + *p_tdata = tdata; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess, + pj_stun_tx_data **p_tdata) +{ + PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); +} + + +PJ_DEF(pj_status_t) +pj_stun_session_create_set_active_destination_req(pj_stun_session *sess, + pj_stun_tx_data **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_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); +} + +PJ_DEF(pj_status_t) +pj_stun_session_create_connection_status_ind(pj_stun_session *sess, + pj_stun_tx_data **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_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_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); +} + +PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, + unsigned options, + unsigned addr_len, + const pj_sockaddr_t *server, + pj_stun_tx_data *tdata) +{ + pj_status_t status; + + PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); + + /* Allocate packet */ + 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))); + } + + /* Apply options */ + status = session_apply_req(sess, tdata->pool, options, tdata->msg); + if (status != PJ_SUCCESS) { + LOG_ERR_(sess, "Error applying options", status); + destroy_tdata(tdata); + return status; + } + + /* Encode message */ + status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, + 0, NULL, &tdata->pkt_size); + if (status != PJ_SUCCESS) { + LOG_ERR_(sess, "STUN encode() error", status); + destroy_tdata(tdata); + return status; + } + + /* If this is a STUN request message, then send the request with + * a new STUN client transaction. + */ + if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) { + + /* Create STUN client transaction */ + status = pj_stun_client_tsx_create(sess->endpt, tdata->pool, + &tsx_cb, &tdata->client_tsx); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata); + + /* Save the remote address */ + tdata->addr_len = addr_len; + tdata->dst_addr = server; + + /* Send the request! */ + status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE, + tdata->pkt, tdata->pkt_size); + if (status != PJ_SUCCESS && status != PJ_EPENDING) { + LOG_ERR_(sess, "Error sending STUN request", status); + destroy_tdata(tdata); + return status; + } + + /* Add to pending request list */ + tsx_add(sess, tdata); + + } 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); + + if (status != PJ_SUCCESS && status != PJ_EPENDING) { + LOG_ERR_(sess, "Error sending STUN request", status); + destroy_tdata(tdata); + return status; + } + } + + + return status; +} + + +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) +{ + pj_stun_msg *msg, *response; + pj_pool_t *tmp_pool; + char *dump; + pj_status_t status; + + PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); + + tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL); + if (!tmp_pool) + return PJ_ENOMEM; + + /* Try to parse the message */ + status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet, + pkt_size, 0, &msg, parsed_len, + &response); + if (status != PJ_SUCCESS) { + LOG_ERR_(sess, "STUN msg_decode() error", status); + if (response) { + PJ_TODO(SEND_RESPONSE); + } + pj_pool_release(tmp_pool); + return status; + } + + dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN); + + PJ_LOG(4,(SNAME(sess), + "RX STUN message:\n" + "--- begin STUN message ---" + "%s" + "--- end of STUN message ---\n", + pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); + + + 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; + + } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { + + PJ_TODO(HANDLE_INCOMING_STUN_REQUEST); + + } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) { + + PJ_TODO(HANDLE_INCOMING_STUN_INDICATION); + + } else { + pj_assert(!"Unexpected!"); + } + + pj_pool_release(tmp_pool); + return PJ_ENOTSUP; +} + diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c index 5f9d7d4c..4ef95d85 100644 --- a/pjlib-util/src/pjstun-client/client_main.c +++ b/pjlib-util/src/pjstun-client/client_main.c @@ -18,7 +18,6 @@ */ #include #include -#include "stun_session.h" #include diff --git a/pjlib-util/src/pjstun-client/stun_session.c b/pjlib-util/src/pjstun-client/stun_session.c deleted file mode 100644 index 03dc6f19..00000000 --- a/pjlib-util/src/pjstun-client/stun_session.c +++ /dev/null @@ -1,626 +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 - */ -#include "stun_session.h" -#include - -struct pj_stun_session -{ - pj_stun_endpoint *endpt; - pj_pool_t *pool; - pj_stun_session_cb cb; - void *user_data; - - /* Long term credential */ - pj_str_t l_realm; - pj_str_t l_username; - pj_str_t l_password; - - /* Short term credential */ - pj_str_t s_username; - pj_str_t s_password; - - pj_stun_tx_data pending_request_list; -}; - -#define SNAME(s_) ((s_)->pool->obj_name) - -#if PJ_LOG_MAX_LEVEL >= 5 -# define TRACE_(expr) PJ_LOG(5,expr) -#else -# define TRACE_(expr) -#endif - -#if PJ_LOG_MAX_LEVEL >= 4 -# define LOG_ERR_(sess, title, rc) -static void stun_perror(pj_stun_session *sess, const char *title, - pj_status_t status) -{ - char errmsg[PJ_ERR_MSG_SIZE]; - - pj_strerror(status, errmsg, sizeof(errmsg)); - - PJ_LOG(4,(SNAME(sess), "%s: %s", title, errmsg)); -} - -#else -# define ERR_(sess, title, rc) -#endif - -#define TDATA_POOL_SIZE 1024 -#define TDATA_POOL_INC 1024 - - -static void tsx_on_complete(pj_stun_client_tsx *tsx, - pj_status_t status, - const pj_stun_msg *response); -static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, - const void *stun_pkt, - pj_size_t pkt_size); - -static pj_stun_tsx_cb tsx_cb = -{ - &tsx_on_complete, - &tsx_on_send_msg -}; - - -static pj_status_t tsx_add(pj_stun_session *sess, - pj_stun_tx_data *tdata) -{ - pj_list_push_back(&sess->pending_request_list, tdata); - return PJ_SUCCESS; -} - -static pj_status_t tsx_erase(pj_stun_session *sess, - pj_stun_tx_data *tdata) -{ - pj_list_erase(tdata); - return PJ_SUCCESS; -} - -static pj_stun_tx_data* tsx_lookup(pj_stun_session *sess, - const pj_stun_msg *msg) -{ - pj_stun_tx_data *tdata; - - tdata = sess->pending_request_list.next; - while (tdata != &sess->pending_request_list) { - pj_assert(sizeof(tdata->client_key)==sizeof(msg->hdr.tsx_id)); - if (pj_memcmp(tdata->client_key, msg->hdr.tsx_id, - sizeof(msg->hdr.tsx_id))==0) - { - return tdata; - } - tdata = tdata->next; - } - - return NULL; -} - -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 */ - pool = pj_pool_create(sess->endpt->pf, "tdata%p", - TDATA_POOL_SIZE, TDATA_POOL_INC, NULL); - PJ_ASSERT_RETURN(pool, PJ_ENOMEM); - - tdata = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_tx_data); - tdata->pool = pool; - tdata->sess = sess; - tdata->user_data = tdata; - - /* Create STUN message */ - status = pj_stun_msg_create(pool, msg_type, PJ_STUN_MAGIC, - NULL, &tdata->msg); - if (status != PJ_SUCCESS) { - pj_pool_release(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)); - } - - *p_tdata = tdata; - - return PJ_SUCCESS; -} - -static void destroy_tdata(pj_stun_tx_data *tdata) -{ - if (tdata->client_tsx) { - tsx_erase(tdata->sess, tdata); - pj_stun_client_tsx_destroy(tdata->client_tsx); - tdata->client_tsx = NULL; - } - - pj_pool_release(tdata->pool); -} - -static pj_status_t session_apply_req(pj_stun_session *sess, - pj_pool_t *pool, - unsigned options, - pj_stun_msg *msg) -{ - pj_status_t status; - - /* From draft-ietf-behave-rfc3489bis-05.txt - * Section 8.3.1. Formulating the Request Message - */ - if (options & PJ_STUN_USE_LONG_TERM_CRED) { - pj_stun_generic_string_attr *auname; - pj_stun_msg_integrity_attr *amsgi; - pj_stun_generic_string_attr *arealm; - - /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(sess->pool, - PJ_STUN_ATTR_USERNAME, - &sess->l_username, - &auname); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &auname->hdr); - 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, - PJ_STUN_ATTR_REALM, - &sess->l_realm, - &arealm); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &arealm->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(sess->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; - - /* Create and add USERNAME attribute */ - status = pj_stun_generic_string_attr_create(sess->pool, - PJ_STUN_ATTR_USERNAME, - &sess->s_username, - &auname); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &auname->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - /* Add MESSAGE-INTEGRITY attribute */ - status = pj_stun_msg_integrity_attr_create(sess->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); - } - - /* 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, - PJ_STUN_ATTR_FINGERPRINT, - 0, &af); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - - status = pj_stun_msg_add_attr(msg, &af->hdr); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - } - - return PJ_SUCCESS; -} - - -static void tsx_on_complete(pj_stun_client_tsx *tsx, - pj_status_t status, - const pj_stun_msg *response) -{ - pj_stun_tx_data *tdata; - - 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; - } -} - -static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, - const void *stun_pkt, - pj_size_t pkt_size) -{ - pj_stun_tx_data *tdata; - - 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); -} - -/* **************************************************************************/ - -PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, - const char *name, - const pj_stun_session_cb *cb, - pj_stun_session **p_sess) -{ - pj_pool_t *pool; - pj_stun_session *sess; - - PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL); - - pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL); - PJ_ASSERT_RETURN(pool, PJ_ENOMEM); - - sess = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_session); - sess->endpt = endpt; - sess->pool = pool; - pj_memcpy(&sess->cb, cb, sizeof(*cb)); - - pj_list_init(&sess->pending_request_list); - - *p_sess = sess; - - PJ_TODO(MUTEX_PROTECTION); - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) -{ - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - - pj_pool_release(sess->pool); - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pj_stun_session_set_user_data( pj_stun_session *sess, - void *user_data) -{ - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - sess->user_data = user_data; - return PJ_SUCCESS; -} - -PJ_DEF(void*) pj_stun_session_get_user_data(pj_stun_session *sess) -{ - PJ_ASSERT_RETURN(sess, NULL); - return sess->user_data; -} - -PJ_DEF(pj_status_t) -pj_stun_session_set_long_term_credential(pj_stun_session *sess, - const pj_str_t *realm, - const pj_str_t *user, - const pj_str_t *passwd) -{ - pj_str_t nil = { NULL, 0 }; - - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - 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); - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) -pj_stun_session_set_short_term_credential(pj_stun_session *sess, - const pj_str_t *user, - const pj_str_t *passwd) -{ - pj_str_t nil = { NULL, 0 }; - - PJ_ASSERT_RETURN(sess, PJ_EINVAL); - pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); - pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); - - return PJ_SUCCESS; -} - - -PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata) -{ - pj_stun_tx_data *tdata; - pj_status_t status; - - PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); - - status = create_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, &tdata); - if (status != PJ_SUCCESS) - return status; - - *p_tdata = tdata; - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata) -{ - PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); -} - - -PJ_DEF(pj_status_t) -pj_stun_session_create_set_active_destination_req(pj_stun_session *sess, - pj_stun_tx_data **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_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); -} - -PJ_DEF(pj_status_t) -pj_stun_session_create_connection_status_ind(pj_stun_session *sess, - pj_stun_tx_data **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_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_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); -} - -PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, - unsigned options, - unsigned addr_len, - const pj_sockaddr_t *server, - pj_stun_tx_data *tdata) -{ - pj_status_t status; - - PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); - - /* Allocate packet */ - 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))); - } - - /* Apply options */ - status = session_apply_req(sess, tdata->pool, options, tdata->msg); - if (status != PJ_SUCCESS) { - LOG_ERR_(sess, "Error applying options", status); - destroy_tdata(tdata); - return status; - } - - /* Encode message */ - status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, - 0, NULL, &tdata->pkt_size); - if (status != PJ_SUCCESS) { - LOG_ERR_(sess, "STUN encode() error", status); - destroy_tdata(tdata); - return status; - } - - /* If this is a STUN request message, then send the request with - * a new STUN client transaction. - */ - if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) { - - /* Create STUN client transaction */ - status = pj_stun_client_tsx_create(sess->endpt, tdata->pool, - &tsx_cb, &tdata->client_tsx); - PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); - pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata); - - /* Save the remote address */ - tdata->addr_len = addr_len; - tdata->dst_addr = server; - - /* Send the request! */ - status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE, - tdata->pkt, tdata->pkt_size); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - LOG_ERR_(sess, "Error sending STUN request", status); - destroy_tdata(tdata); - return status; - } - - /* Add to pending request list */ - tsx_add(sess, tdata); - - } 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); - - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - LOG_ERR_(sess, "Error sending STUN request", status); - destroy_tdata(tdata); - return status; - } - } - - - return status; -} - - -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) -{ - pj_stun_msg *msg, *response; - pj_pool_t *tmp_pool; - char *dump; - pj_status_t status; - - PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); - - tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL); - if (!tmp_pool) - return PJ_ENOMEM; - - /* Try to parse the message */ - status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet, - pkt_size, 0, &msg, parsed_len, - &response); - if (status != PJ_SUCCESS) { - LOG_ERR_(sess, "STUN msg_decode() error", status); - if (response) { - PJ_TODO(SEND_RESPONSE); - } - pj_pool_release(tmp_pool); - return status; - } - - dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN); - - PJ_LOG(4,(SNAME(sess), - "RX STUN message:\n" - "--- begin STUN message ---" - "%s" - "--- end of STUN message ---\n", - pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); - - - 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; - - } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { - - PJ_TODO(HANDLE_INCOMING_STUN_REQUEST); - - } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) { - - PJ_TODO(HANDLE_INCOMING_STUN_INDICATION); - - } else { - pj_assert(!"Unexpected!"); - } - - pj_pool_release(tmp_pool); - return PJ_ENOTSUP; -} - diff --git a/pjlib-util/src/pjstun-client/stun_session.h b/pjlib-util/src/pjstun-client/stun_session.h deleted file mode 100644 index 057b35aa..00000000 --- a/pjlib-util/src/pjstun-client/stun_session.h +++ /dev/null @@ -1,419 +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 __PJLIB_UTIL_STUN_SESSION_H__ -#define __PJLIB_UTIL_STUN_SESSION_H__ - -#include -#include -#include -#include - - -/** Forward declaration for pj_stun_tx_data */ -typedef struct pj_stun_tx_data pj_stun_tx_data; - -/** Forward declaration for pj_stun_session */ -typedef struct pj_stun_session pj_stun_session; - -/** - * This is the callback to be registered to pj_stun_session, to send - * outgoing message and to receive various notifications from the STUN - * session. - */ -typedef struct pj_stun_session_cb -{ - /** - * Callback to be called by the STUN session to send outgoing message. - * - * @param tdata The STUN transmit data containing the original - * STUN message - * @param pkt Packet to be sent. - * @param pkt_size Size of the packet to be sent. - * @param addr_len Length of destination address. - * @param dst_addr The destination address. - * - * @return The callback should return the status of the - * packet sending. - */ - pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata, - const void *pkt, - pj_size_t pkt_size, - unsigned addr_len, - const pj_sockaddr_t *dst_addr); - - /** - * Callback to be called when Binding response is received or the - * transaction has timed out. - * - * @param sess The STUN session. - * @param status Status of the request. If the value if not - * PJ_SUCCESS, the transaction has timed-out - * or other error has occurred, and the response - * argument may be NULL. - * @param request The original STUN request. - * @param response The response message, on successful transaction. - */ - void (*on_bind_response)(pj_stun_session *sess, - pj_status_t status, - pj_stun_tx_data *request, - const pj_stun_msg *response); - - /** - * Callback to be called when Allocate response is received or the - * transaction has timed out. - * - * @param sess The STUN session. - * @param status Status of the request. If the value if not - * PJ_SUCCESS, the transaction has timed-out - * or other error has occurred, and the response - * argument may be NULL. - * @param request The original STUN request. - * @param response The response message, on successful transaction. - */ - void (*on_allocate_response)(pj_stun_session *sess, - pj_status_t status, - pj_stun_tx_data *request, - const pj_stun_msg *response); - - /** - * Callback to be called when Set Active Destination response is received - * or the transaction has timed out. - * - * @param sess The STUN session. - * @param status Status of the request. If the value if not - * PJ_SUCCESS, the transaction has timed-out - * or other error has occurred, and the response - * argument may be NULL. - * @param request The original STUN request. - * @param response The response message, on successful transaction. - */ - void (*on_set_active_destination_response)(pj_stun_session *sess, - pj_status_t status, - pj_stun_tx_data *request, - const pj_stun_msg *response); - - /** - * Callback to be called when Connect response is received or the - * transaction has timed out. - * - * @param sess The STUN session. - * @param status Status of the request. If the value if not - * PJ_SUCCESS, the transaction has timed-out - * or other error has occurred, and the response - * argument may be NULL. - * @param request The original STUN request. - * @param response The response message, on successful transaction. - */ - void (*on_connect_response)( pj_stun_session *sess, - pj_status_t status, - pj_stun_tx_data *request, - const pj_stun_msg *response); -} pj_stun_session_cb; - - -/** - * This structure describe the outgoing STUN transmit data to carry the - * message to be sent. - */ -struct pj_stun_tx_data -{ - PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data); - - pj_pool_t *pool; /**< Pool. */ - pj_stun_session *sess; /**< The STUN session. */ - pj_stun_msg *msg; /**< The STUN message. */ - void *user_data; /**< Arbitrary user data. */ - - pj_stun_client_tsx *client_tsx; /**< Client STUN transaction. */ - pj_uint8_t client_key[12];/**< Client transaction key. */ - - void *pkt; /**< The STUN packet. */ - unsigned max_len; /**< Length of packet buffer. */ - unsigned pkt_size; /**< The actual length of STUN pkt. */ - - unsigned addr_len; /**< Length of destination address. */ - const pj_sockaddr_t *dst_addr; /**< Destination address. */ -}; - - -/** - * Options that can be specified when creating or sending outgoing STUN - * messages. These options may be specified as bitmask. - */ -enum pj_stun_session_option -{ - /** - * Add short term credential to the message. This option may not be used - * together with PJ_STUN_USE_LONG_TERM_CRED option. - */ - PJ_STUN_USE_SHORT_TERM_CRED = 1, - - /** - * Add long term credential to the message. This option may not be used - * together with PJ_STUN_USE_SHORT_TERM_CRED option. - */ - PJ_STUN_USE_LONG_TERM_CRED = 2, - - /** - * Add STUN fingerprint to the message. - */ - PJ_STUN_USE_FINGERPRINT = 4 -}; - - -/** - * Create a STUN session. - * - * @param endpt The STUN endpoint, to be used to register timers etc. - * @param name Optional name to be associated with this instance. The - * name will be used for example for logging purpose. - * @param cb Session callback. - * @param p_sess Pointer to receive STUN session instance. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt, - const char *name, - const pj_stun_session_cb *cb, - pj_stun_session **p_sess); - -/** - * Destroy the STUN session. - * - * @param sess The STUN session instance. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess); - -/** - * Associated an arbitrary data with this STUN session. The user data may - * be retrieved later with pj_stun_session_get_user_data() function. - * - * @param sess The STUN session instance. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess, - void *user_data); - -/** - * Retrieve the user data previously associated to this STUN session with - * pj_stun_session_set_user_data(). - * - * @param sess The STUN session instance. - * - * @return The user data associated with this STUN session. - */ -PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess); - -/** - * Save a long term credential to be used by this STUN session when sending - * outgoing messages. After long term credential is configured, application - * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN - * message to send the long term credential in the message. - * - * @param sess The STUN session instance. - * @param realm Realm of the long term credential. - * @param user The user name. - * @param passwd The pain-text password. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) -pj_stun_session_set_long_term_credential(pj_stun_session *sess, - const pj_str_t *realm, - const pj_str_t *user, - const pj_str_t *passwd); - - -/** - * Save a short term credential to be used by this STUN session when sending - * outgoing messages. After short term credential is configured, application - * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN - * message to send the short term credential in the message. - * - * @param sess The STUN session instance. - * @param user The user name. - * @param passwd The pain-text password. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) -pj_stun_session_set_short_term_credential(pj_stun_session *sess, - const pj_str_t *user, - const pj_str_t *passwd); - -/** - * Create a STUN Bind request message. After the message has been - * successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the request. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Allocate request message. After the message has been - * successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the request. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Set Active Destination request message. After the message - * has been successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the request. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) -pj_stun_session_create_set_active_destination_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Connect request message. After the message has been - * successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the request. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create_connect_req(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Connection Status Indication message. After the message - * has been successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the message. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) -pj_stun_session_create_connection_status_ind(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Send Indication message. After the message has been - * successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the message. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create_send_ind(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Create a STUN Data Indication message. After the message has been - * successfully created, application can send the message by calling - * pj_stun_session_send_msg(). - * - * @param sess The STUN session instance. - * @param p_tdata Pointer to receive STUN transmit data instance containing - * the message. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess, - pj_stun_tx_data **p_tdata); - -/** - * Send STUN message to the specified destination. This function will encode - * the pj_stun_msg instance to a packet buffer, and add credential or - * fingerprint if necessary. If the message is a request, the session will - * also create and manage a STUN client transaction to be used to manage the - * retransmission of the request. After the message has been encoded and - * transaction is setup, the \a on_send_msg() callback of pj_stun_session_cb - * (which is registered when the STUN session is created) will be called - * to actually send the message to the wire. - * - * @param sess The STUN session instance. - * @param options Optional flags, from pj_stun_session_option. - * @param addr_len Length of destination address. - * @param dst_addr The destination socket address. - * @param tdata The STUN transmit data containing the STUN message to - * be sent. - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess, - unsigned options, - unsigned addr_len, - const pj_sockaddr_t *dst_addr, - pj_stun_tx_data *tdata); - -/** - * Application must call this function to notify the STUN session about - * the arrival of STUN packet. The STUN packet MUST have been checked - * first with #pj_stun_msg_check() to verify that this is indeed a valid - * STUN packet. - * - * The STUN session will decode the packet into pj_stun_msg, and process - * the message accordingly. If the message is a response, it will search - * through the outstanding STUN client transactions for a matching - * transaction ID and hand over the response to the transaction. - * - * On successful message processing, application will be notified about - * the message via one of the pj_stun_session_cb callback. - * - * @param sess The STUN session instance. - * @param packet The packet containing STUN message. - * @param pkt_size Size of the packet. - * @param parsed_len Optional pointer to receive the size of the parsed - * STUN message (useful if packet is received via a - * stream oriented protocol). - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, - const void *packet, - pj_size_t pkt_size, - unsigned *parsed_len); - - - -#endif /* __PJLIB_UTIL_STUN_SESSION_H__ */ - -- cgit v1.2.3