From 38fa00aca483bbe28c0debf9752bd25f3eef10e0 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Wed, 21 Mar 2007 09:12:22 +0000 Subject: [PATCH] s/stun_endpoint/stun_setting git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1090 74dad513-b988-da41-8d7b-12977e46ad98 --- pjnath/build/pjnath.dsp | 16 +- pjnath/include/pjnath.h | 2 +- pjnath/include/pjnath/ice.h | 20 +- .../{stun_endpoint.h => stun_setting.h} | 33 +- pjnath/src/pjnath/ice.c | 343 ++++++++++++++---- pjnath/src/pjnath/stun_endpoint.c | 69 ---- pjnath/src/pjnath/stun_setting.c | 23 ++ 7 files changed, 337 insertions(+), 169 deletions(-) rename pjnath/include/pjnath/{stun_endpoint.h => stun_setting.h} (76%) delete mode 100644 pjnath/src/pjnath/stun_endpoint.c create mode 100644 pjnath/src/pjnath/stun_setting.c diff --git a/pjnath/build/pjnath.dsp b/pjnath/build/pjnath.dsp index 9cef5642b..c46df1faa 100644 --- a/pjnath/build/pjnath.dsp +++ b/pjnath/build/pjnath.dsp @@ -99,10 +99,6 @@ SOURCE=..\src\pjnath\stun_auth.c # End Source File # Begin Source File -SOURCE=..\src\pjnath\stun_endpoint.c -# End Source File -# Begin Source File - SOURCE=..\src\pjnath\stun_msg.c # End Source File # Begin Source File @@ -115,6 +111,10 @@ SOURCE=..\src\pjnath\stun_session.c # End Source File # Begin Source File +SOURCE=..\src\pjnath\stun_setting.c +# End Source File +# Begin Source File + SOURCE=..\src\pjnath\stun_transaction.c # End Source File # End Group @@ -147,10 +147,6 @@ SOURCE=..\include\pjnath\stun_doc.h # End Source File # Begin Source File -SOURCE=..\include\pjnath\stun_endpoint.h -# End Source File -# Begin Source File - SOURCE=..\include\pjnath\stun_msg.h # End Source File # Begin Source File @@ -159,6 +155,10 @@ SOURCE=..\include\pjnath\stun_session.h # End Source File # Begin Source File +SOURCE=..\include\pjnath\stun_setting.h +# End Source File +# Begin Source File + SOURCE=..\include\pjnath\stun_transaction.h # End Source File # Begin Source File diff --git a/pjnath/include/pjnath.h b/pjnath/include/pjnath.h index 7562120a6..42fc3ca3a 100644 --- a/pjnath/include/pjnath.h +++ b/pjnath/include/pjnath.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/pjnath/include/pjnath/ice.h b/pjnath/include/pjnath/ice.h index 9f86894fa..3b3325d32 100644 --- a/pjnath/include/pjnath/ice.h +++ b/pjnath/include/pjnath/ice.h @@ -147,16 +147,6 @@ typedef struct pj_ice_cb } pj_ice_cb; -typedef enum pj_ice_state -{ - PJ_ICE_STATE_INIT, - PJ_ICE_STATE_GATHERING, - PJ_ICE_STATE_CAND_COMPLETE, - PJ_ICE_STATE_CHECKING, - PJ_ICE_STATE_COMPLETE, - PJ_ICE_STATE_RESV_ERROR -} pj_ice_state; - typedef enum pj_ice_role { PJ_ICE_ROLE_CONTROLLED, @@ -175,7 +165,6 @@ struct pj_ice int af; int sock_type; pj_ice_role role; - pj_ice_state state; pj_ice_cb cb; pj_stun_config stun_cfg; @@ -198,9 +187,12 @@ struct pj_ice unsigned rcand_cnt; pj_ice_cand rcand[PJ_ICE_MAX_CAND]; - /* Checklists */ - pj_ice_checklist cklist; - pj_ice_checklist valid_list; + /* Checklist */ + pj_ice_checklist clist; + + /* Valid list */ + unsigned valid_cnt; + unsigned valid_list[PJ_ICE_MAX_CHECKS]; /* STUN servers */ pj_dns_resolver *resv; diff --git a/pjnath/include/pjnath/stun_endpoint.h b/pjnath/include/pjnath/stun_setting.h similarity index 76% rename from pjnath/include/pjnath/stun_endpoint.h rename to pjnath/include/pjnath/stun_setting.h index d9a32b5c3..66a5f7aad 100644 --- a/pjnath/include/pjnath/stun_endpoint.h +++ b/pjnath/include/pjnath/stun_setting.h @@ -32,16 +32,14 @@ PJ_BEGIN_DECL /* **************************************************************************/ /** - * @defgroup PJNATH_STUN_ENDPOINT STUN Endpoint - * @brief Management of incoming and outgoing STUN transactions. + * @defgroup PJNATH_STUN_SETTING STUN Settings + * @brief STUN settings. * @ingroup PJNATH_STUN * @{ */ /** - * Opaque declaration for STUN endpoint. STUN endpoint manages client and - * server STUN transactions, and it needs to be initialized before application - * can send or receive STUN messages. + * Opaque declaration for STUN setting. */ typedef struct pj_stun_config { @@ -91,18 +89,23 @@ typedef struct pj_stun_config /** - * Create a STUN endpoint instance. + * Initialize STUN config. */ -PJ_DECL(pj_status_t) pj_stun_config_create(pj_pool_factory *factory, - unsigned options, - pj_ioqueue_t *ioqueue, - pj_timer_heap_t *timer_heap, - pj_stun_config **p_endpt); +PJ_INLINE(void) pj_stun_config_init(pj_stun_config *cfg, + pj_pool_factory *factory, + unsigned options, + pj_ioqueue_t *ioqueue, + pj_timer_heap_t *timer_heap) +{ + pj_bzero(cfg, sizeof(*cfg)); -/** - * Destroy STUN endpoint instance. - */ -PJ_DECL(pj_status_t) pj_stun_config_destroy(pj_stun_config *endpt); + cfg->pf = factory; + cfg->options = options; + cfg->ioqueue = ioqueue; + cfg->timer_heap = timer_heap; + cfg->rto_msec = PJ_STUN_RTO_VALUE; + cfg->res_cache_msec = 10000; +} /** diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c index 7273399b6..e8babab0a 100644 --- a/pjnath/src/pjnath/ice.c +++ b/pjnath/src/pjnath/ice.c @@ -64,8 +64,6 @@ const pj_str_t peer_mapped_foundation = {"peer", 4}; static void destroy_ice(pj_ice *ice, pj_status_t reason); -static void ice_set_state(pj_ice *ice, - pj_ice_state new_state); static pj_status_t start_periodic_check(pj_timer_heap_t *th, pj_timer_entry *te); static pj_status_t on_stun_send_msg(pj_stun_session *sess, @@ -168,10 +166,26 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, static void destroy_ice(pj_ice *ice, pj_status_t reason) { + unsigned i; + if (reason == PJ_SUCCESS) { LOG((ice->obj_name, "Destroying ICE session")); } + for (i=0; icomp_cnt; ++i) { + pj_ice_comp *comp = &ice->comp[i]; + + if (comp->stun_sess) { + pj_stun_session_destroy(comp->stun_sess); + comp->stun_sess = NULL; + } + } + + if (ice->clist.timer.id) { + pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); + ice->clist.timer.id = PJ_FALSE; + } + if (ice->resv_q) { pj_dns_resolver_cancel_query(ice->resv_q, PJ_FALSE); ice->resv_q = NULL; @@ -197,12 +211,108 @@ PJ_DEF(pj_status_t) pj_ice_destroy(pj_ice *ice) } -static void ice_set_state(pj_ice *ice, - pj_ice_state new_state) +/* This function is called when ICE processing completes */ +static void on_ice_complete(pj_ice *ice, pj_status_t status) { - ice->state = new_state; } + +/* This function is called when one check completes */ +static pj_bool_t on_check_complete(pj_ice *ice, + pj_ice_check *check) +{ + unsigned i; + + /* If there is at least one nominated pair in the valid list: + * - The agent MUST remove all Waiting and Frozen pairs in the check + * list for the same component as the nominated pairs for that + * media stream + * - If an In-Progress pair in the check list is for the same + * component as a nominated pair, the agent SHOULD cease + * retransmissions for its check if its pair priority is lower + * than the lowest priority nominated pair for that component + */ + if (check->nominated) { + for (i=0; iclist.count; ++i) { + pj_ice_check *c; + if (c->lcand->comp_id == check->lcand->comp_id && + (c->state==PJ_ICE_CHECK_STATE_FROZEN || + c->state==PJ_ICE_CHECK_STATE_WAITING) + { + check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, + PJ_ECANCELLED); + } + } + } + + /* Once there is at least one nominated pair in the valid list for + * every component of at least one media stream: + * - The agent MUST change the state of processing for its check + * list for that media stream to Completed. + * - The agent MUST continue to respond to any checks it may still + * receive for that media stream, and MUST perform triggered + * checks if required by the processing of Section 7.2. + * - The agent MAY begin transmitting media for this media stream as + * described in Section 11.1 + */ + /* TODO */ + + /* Once there is at least one nominated pair in the valid list for + * each component of each media stream: + * - The agent sets the state of ICE processing overall to + * Completed. + * - If an agent is controlling, it examines the highest priority + * nominated candidate pair for each component of each media + * stream. If any of those candidate pairs differ from the + * default candidate pairs in the most recent offer/answer + * exchange, the controlling agent MUST generate an updated offer + * as described in Section 9. If the controlling agent is using + * an aggressive nomination algorithm, this may result in several + * updated offers as the pairs selected for media change. An + * agent MAY delay sending the offer for a brief interval (one + * second is RECOMMENDED) in order to allow the selected pairs to + * stabilize. + */ + /* TODO */ + + + /* For now, just see if we have a valid pair in component 1 and + * just terminate ICE. + */ + for (i=0; ivalid_cnt; ++i) { + pj_ice_check *c = ice->clist.checks[ice->valid_list[i]]; + if (c->lcand->comp_id == 1) + break; + } + + if (i != ice->valid_cnt) { + /* ICE succeeded */ + on_ice_complete(ice, PJ_SUCCESS); + return PJ_TRUE; + } + + /* We don't have valid pair for component 1. + * See if we have performed all checks in the checklist. If we do, + * then mark ICE processing as failed. + */ + for (i=0; iclist.count; ++i) { + pj_ice_check *c = &ice->clist.checks[i]; + if (c->state < PJ_ICE_CHECK_STATE_SUCCEEDED) { + break; + } + } + + if (i == ice->clist.count) { + /* All checks have completed */ + on_ice_complete(ice, -1); + return PJ_TRUE; + } + + /* We still have checks to perform */ + return PJ_FALSE; +} + + static void resolver_cb(void *user_data, pj_status_t status, pj_dns_parsed_packet *response) @@ -632,8 +742,6 @@ PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); - ice_set_state(ice, PJ_ICE_STATE_CAND_COMPLETE); - return PJ_SUCCESS; } @@ -882,6 +990,7 @@ static void clist_set_state(pj_ice *ice, pj_ice_checklist *clist, clist->state = st; } +/* Sort checklist based on priority */ static void sort_checklist(pj_ice_checklist *clist) { unsigned i; @@ -905,6 +1014,31 @@ static void sort_checklist(pj_ice_checklist *clist) } } +/* Sort valid list based on priority */ +static void sort_valid_list(pj_ice *ice) +{ + unsigned i; + + for (i=0; ivalid_cnt-1; ++i) { + unsigned j, highest = i; + pj_ice_check *ci = ice->clist.checks[ice->valid_list[i]]; + + for (j=i+1; jvalid_cnt; ++j) { + pj_ice_check *cj = ice->clist.checks[ice->valid_list[j]]; + + if (cj->prio > ci->prio) { + highest = j; + } + } + + if (highest != i) { + unsigned tmp = ice->valid_list[i]; + ice->valid_list[i] = ice->valid_list[j]; + ice->valid_list[j] = tmp; + } + } +} + enum { @@ -1019,7 +1153,7 @@ PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, } /* Generate checklist */ - clist = &ice->cklist; + clist = &ice->clist; for (i=0; ilcand_cnt; ++i) { for (j=0; jrcand_cnt; ++j) { @@ -1130,10 +1264,11 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist, pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY, prio); - /* Add USE-CANDIDATE */ + /* Add USE-CANDIDATE and set this check to nominated */ if (ice->role == PJ_ICE_ROLE_CONTROLLING) { pj_stun_msg_add_empty_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_USE_CANDIDATE); + check->nominated = PJ_TRUE; } /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the @@ -1247,7 +1382,7 @@ PJ_DEF(pj_status_t) pj_ice_start_check(pj_ice *ice) LOG((ice->obj_name, "Starting ICE check..")); - clist = &ice->cklist; + clist = &ice->clist; if (clist->count == 0) return PJ_EICENOCHECKLIST; @@ -1379,20 +1514,20 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, /* Sets the state of the pair that generated the check to succeeded. */ check_set_state(ice, check, PJ_ICE_CHECK_STATE_SUCCEEDED, PJ_SUCCESS); - /* This is a valid pair, so add this to the valid list */ - valid_check = &ice->valid_list.checks[ice->valid_list.count++]; - valid_check->lcand = lcand; - valid_check->rcand = rcand; - valid_check->prio = CALC_CHECK_PRIO(ice, lcand, rcand); - valid_check->state = PJ_ICE_CHECK_STATE_SUCCEEDED; - valid_check->nominated = (pj_stun_msg_find_attr(tdata->msg, - PJ_STUN_ATTR_USE_CANDIDATE, - 0) != NULL); - valid_check->err_code = PJ_SUCCESS; + ice->valid_list[ice->valid_cnt++] = rd->ckid; /* Sort valid_list */ - sort_checklist(&ice->valid_list); + sort_valid_list(ice); + + /* Inform about check completion. + * This may terminate ICE processing. + */ + if (on_check_complete(ice, check)) { + /* ICE complete! */ + pj_mutex_unlock(ice->mutex); + return; + } /* If the pair had a component ID of 1, the agent MUST change the * states for all other Frozen pairs for the same media stream and @@ -1452,6 +1587,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, stun_data *sd; pj_ice *ice; pj_stun_priority_attr *ap; + pj_stun_use_candidate_attr *uc; pj_ice_comp *comp; pj_ice_cand *lcand; pj_ice_cand *rcand; @@ -1463,12 +1599,23 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, PJ_UNUSED_ARG(pkt); PJ_UNUSED_ARG(pkt_len); - /* Only accepts Binding request */ + /* Reject any requests except Binding request */ if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { - LOG((ice->obj_name, "Received non-Binding request, ignored")); - return PJ_SUCCESS; + pj_str_t err_msg = pj_str("Expecting Binding Request only"); + status = pj_stun_session_create_response(sess, msg, + PJ_STUN_SC_BAD_REQUEST, + &err_msg, &tdata); + if (status != PJ_SUCCESS) { + return status; + } + + status = pj_stun_session_send_msg(sess, PJ_TRUE, + src_addr, src_addr_len, tdata); + + return status; } + sd = (stun_data*) pj_stun_session_get_user_data(sess); ice = sd->ice; comp = sd->comp; @@ -1484,6 +1631,10 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, return PJ_SUCCESS; } + /* Get USE-CANDIDATE attribute */ + uc = (pj_stun_use_candidate_attr*) + pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0); + /* For simplicity, ignore incoming requests when we don't have remote * candidates yet. The peer agent should retransmit the STUN request * and we'll receive it again later. @@ -1493,6 +1644,22 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, return PJ_SUCCESS; } + /* + * First send response to this request + */ + status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(ice->mutex); + return status; + } + + status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_XOR_MAPPED_ADDR, + PJ_TRUE, src_addr, src_addr_len); + + status = pj_stun_session_send_msg(sess, PJ_TRUE, + src_addr, src_addr_len, tdata); + /* Find remote candidate based on the source transport address of * the request. @@ -1532,52 +1699,104 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE); is_relayed = PJ_FALSE; - /* Next find local candidate */ - /* Just pick up + /* Next find local candidate, by first finding a check in the checklist + * which base address is equal to the local address. + */ + for (i=0; iclist.count; ++i) { + pj_ice_check *c = &ice->clist.checks[i]; + if (sockaddr_cmp(&c->lcand->base_addr, &comp->local_addr)==0) + break; + } + /* MUST find a local candidate! */ + pj_assert(i != ice->clist.count); + if (i == ice->clist.count) { + pj_mutex_unlock(ice->mutex); + LOG((ice->obj_name, "Error: unable to find local candidate for " + "incoming request")); + return PJ_SUCCESS; + } + lcand = ice->clist.checks[i].lcand; - /* 7.2.1.2. Learning Peer Reflexive Candidates */ - PJ_TODO(LEARN_PEER_REFLEXIVE_CANDIDATES); + /* Now that we have local and remote candidate, check if we already + * have this pair in our checklist. + */ + for (i=0; iclist.count; ++i) { + pj_ice_check *c = &ice->clist.checks[i]; + if (c->lcand == lcand && c->rcand == rcand) + break; + } - /* Reject any requests except Binding request */ - if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { - status = pj_stun_session_create_response(sess, msg, - PJ_STUN_SC_BAD_REQUEST, - NULL, &tdata); - if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); - return status; + /* If the pair is already on the check list: + * - If the state of that pair is Waiting or Frozen, its state is + * changed to In-Progress and a check for that pair is performed + * immediately. This is called a triggered check. + * + * - If the state of that pair is In-Progress, the agent SHOULD + * generate an immediate retransmit of the Binding Request for the + * check in progress. This is to facilitate rapid completion of + * ICE when both agents are behind NAT. + * + * - If the state of that pair is Failed or Succeeded, no triggered + * check is sent. + */ + if (i != ice->clist.count) { + pj_ice_check *c = &ice->clist.checks[i]; + + /* If USE-CANDIDATE is present, set nominated flag */ + c->nominated = (uc != NULL); + + if (c->state == PJ_ICE_CHECK_STATE_FROZEN || + c->state == PJ_ICE_CHECK_STATE_WAITING) + { + LOG((ice->obj_name, "Performing triggered check for check %d",i)); + perform_check(ice, &ice->clist, i); + + } else if (c->state == PJ_ICE_CHECK_STATE_IN_PROGRESS) { + /* Should retransmit here, but how?? + * TODO + */ + } else if (c->state == PJ_ICE_CHECK_STATE_SUCCEEDED) { + /* Check complete for this component. + * Note this may end ICE process. + */ + pj_bool_t complete; + + complete = on_check_complete(ice, c); + if (complete) { + pj_mutex_unlock(ice->mutex); + return PJ_SUCCESS; + } } - status = pj_stun_session_send_msg(sess, PJ_TRUE, - src_addr, src_addr_len, tdata); - - pj_mutex_unlock(ice->mutex); - return status; } - - status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); - if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); - return status; - } - - status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_XOR_MAPPED_ADDR, - PJ_TRUE, src_addr, src_addr_len); - - status = pj_stun_session_send_msg(sess, PJ_TRUE, - src_addr, src_addr_len, tdata); - - /* 7.2.1.3. Triggered Checks: - * Next, the agent constructs a pair whose local candidate is equal to - * the transport address on which the STUN request was received, and a - * remote candidate equal to the source transport address where the - * request came from (which may be peer-reflexive remote candidate that - * was just learned). + /* If the pair is not already on the check list: + * - The pair is inserted into the check list based on its priority. + * - Its state is set to In-Progress + * - A triggered check for that pair is performed immediately. */ - + /* Note: only do this if we don't have too many checks in checklist */ + else if (ice->clist.count < PJ_ICE_MAX_CHECKS) { + + pj_ice_check *c = &ice->clist.checks[ice->clist.count]; + + c->lcand = lcand; + c->rcand = rcand; + c->prio = CALC_CHECK_PRIO(ice, lcand, rcand); + c->state = PJ_ICE_CHECK_STATE_WAITING; + c->nominated = (uc != NULL); + c->err_code = PJ_SUCCESS; + + LOG((ice->obj_name, "New triggered check added: %d", + ice->clist.count)); + perform_check(ice, &ice->clist, ice->clist.count++); + + } else { + LOG((ice->obj_name, "Error: unable to perform triggered check: " + "TOO MANY CHECKS IN CHECKLIST!")); + } + pj_mutex_unlock(ice->mutex); return status; } diff --git a/pjnath/src/pjnath/stun_endpoint.c b/pjnath/src/pjnath/stun_endpoint.c deleted file mode 100644 index 3be6407d6..000000000 --- a/pjnath/src/pjnath/stun_endpoint.c +++ /dev/null @@ -1,69 +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 -#include -#include -#include - - -/* - * Create a STUN endpoint instance. - */ -PJ_DEF(pj_status_t) pj_stun_config_create( pj_pool_factory *factory, - unsigned options, - pj_ioqueue_t *ioqueue, - pj_timer_heap_t *timer_heap, - pj_stun_config **p_endpt) -{ - pj_pool_t *pool; - pj_stun_config *endpt; - - PJ_ASSERT_RETURN(factory && p_endpt, PJ_EINVAL); - - pool = pj_pool_create(factory, "stunendpt", 1000, 1000, NULL); - if (!pool) - return PJ_ENOMEM; - - endpt = PJ_POOL_ZALLOC_T(pool, pj_stun_config); - endpt->pool = pool; - endpt->pf = factory; - endpt->options = options; - endpt->ioqueue = ioqueue; - endpt->timer_heap = timer_heap; - endpt->rto_msec = PJ_STUN_RTO_VALUE; - endpt->res_cache_msec = 10000; - - *p_endpt = endpt; - - return PJ_SUCCESS; -} - - -/* - * Destroy STUN endpoint instance. - */ -PJ_DEF(pj_status_t) pj_stun_config_destroy(pj_stun_config *endpt) -{ - PJ_ASSERT_RETURN(endpt, PJ_EINVAL); - - pj_pool_release(endpt->pool); - - return PJ_SUCCESS; -} - diff --git a/pjnath/src/pjnath/stun_setting.c b/pjnath/src/pjnath/stun_setting.c new file mode 100644 index 000000000..791964413 --- /dev/null +++ b/pjnath/src/pjnath/stun_setting.c @@ -0,0 +1,23 @@ +/* $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 +#include +#include +