mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-14 05:18:31 +00:00
merge with sofia darcs trunk:
Fri Oct 12 08:42:17 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * Makefile.am: fixed ordering of SUBDIRS Fri Oct 12 13:32:02 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * win32/utils/stunc.dsp: fixed include paths Fri Oct 12 13:32:19 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * win32/tests/torture_su_root: fixed include paths Fri Oct 12 13:32:52 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * win32: added missing files from Makefile.am, .dsp, vproj Fri Oct 12 13:33:42 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * win32/build_sources.cmd: added extra headers to sip_tag.c and sip_parser_table.c Fri Oct 12 13:37:00 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * win32/check.cmd: added option -a to relevant tests. Optionally check Release build. Fri Oct 12 13:37:25 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * url.h: silenced warning on URL_INIT_AS() Fri Oct 12 13:37:43 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * tstdef.h: silenced warnings on TEST_M() Fri Oct 12 13:38:15 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * nta_internal.h, nua_params.c: fixed NTATAG_UDP_MTU() type Fri Oct 12 13:39:06 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_class.h: fixed test_auth_class, test_numeric_class declaration Fri Oct 12 13:39:51 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * Fixed various tests on win32. Fri Oct 12 13:39:58 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * sip_basic.c: removed dead code Fri Oct 12 14:38:02 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * nea_server.c: avoid raporting un-SUBSCRIBE twice Fri Oct 12 14:38:31 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * test_sip_events.c: checking some nua_i_notifier/nua_i_subscriber events Fri Oct 12 14:38:42 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> tagged Release candidate 2 for 1.12.7 Mon Oct 15 04:03:22 EDT 2007 Pekka.Pessi@nokia.com * configure.ac, RELEASE: version 1.12.7 Mon Oct 15 08:27:13 EDT 2007 Pekka.Pessi@nokia.com * open_c: included in the dist Tue Oct 16 08:07:46 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * nua: Open C fixes Wed Oct 17 06:50:11 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * nua.docs: replace reference to nua_cli.c with sofsip_cli Wed Oct 17 08:43:11 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> tagged rel-sofia-sip-1_12_7 Wed Oct 17 08:43:15 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> tagged 1.12.7 Wed Oct 17 11:01:12 EDT 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * libsofia-sip-ua/su/Makefile.am: fixed problem with automake 1.9 Wed Oct 17 11:13:15 EDT 2007 Pekka.Pessi@nokia.com * configure.ac, RELEASE: opened tree for development Tue Oct 23 10:45:17 EDT 2007 Pekka.Pessi@nokia.com * su_alloc.c: fixed su_home_init() (not initializing pointer to mutexes) Thu Oct 25 13:15:45 EDT 2007 Pekka.Pessi@nokia.com * nua_notifier.c: updated nua_i_subscribe, nua_notify() and nua_r_notify documentation Wed Nov 7 07:58:08 EST 2007 Pekka.Pessi@nokia.com * sofia-sip/htable2.h: fixed HTABLE_PROTOS2() git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6219 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
1 parent
3f4fd53c97
commit
8ff118dc2c
37 files changed
+689
-300
No files matched your search
@@ -13,21 +13,25 @@ AUTOMAKE_OPTIONS = foreign
|
||||
# in the build
|
||||
OPT_LIBADD =
|
||||
OPT_SUBDIRS_STUN =
|
||||
OPT_SUBDIRS_HTTP =
|
||||
OPT_SUBDIRS_NTH =
|
||||
if HAVE_STUN
|
||||
OPT_LIBADD += stun/libstun.la
|
||||
OPT_SUBDIRS_STUN += stun
|
||||
endif
|
||||
if HAVE_NTH
|
||||
OPT_LIBADD += nth/libnth.la http/libhttp.la
|
||||
OPT_SUBDIRS_NTH += nth http
|
||||
OPT_LIBADD += http/libhttp.la nth/libnth.la
|
||||
OPT_SUBDIRS_HTTP += http
|
||||
OPT_SUBDIRS_NTH += nth
|
||||
endif
|
||||
|
||||
# note: order does matter in the subdir list
|
||||
SUBDIRS = su features bnf sresolv sdp url msg sip $(OPT_SUBDIRS_STUN) ipt soa \
|
||||
tport nta nea iptsec $(OPT_SUBDIRS_NTH) nua
|
||||
DIST_SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
|
||||
tport nta nea iptsec nth http nua docs
|
||||
SUBDIRS = su features bnf sresolv ipt sdp url msg sip $(OPT_SUBDIRS_HTTP) \
|
||||
$(OPT_SUBDIRS_STUN) soa tport nta $(OPT_SUBDIRS_NTH) \
|
||||
nea iptsec nua
|
||||
DIST_SUBDIRS = su features bnf sresolv ipt sdp url msg sip http \
|
||||
stun soa tport nta nth \
|
||||
nea iptsec nua docs
|
||||
|
||||
DOXYGEN = doxygen
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ enum {
|
||||
msg_numeric_hash = 24435
|
||||
};
|
||||
|
||||
SOFIAPUBVAR msg_hclass_t test_auth_class[1], test_numeric_class[1];
|
||||
extern msg_hclass_t test_auth_class[1], test_numeric_class[1];
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
|
||||
@@ -201,6 +201,8 @@ struct nea_sub_s {
|
||||
sip_content_type_t *s_content_type; /** Content-Type of SUBSCRIBE body. */
|
||||
sip_payload_t *s_payload; /**< Body of SUBSCRIBE. */
|
||||
|
||||
unsigned s_reported :1 ; /**< Made watcher report upon un-SUBSCRIBE */
|
||||
|
||||
unsigned s_processing : 1;
|
||||
unsigned s_rejected : 1;
|
||||
unsigned s_pending_flush : 1;
|
||||
@@ -1384,14 +1386,18 @@ static
|
||||
int nes_watcher_callback(nea_server_t *nes,
|
||||
nea_event_t *ev,
|
||||
nea_sub_t *s,
|
||||
sip_t const *sip)
|
||||
sip_t const *sip,
|
||||
sip_time_t now)
|
||||
{
|
||||
if (!nes->nes_in_callback) {
|
||||
nes->nes_in_callback = 1;
|
||||
if (ev->ev_callback) {
|
||||
if (ev->ev_callback && !s->s_reported) {
|
||||
nea_subnode_t sn[1];
|
||||
|
||||
nea_subnode_init(sn, s, sip_now());
|
||||
nea_subnode_init(sn, s, now);
|
||||
|
||||
if (sn->sn_expires == 0 || sn->sn_state == nea_terminated)
|
||||
s->s_reported = 1;
|
||||
|
||||
ev->ev_callback(nes, ev->ev_magic, ev, sn, sip);
|
||||
}
|
||||
@@ -1908,13 +1914,15 @@ int nea_sub_process_subscribe(nea_sub_t *s,
|
||||
}
|
||||
|
||||
/* Callback for checking subscriber authorization */
|
||||
if (nes_watcher_callback(nes, ev, s, sip) < 0) {
|
||||
if (nes_watcher_callback(nes, ev, s, sip, now) < 0) {
|
||||
if (irq) {
|
||||
nta_incoming_treply(irq, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
|
||||
nta_incoming_destroy(irq);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
evv = s->s_view; /* Callback can change event view */
|
||||
|
||||
@@ -1975,7 +1983,7 @@ int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
|
||||
{
|
||||
int notified = 0;
|
||||
ta_list ta;
|
||||
int subscription_state_change = now == 0;
|
||||
int suppress = now != 0;
|
||||
nea_event_t *ev = s->s_event;
|
||||
nea_state_t substate = s->s_state;
|
||||
|
||||
@@ -1990,7 +1998,7 @@ int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
|
||||
|
||||
assert(s->s_view); assert(ev);
|
||||
|
||||
if (!subscription_state_change && s->s_view->evv_updated == s->s_updated)
|
||||
if (suppress && s->s_view->evv_updated == s->s_updated)
|
||||
return 0;
|
||||
|
||||
if (now == 0)
|
||||
@@ -2069,7 +2077,7 @@ int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
|
||||
break;
|
||||
}
|
||||
|
||||
subscription_state_change = (s->s_view->evv_updated == s->s_updated);
|
||||
suppress = (s->s_view->evv_updated == s->s_updated);
|
||||
|
||||
n_evq = evq->evq_payload ? evq : evv->evv_primary->evv_head;
|
||||
|
||||
@@ -2083,9 +2091,9 @@ int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
|
||||
SIPTAG_USER_AGENT_STR(nes->nes_server),
|
||||
SIPTAG_CONTACT(s->s_local),
|
||||
SIPTAG_EVENT(s->s_id),
|
||||
TAG_IF(!subscription_state_change,
|
||||
TAG_IF(!suppress,
|
||||
SIPTAG_CONTENT_TYPE(n_evq->evq_content_type)),
|
||||
TAG_IF(!subscription_state_change,
|
||||
TAG_IF(!suppress,
|
||||
SIPTAG_PAYLOAD(n_evq->evq_payload)),
|
||||
ta_tags(ta));
|
||||
|
||||
@@ -2104,7 +2112,7 @@ int nea_sub_notify(nea_server_t *nes, nea_sub_t *s,
|
||||
if (callback == NULL) {
|
||||
nta_outgoing_destroy(s->s_oreq), s->s_oreq = NULL;
|
||||
/* Inform the application of a subscriber leaving the subscription. */
|
||||
nes_watcher_callback(nes, ev, s, NULL);
|
||||
nes_watcher_callback(nes, ev, s, NULL, now);
|
||||
}
|
||||
}
|
||||
ta_end(ta);
|
||||
@@ -2127,6 +2135,7 @@ int response_to_notify(nea_sub_t *s,
|
||||
{
|
||||
nea_server_t *nes = s->s_nes;
|
||||
int status = sip->sip_status->st_status;
|
||||
sip_time_t now = sip_now();
|
||||
|
||||
if (status < 200)
|
||||
return 0;
|
||||
@@ -2135,8 +2144,6 @@ int response_to_notify(nea_sub_t *s,
|
||||
|
||||
if (status < 300) {
|
||||
if (s->s_view->evv_updated != s->s_updated) {
|
||||
sip_time_t now = sip_now();
|
||||
|
||||
if (s->s_notified + s->s_throttle <= now)
|
||||
nea_sub_notify(nes, s, now, TAG_END());
|
||||
else
|
||||
@@ -2148,7 +2155,7 @@ int response_to_notify(nea_sub_t *s,
|
||||
SU_DEBUG_5(("nea_server: removing subscriber " URL_PRINT_FORMAT "\n",
|
||||
URL_PRINT_ARGS(s->s_from->a_url)));
|
||||
/* Inform the application of a subscriber leaving the subscription. */
|
||||
nes_watcher_callback(nes, s->s_event, s, NULL);
|
||||
nes_watcher_callback(nes, s->s_event, s, NULL, now);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -332,15 +332,15 @@ message sequence charts.
|
||||
|
||||
@image html SIP_outgoing_operation_with_auth.gif
|
||||
|
||||
|
||||
@section nua_simpleapplication Simple Application
|
||||
|
||||
The following sections will present code examples from a simple application
|
||||
that uses services of NUA. The example is not complete but should present
|
||||
all relevant details of the basic use of NUA.
|
||||
|
||||
The source distribution of Sofia stack contains in directory nua an example
|
||||
application nua_cli.c that can be studied for more complete example.
|
||||
On sourceforge.net there is available an example application
|
||||
<a href="http://sourceforge.net/project/showfiles.php?group_id=143636&package_id=179933">
|
||||
sofisip_cli.c</a> that can be studied for more complete example.
|
||||
|
||||
@subsection nua_datastructures Data Structures & Defines
|
||||
|
||||
|
||||
@@ -129,28 +129,6 @@ void nua_notify_usage_remove(nua_handle_t *nh,
|
||||
* @b SUBSCRIBE request is used to query SIP event state or establish a SIP
|
||||
* event subscription.
|
||||
*
|
||||
* Initial SUBSCRIBE requests are dropped with <i>489 Bad Event</i>
|
||||
* response, unless the application has explicitly included the @Event in
|
||||
* the list of allowed events with nua_set_params() tag NUTAG_ALLOW_EVENTS()
|
||||
* (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). The application
|
||||
* can decide whether to accept the SUBSCRIBE request or reject it. The
|
||||
* nua_response() call responding to a SUBSCRIBE request must have
|
||||
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag.
|
||||
*
|
||||
* If the application accepts the SUBSCRIBE request, it must immediately
|
||||
* send an initial NOTIFY establishing the dialog. This is because the
|
||||
* response to the SUBSCRIBE request may be lost because the SUBSCRIBE
|
||||
* request was forked by an intermediate proxy.
|
||||
*
|
||||
* SUBSCRIBE requests modifying (usually refreshing or terminating) an
|
||||
* existing event subscription are accepted by default and a <i>200 OK</i>
|
||||
* response along with a copy of previously sent NOTIFY is sent
|
||||
* automatically.
|
||||
*
|
||||
* By default, only event subscriptions accepted are those created
|
||||
* implicitly by REFER request. See #nua_i_refer how the application must
|
||||
* handle the REFER requests.
|
||||
*
|
||||
* @param status status code of response sent automatically by stack
|
||||
* @param phrase response phrase sent automatically by stack
|
||||
* @param nh operation handle associated with the incoming request
|
||||
@@ -159,6 +137,46 @@ void nua_notify_usage_remove(nua_handle_t *nh,
|
||||
* @param sip SUBSCRIBE request headers
|
||||
* @param tags NUTAG_SUBSTATE()
|
||||
*
|
||||
* Initial SUBSCRIBE requests are dropped with <i>489 Bad Event</i>
|
||||
* response, unless the application has explicitly included the @Event in
|
||||
* the list of allowed events with nua_set_params() tag NUTAG_ALLOW_EVENTS()
|
||||
* (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()).
|
||||
*
|
||||
* If the event has been allowed the application
|
||||
* can decide whether to accept the SUBSCRIBE request or reject it. The
|
||||
* nua_response() call responding to a SUBSCRIBE request must have
|
||||
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag.
|
||||
*
|
||||
* If the application accepts the SUBSCRIBE request, it must immediately
|
||||
* send an initial NOTIFY establishing the dialog. This is because the
|
||||
* response to the SUBSCRIBE request may be lost by an intermediate proxy
|
||||
* because it had forked the SUBSCRIBE request.
|
||||
*
|
||||
* SUBSCRIBE requests modifying (usually refreshing or terminating) an
|
||||
* existing event subscription are accepted by default and a <i>200 OK</i>
|
||||
* response along with a copy of previously sent NOTIFY is sent
|
||||
* automatically to the subscriber.
|
||||
*
|
||||
* By default, only event subscriptions accepted are those created
|
||||
* implicitly by REFER request. See #nua_i_refer how the application must
|
||||
* handle the REFER requests.
|
||||
*
|
||||
* @par Subscription Lifetime and Terminating Subscriptions
|
||||
*
|
||||
* Accepting the SUBSCRIBE request creates a dialog with a <i>notifier
|
||||
* dialog usage</i> on the handle. The dialog usage is active, until the
|
||||
* subscriber terminates the subscription, it times out or the application
|
||||
* terminates the usage with nua_notify() call containing the tag
|
||||
* NUTAG_SUBSTATE(nua_substate_terminated) or @SubscriptionState header with
|
||||
* state "terminated" and/or expiration time 0.
|
||||
*
|
||||
* When the subscriber terminates the subscription, the application is
|
||||
* notified of an termination by a #nua_i_subscribe event with
|
||||
* NUTAG_SUBSTATE(nua_substate_terminated) tag. When the subscription times
|
||||
* out, nua automatically initiates a NOTIFY transaction. When it is
|
||||
* terminated, the application is sent a #nua_r_notify event with
|
||||
* NUTAG_SUBSTATE(nua_substate_terminated) tag.
|
||||
*
|
||||
* @sa @RFC3265, nua_notify(), NUTAG_SUBSTATE(), @SubscriptionState,
|
||||
* @Event, nua_subscribe(), #nua_r_subscribe, #nua_i_refer, nua_refer()
|
||||
*
|
||||
@@ -351,11 +369,22 @@ int nua_subscribe_server_report(nua_server_request_t *sr, tagi_t const *tags)
|
||||
*
|
||||
* This function is used when the application implements itself the
|
||||
* notifier. The application must provide valid @SubscriptionState and
|
||||
* @Event headers using SIP tags. If there is no @SubscriptionState header,
|
||||
* the subscription state can be modified with NUTAG_SUBSTATE().
|
||||
* @Event headers using SIP tags. The subscription state can be modified
|
||||
* with NUTAG_SUBSTATE(), however, its effect is overriden by
|
||||
* @SubscriptionState header included in the nua_notify() tags.
|
||||
*
|
||||
* @bug If the @Event is not given by application, stack uses the @Event
|
||||
* header from the first subscription usage on handle.
|
||||
*
|
||||
* If there is no active <i>notifier dialog usage</i> or no notifier dialog
|
||||
* usage matches the @Event header given by the application the nua_notify()
|
||||
* request is rejected locally by the stack with status code 481. The local
|
||||
* rejection can be bypassed if NUTAG_NEWSUB(1) is included in tags.
|
||||
*
|
||||
* Please note that including NUTAG_NEWSUB(1) in nua_notify() tags if there
|
||||
* is a valid subscription may lead to an extra NOTIFY sent to subscriber if
|
||||
* the subscription had been terminated by the subscriber or by a timeout
|
||||
* before the nua_notify() is processed.
|
||||
*
|
||||
* @param nh Pointer to operation handle
|
||||
* @param tag, value, ... List of tagged parameters
|
||||
@@ -365,6 +394,7 @@ int nua_subscribe_server_report(nua_server_request_t *sr, tagi_t const *tags)
|
||||
*
|
||||
* @par Related Tags:
|
||||
* NUTAG_SUBSTATE() \n
|
||||
* NUTAG_NEWSUB() \n
|
||||
* Tags of nua_set_hparams() \n
|
||||
* Header tags defined in <sofia-sip/sip_tag.h>
|
||||
*
|
||||
@@ -461,8 +491,11 @@ static int nua_notify_client_init(nua_client_request_t *cr,
|
||||
if (now + expires < now)
|
||||
expires = SIP_TIME_MAX - now - 1;
|
||||
|
||||
/* Notifier can only shorten the subscription time */
|
||||
if (nu->nu_requested == 0 || nu->nu_requested >= now + expires)
|
||||
/* We can change the lifetime of unsolicited subscription at will */
|
||||
if (nu->nu_requested == 0)
|
||||
nu->nu_expires = nu->nu_requested = now + expires;
|
||||
/* Notifier can only shorten the subscribed time */
|
||||
else if (nu->nu_requested >= now + expires)
|
||||
nu->nu_expires = nu->nu_requested = now + expires;
|
||||
}
|
||||
}
|
||||
@@ -648,7 +681,12 @@ int nua_notify_client_request(nua_client_request_t *cr,
|
||||
* The @b NOTIFY may be sent explicitly by nua_notify() or implicitly by NUA
|
||||
* state machine. Implicit @b NOTIFY is sent when an established dialog is
|
||||
* refreshed by client or it is terminated (either by client or because of a
|
||||
* timeout)
|
||||
* timeout).
|
||||
*
|
||||
* The current subscription state is included in NUTAG_SUBSTATE() tag. The
|
||||
* nua_substate_terminated indicates that the subscription is terminated,
|
||||
* the notifier usage has been removed and when there was no other usages of
|
||||
* the dialog the dialog state is also removed.
|
||||
*
|
||||
* @param status response status code
|
||||
* (if the request is retried, @a status is 100, the @a
|
||||
@@ -663,7 +701,7 @@ int nua_notify_client_request(nua_client_request_t *cr,
|
||||
* @param tags NUTAG_SUBSTATE() indicating subscription state
|
||||
* SIPTAG_EVENT() indicating subscription event
|
||||
*
|
||||
* @sa nua_notify(), @RFC3265, #nua_i_subscribe, #nua_i_refer
|
||||
* @sa nua_notify(), @RFC3265, #nua_i_subscribe, #nua_i_refer, NUTAG_SUBSTATE()
|
||||
*
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
@@ -1525,7 +1525,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
sip_contact_t const *m;
|
||||
|
||||
/* nta */
|
||||
usize_t udp_mtu = 0;
|
||||
unsigned udp_mtu = 0;
|
||||
usize_t max_proceeding = 0;
|
||||
unsigned sip_t1 = 0, sip_t2 = 0, sip_t4 = 0, sip_t1x64 = 0;
|
||||
unsigned debug_drop_prob = 0;
|
||||
|
||||
@@ -1003,6 +1003,7 @@ void nua_register_connection_closed(tp_stack_t *sip_stack,
|
||||
msg_t *msg,
|
||||
int error)
|
||||
{
|
||||
nua_dialog_usage_t *du = nua_dialog_usage_public(nr);
|
||||
tp_name_t const *tpn;
|
||||
int pending = nr->nr_error_report_id;
|
||||
|
||||
@@ -1018,7 +1019,7 @@ void nua_register_connection_closed(tp_stack_t *sip_stack,
|
||||
tpn = tport_name(nr->nr_tport);
|
||||
|
||||
SU_DEBUG_5(("nua_register(%p): tport to %s/%s:%s%s%s closed %s\n",
|
||||
nua_dialog_usage_public(nr)->du_dialog->ds_owner,
|
||||
du->du_dialog->ds_owner,
|
||||
tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
|
||||
tpn->tpn_comp ? ";comp=" : "",
|
||||
tpn->tpn_comp ? tpn->tpn_comp : "",
|
||||
@@ -1027,7 +1028,7 @@ void nua_register_connection_closed(tp_stack_t *sip_stack,
|
||||
tport_unref(nr->nr_tport), nr->nr_tport = NULL;
|
||||
|
||||
/* Schedule re-REGISTER immediately */
|
||||
nua_dialog_usage_set_refresh_range(nua_dialog_usage_public(nr), 0, 0);
|
||||
nua_dialog_usage_set_refresh_range(du, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -330,8 +330,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
ctx->a.printer = o_events_init ? print_event : NULL;
|
||||
|
||||
sleep(2);
|
||||
|
||||
retval |= test_nua_api_errors(ctx); SINGLE_FAILURE_CHECK();
|
||||
|
||||
retval |= test_tag_filter(); SINGLE_FAILURE_CHECK();
|
||||
|
||||
@@ -86,7 +86,7 @@ STORAGE void PREFIX ##_remove(T *node) \
|
||||
} \
|
||||
extern int LIST_DUMMY_VARIABLE
|
||||
|
||||
#include <test_proxy.h>
|
||||
#include "test_proxy.h"
|
||||
#include <sofia-sip/auth_module.h>
|
||||
|
||||
struct proxy {
|
||||
|
||||
@@ -99,6 +99,7 @@ int test_events(struct context *ctx)
|
||||
sip_t const *sip;
|
||||
tagi_t const *t, *n_tags, *r_tags;
|
||||
url_t b_url[1];
|
||||
enum nua_substate substate;
|
||||
nea_sub_t *sub = NULL;
|
||||
|
||||
char const open[] =
|
||||
@@ -207,7 +208,7 @@ int test_events(struct context *ctx)
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, save_until_notified_and_responded,
|
||||
-1, NULL /* XXX save_until_received */);
|
||||
-1, save_until_received);
|
||||
|
||||
/* Client events:
|
||||
nua_subscribe(), nua_i_notify/nua_r_subscribe
|
||||
@@ -242,6 +243,9 @@ int test_events(struct context *ctx)
|
||||
TEST_1(!en->next || !es->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/* XXX --- Do not check server side events */
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-12.2: PASSED\n");
|
||||
|
||||
@@ -266,8 +270,7 @@ int test_events(struct context *ctx)
|
||||
SIPTAG_PAYLOAD_STR(open),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, save_until_notified,
|
||||
-1, NULL /* XXX save_until_received */);
|
||||
run_ab_until(ctx, -1, save_until_notified, -1, save_until_received);
|
||||
|
||||
/* subscriber events:
|
||||
nua_i_notify
|
||||
@@ -287,6 +290,9 @@ int test_events(struct context *ctx)
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/* XXX --- Do not check server side events */
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-12.3: PASSED\n");
|
||||
|
||||
@@ -308,7 +314,7 @@ int test_events(struct context *ctx)
|
||||
UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, save_until_final_response,
|
||||
-1, NULL /* XXX save_until_received */);
|
||||
-1, save_until_subscription);
|
||||
|
||||
/* Client events:
|
||||
nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
|
||||
@@ -335,6 +341,19 @@ int test_events(struct context *ctx)
|
||||
/* TEST_1(!e->next); */
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/* Server events: nua_i_subscription with terminated status */
|
||||
TEST_1(e = b->events->head);
|
||||
TEST_E(e->data->e_event, nua_i_subscription);
|
||||
TEST(tl_gets(e->data->e_tags,
|
||||
NEATAG_SUB_REF(sub),
|
||||
NUTAG_SUBSTATE_REF(substate),
|
||||
TAG_END()), 2);
|
||||
TEST_1(sub);
|
||||
TEST(substate, nua_substate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-12.5: PASSED\n");
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ bin_PROGRAMS = addrinfo localinfo
|
||||
|
||||
check_PROGRAMS = torture_su torture_su_port \
|
||||
torture_su_alloc torture_su_time torture_su_tag \
|
||||
test_htable torture_rbtree torture_heap \
|
||||
test_htable test_htable2 torture_rbtree torture_heap \
|
||||
test_memmem torture_su_bm \
|
||||
torture_su_root torture_su_timer \
|
||||
test_su su_proxy test_poll $(OSXPROGS)
|
||||
@@ -28,7 +28,7 @@ check_PROGRAMS = torture_su torture_su_port \
|
||||
|
||||
TESTS = torture_su torture_su_port \
|
||||
torture_su_alloc torture_su_time torture_su_tag \
|
||||
test_htable torture_rbtree torture_heap \
|
||||
test_htable test_htable2 torture_rbtree torture_heap \
|
||||
test_memmem torture_su_bm \
|
||||
torture_su_root torture_su_timer \
|
||||
run_addrinfo run_localinfo run_test_su \
|
||||
@@ -80,7 +80,11 @@ EXTRA_libsu_la_SOURCES = \
|
||||
memmem.c strtoull.c strcasestr.c \
|
||||
memspn.c memcspn.c memccpy.c \
|
||||
inet_ntop.c inet_pton.c poll.c getopt.c \
|
||||
su_tag_ref.c su_win32_port.c
|
||||
su_tag_ref.c
|
||||
|
||||
# Automake 1.9 complains about missing CXX
|
||||
EXTRA_DIST = su_win32_port.c \
|
||||
su_open_c_localinfo.cpp
|
||||
|
||||
libsu_la_LIBADD = $(REPLACE_LIBADD)
|
||||
libsu_la_DEPENDENCIES = $(REPLACE_LIBADD)
|
||||
@@ -92,7 +96,7 @@ LDADD = libsu.la
|
||||
# ----------------------------------------------------------------------
|
||||
# Install and distribution rules
|
||||
|
||||
EXTRA_DIST = su.docs \
|
||||
EXTRA_DIST += su.docs \
|
||||
run_addrinfo run_localinfo run_test_su
|
||||
|
||||
dist_pkgdata_SCRIPTS = tag_dll.awk
|
||||
|
||||
@@ -141,6 +141,8 @@ int prefix##_resize(su_home_t *home, \
|
||||
new_size = 2 * pr->pr##_size + 1; \
|
||||
if (new_size < HTABLE_MIN_SIZE) \
|
||||
new_size = HTABLE_MIN_SIZE; \
|
||||
if (new_size < 5 * pr->pr##_used / 4) \
|
||||
new_size = 5 * pr->pr##_used / 4; \
|
||||
\
|
||||
if (!(new_hash = su_zalloc(home, sizeof(*new_hash) * new_size))) \
|
||||
return -1; \
|
||||
@@ -169,6 +171,8 @@ int prefix##_resize(su_home_t *home, \
|
||||
pr->pr##_table = new_hash, pr->pr##_size = new_size; \
|
||||
\
|
||||
assert(pr->pr##_used == used); \
|
||||
\
|
||||
su_free(home, old_hash); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
*
|
||||
* Hash tables templates, take 2.
|
||||
*
|
||||
* Note: this version can handle structures as entries, and it can be used
|
||||
* without <sofia-sip/su_alloc.h>.
|
||||
* Note: this version stores the given element types as entries (instead of
|
||||
* always storing a pointer to element). It can be used without
|
||||
* <sofia-sip/su_alloc.h>.
|
||||
*
|
||||
* This file contain a hash table template for C. The hash tables are
|
||||
* resizeable, and they usually contain pointers to entries. The
|
||||
@@ -66,21 +67,24 @@ typedef unsigned long hash_value_t;
|
||||
|
||||
/** Declare hash table structure type.
|
||||
*
|
||||
* The macro HTABLE2_DECLARE() expands to a declaration for hash table
|
||||
* structure. The its typedef will be <em>prefix</em><code>_t</code>, the
|
||||
* field names start with @a pr. The entry type is @a entrytype.
|
||||
* The macro HTABLE2_DECLARE2() expands to a declaration for hash table
|
||||
* structure. The its typedef will be @a type, the field names start with @a
|
||||
* pr. The entry type is @a entrytype.
|
||||
*
|
||||
* @param type hash table typedef
|
||||
* @param sname name of struct
|
||||
* @param prefix hash table type and function prefix
|
||||
* @param pr hash table field prefix
|
||||
* @param entrytype entry type
|
||||
*/
|
||||
#define HTABLE2_DECLARE2(type, sname, pr, entrytype, size_t) \
|
||||
typedef struct sname { \
|
||||
size_t pr##size; \
|
||||
size_t pr##used; \
|
||||
entrytype *pr##table; \
|
||||
} type
|
||||
|
||||
#define HTABLE2_DECLARE(sname, prefix, pr, entrytype) \
|
||||
struct sname { \
|
||||
unsigned pr##size; \
|
||||
unsigned pr##used; \
|
||||
entrytype *pr##table; /**< Hash table itself */ \
|
||||
}
|
||||
HTABLE2_DECLARE2(prefix##t, sname, pr, entrytype, unsigned)
|
||||
|
||||
#ifndef HTABLE2_SCOPE
|
||||
/** Default scope for hash table functions. */
|
||||
@@ -89,27 +93,30 @@ struct sname { \
|
||||
|
||||
/** Prototypes for hash table
|
||||
*
|
||||
* The macro HTABLE2_PROTOS() expands to the prototypes of hash table
|
||||
* The macro HTABLE2_PROTOS2() expands to the prototypes of hash table
|
||||
* functions. The function and type names start with @a prefix, the field
|
||||
* names start with @a pr. The entry type is @a entrytype.
|
||||
|
||||
*
|
||||
* @param type hash table typedef
|
||||
* @param prefix function prefix
|
||||
* @param pr hash table field prefix
|
||||
* @param pr hash table field prefix (not used)
|
||||
* @param entrytype entry type
|
||||
*/
|
||||
#define HTABLE2_PROTOS(type, prefix, pr, entrytype) \
|
||||
HTABLE2_SCOPE int prefix##_resize(void *a, type pr[1], unsigned); \
|
||||
#define HTABLE2_PROTOS2(type, prefix, pr, entrytype, size_t) \
|
||||
HTABLE2_SCOPE int prefix##_resize(void *a, type *, size_t); \
|
||||
HTABLE2_SCOPE int prefix##_is_full(type const *); \
|
||||
HTABLE2_SCOPE entrytype *prefix##_hash(type const *, hash_value_t hv); \
|
||||
HTABLE2_SCOPE entrytype *prefix##_next(type const *, entrytype *ee); \
|
||||
HTABLE2_SCOPE void prefix##_append(type *pr, entrytype e); \
|
||||
HTABLE2_SCOPE void prefix##_insert(type *pr, entrytype e); \
|
||||
HTABLE2_SCOPE int prefix##_remove(type *, entrytype const e)
|
||||
HTABLE2_SCOPE entrytype *prefix##_hash(type const *, hash_value_t); \
|
||||
HTABLE2_SCOPE entrytype *prefix##_next(type const *, entrytype *); \
|
||||
HTABLE2_SCOPE entrytype *prefix##_append(type *, entrytype); \
|
||||
HTABLE2_SCOPE entrytype *prefix##_insert(type *, entrytype); \
|
||||
HTABLE2_SCOPE int prefix##_remove(type *, entrytype const)
|
||||
|
||||
#define HTABLE2_PROTOS(type, prefix, pr, entrytype) \
|
||||
HTABLE2_PROTOS2(type, prefix, pr, entrytype, unsigned)
|
||||
|
||||
/** Hash table implementation.
|
||||
*
|
||||
* The macro HTABLE2_BODIES() expands the hash table functions. The function
|
||||
* The macro HTABLE2_BODIES2() expands the hash table functions. The function
|
||||
* and type names start with @a prefix, the field names start with @a pr.
|
||||
* The entry type is @a entrytype. The function (or macro) name returning
|
||||
* hash value of each entry is given as @a hfun.
|
||||
@@ -118,25 +125,26 @@ HTABLE2_SCOPE int prefix##_remove(type *, entrytype const e)
|
||||
* @param prefix function prefix for hash table
|
||||
* @param pr field prefix for hash table
|
||||
* @param entrytype type of entry element
|
||||
* @param size_t size_t type
|
||||
* @param hfun function or macro returning hash value of entry
|
||||
* @param is_used function or macro returning true if entry is occupied
|
||||
* @param reclaim function or macro zeroing entry
|
||||
* @param is_equal equality test
|
||||
* @param halloc function allocating or freeing memory
|
||||
*/
|
||||
#define HTABLE2_BODIES(type, prefix, pr, entrytype, \
|
||||
hfun, is_used, reclaim, is_equal, halloc) \
|
||||
#define HTABLE2_BODIES2(type, prefix, pr, entrytype, size_t, \
|
||||
hfun, is_used, reclaim, is_equal, halloc) \
|
||||
/** Reallocate new hash table */ \
|
||||
HTABLE2_SCOPE \
|
||||
int prefix##_resize(void *realloc_arg, \
|
||||
type pr[1], \
|
||||
unsigned new_size) \
|
||||
usize_t new_size) \
|
||||
{ \
|
||||
entrytype *new_hash; \
|
||||
entrytype *old_hash = pr->pr##table; \
|
||||
unsigned old_size; \
|
||||
unsigned i, j, i0; \
|
||||
unsigned again = 0, used = 0, collisions = 0; \
|
||||
usize_t old_size; \
|
||||
usize_t i, j, i0; \
|
||||
usize_t again = 0, used = 0, collisions = 0; \
|
||||
\
|
||||
(void)realloc_arg; \
|
||||
\
|
||||
@@ -144,11 +152,15 @@ int prefix##_resize(void *realloc_arg, \
|
||||
new_size = 2 * pr->pr##size + 1; \
|
||||
if (new_size < HTABLE2_MIN_SIZE) \
|
||||
new_size = HTABLE2_MIN_SIZE; \
|
||||
if (new_size < 5 * pr->pr##used / 4) \
|
||||
new_size = 5 * pr->pr##used / 4; \
|
||||
\
|
||||
if (!(new_hash = halloc(realloc_arg, NULL, sizeof(*new_hash) * new_size))) \
|
||||
return -1; \
|
||||
\
|
||||
memset(new_hash, 0, sizeof(*new_hash) * new_size); \
|
||||
for (i = 0; i < new_size; i++) { \
|
||||
(reclaim(&new_hash[i])); \
|
||||
} \
|
||||
old_size = pr->pr##size; \
|
||||
\
|
||||
do for (j = 0; j < old_size; j++) { \
|
||||
@@ -202,9 +214,13 @@ entrytype *prefix##_next(type const *pr, entrytype *ee) \
|
||||
} \
|
||||
\
|
||||
HTABLE2_SCOPE \
|
||||
void prefix##_append(type *pr, entrytype e) \
|
||||
entrytype *prefix##_append(type *pr, entrytype e) \
|
||||
{ \
|
||||
entrytype *ee; \
|
||||
\
|
||||
assert(pr->pr##used < pr->pr##size); \
|
||||
if (pr->pr##used == pr->pr##size) \
|
||||
return (entrytype *)0; \
|
||||
\
|
||||
pr->pr##used++; \
|
||||
for (ee = prefix##_hash(pr, hfun(e)); \
|
||||
@@ -212,13 +228,19 @@ void prefix##_append(type *pr, entrytype e) \
|
||||
ee = prefix##_next(pr, ee)) \
|
||||
; \
|
||||
*ee = e; \
|
||||
\
|
||||
return ee; \
|
||||
} \
|
||||
\
|
||||
HTABLE2_SCOPE \
|
||||
void prefix##_insert(type *pr, entrytype e) \
|
||||
entrytype *prefix##_insert(type *pr, entrytype e) \
|
||||
{ \
|
||||
entrytype e0; \
|
||||
entrytype *ee; \
|
||||
\
|
||||
assert(pr->pr##used < pr->pr##size); \
|
||||
if (pr->pr##used == pr->pr##size) \
|
||||
return (entrytype *)0; \
|
||||
\
|
||||
pr->pr##used++; \
|
||||
/* Insert entry into hash table (before other entries with same hash) */ \
|
||||
@@ -227,12 +249,14 @@ void prefix##_insert(type *pr, entrytype e) \
|
||||
ee = prefix##_next(pr, ee)) \
|
||||
*ee = e, e = e0; \
|
||||
*ee = e; \
|
||||
\
|
||||
return ee; \
|
||||
} \
|
||||
\
|
||||
HTABLE2_SCOPE \
|
||||
int prefix##_remove(type *pr, entrytype const e) \
|
||||
{ \
|
||||
unsigned i, j, k, size = pr->pr##size; \
|
||||
usize_t i, j, k, size = pr->pr##size; \
|
||||
entrytype *htable = pr->pr##table; \
|
||||
\
|
||||
/* Search for entry */ \
|
||||
@@ -263,4 +287,10 @@ int prefix##_remove(type *pr, entrytype const e) \
|
||||
} \
|
||||
extern int const prefix##_dummy
|
||||
|
||||
#define HTABLE2_BODIES(type, prefix, pr, entrytype, \
|
||||
hfun, is_used, reclaim, is_equal, halloc) \
|
||||
HTABLE2_BODIES2(type, prefix, pr, entrytype, unsigned, \
|
||||
hfun, is_used, reclaim, is_equal, halloc)
|
||||
|
||||
|
||||
#endif /** !defined(HTABLE2_H) */
|
||||
@@ -319,13 +319,13 @@ enum {
|
||||
/** @HIDE */
|
||||
#define TEST_M_(flags, suite, expect, len) do { \
|
||||
void const * _value, * _expect; \
|
||||
int _len; \
|
||||
size_t _len; \
|
||||
if (flags & tst_verbatim) { \
|
||||
printf("%s: %s%stesting %s is %s\n", TSTNAME, #suite, #expect); \
|
||||
fflush(stdout); } \
|
||||
_value = (suite); \
|
||||
_expect = (expect); \
|
||||
_len = (len); \
|
||||
_len = (size_t)(len); \
|
||||
if (((_value == NULL || _expect == NULL) && _value == _expect) || \
|
||||
memcmp(_value, _expect, _len) == 0) \
|
||||
{ if (flags & tst_verbatim) \
|
||||
@@ -333,7 +333,8 @@ enum {
|
||||
fprintf(stderr, "%s:%u: %s %s%sFAILED: %s != %s "\
|
||||
"or \"%.*s\" != \"%.*s\"\n", \
|
||||
__FILE__, __LINE__, TSTNAME, \
|
||||
#suite, #expect, _len, (char *)_value, _len, (char *)_expect); \
|
||||
#suite, #expect, (int)_len, \
|
||||
(char *)_value, (int)_len, (char *)_expect); \
|
||||
fflush(stderr); \
|
||||
TEST_FAILED(flags); \
|
||||
} while(0)
|
||||
|
||||
@@ -915,6 +915,11 @@ void su_home_destroy(su_home_t *home)
|
||||
* @retval -1 upon an error.
|
||||
*
|
||||
* @sa SU_HOME_INIT(), su_home_deinit(), su_home_new(), su_home_clone()
|
||||
*
|
||||
* @bug
|
||||
* Prior to @VERSION_1_12_8 the su_home_t structure should have been
|
||||
* initialized with SU_HOME_INIT() or otherwise zeroed before calling
|
||||
* su_home_init().
|
||||
*/
|
||||
int su_home_init(su_home_t *home)
|
||||
{
|
||||
@@ -924,6 +929,8 @@ int su_home_init(su_home_t *home)
|
||||
return -1;
|
||||
|
||||
home->suh_blocks = sub = su_hash_alloc(SUB_N);
|
||||
home->suh_lock = NULL;
|
||||
|
||||
if (!sub)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -157,18 +157,23 @@ void zap(context_t *c, entry_t *e)
|
||||
su_free(c->c_home, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that all n entries with hash h are in hash table
|
||||
* and they are stored in same order
|
||||
* in which they were added to the hash
|
||||
*/
|
||||
static unsigned long count(context_t *c, hash_value_t h)
|
||||
{
|
||||
entry_t *e, **ee;
|
||||
unsigned long n;
|
||||
unsigned long n, expect = 1;
|
||||
|
||||
for (ee = htable_hash(c->c_hash, h), n = 0;
|
||||
(e = *ee);
|
||||
ee = htable_next(c->c_hash, ee)) {
|
||||
if (e->e_value != h)
|
||||
continue;
|
||||
if (e->e_n == n)
|
||||
n++;
|
||||
if (e->e_n == expect)
|
||||
n++, expect++;
|
||||
}
|
||||
|
||||
return n;
|
||||
@@ -218,9 +223,9 @@ int table_test(int flags)
|
||||
for correct ordering */
|
||||
hash_value_t size = c->c_hash->ht_size, h = size - 1;
|
||||
|
||||
TEST_1(add(c, h, 0)); TEST_1(add(c, h, 1)); TEST_1(add(c, h, 2));
|
||||
TEST_1(add(c, h, 3)); TEST_1(add(c, h, 4)); TEST_1(add(c, h, 5));
|
||||
TEST_1(add(c, h, 6)); TEST_1(add(c, h, 7)); TEST_1(add(c, h, 8));
|
||||
TEST_1(add(c, h, 1)); TEST_1(add(c, h, 2)); TEST_1(add(c, h, 3));
|
||||
TEST_1(add(c, h, 4)); TEST_1(add(c, h, 5)); TEST_1(add(c, h, 6));
|
||||
TEST_1(add(c, h, 7)); TEST_1(add(c, h, 8)); TEST_1(add(c, h, 9));
|
||||
|
||||
TEST(count(c, h), 9);
|
||||
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* This file is part of the Sofia-SIP package
|
||||
*
|
||||
* Copyright (C) 2005 Nokia Corporation.
|
||||
*
|
||||
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/**@ingroup su_htable
|
||||
*
|
||||
* @CFILE test_htable.c
|
||||
*
|
||||
* Test functions for the @b su library hash table implementation.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
||||
*
|
||||
* @date Created: Tue Aug 21 15:18:26 2001 ppessi
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sofia-sip/su_alloc.h"
|
||||
#include "sofia-sip/htable2.h"
|
||||
|
||||
#define TSTFLAGS flags
|
||||
#include <sofia-sip/tstdef.h>
|
||||
|
||||
char const name[] = "test_htable2";
|
||||
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v|--verbatim] [-a|--abort]\n", name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
static int table2_test(int flags);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
int retval = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbatim") == 0)
|
||||
flags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
|
||||
flags |= tst_abort;
|
||||
else
|
||||
usage(1);
|
||||
}
|
||||
|
||||
retval |= table2_test(flags); fflush(stdout);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
typedef struct hentry_s entry_t;
|
||||
|
||||
HTABLE2_DECLARE2(htable2_t, htable2_s, ht2_, entry_t, size_t);
|
||||
HTABLE2_PROTOS2(htable2_t, htable2, ht2_, entry_t, size_t);
|
||||
|
||||
struct hentry_s
|
||||
{
|
||||
unsigned long e_hash;
|
||||
unsigned long e_n;
|
||||
};
|
||||
|
||||
#define HENTRY_HASH(e) ((e).e_hash)
|
||||
#define HENTRY_IS_USED(e) ((e).e_n != 0)
|
||||
#define HENTRY_REMOVE(e) ((e)->e_n = 0, (e)->e_hash = 0)
|
||||
#define HENTRY_IS_EQUAL(a, b) ((a).e_n == (b).e_n)
|
||||
#define HALLOC(home, old, newsize) (su_realloc(home, old, newsize))
|
||||
|
||||
HTABLE2_BODIES2(htable2_t, htable2, ht2_, entry_t, size_t,
|
||||
HENTRY_HASH, HENTRY_IS_USED, HENTRY_REMOVE, HENTRY_IS_EQUAL,
|
||||
HALLOC);
|
||||
|
||||
typedef struct context_s
|
||||
{
|
||||
su_home_t c_home[1];
|
||||
htable2_t c_hash[1];
|
||||
} context_t;
|
||||
|
||||
context_t *context_create(void)
|
||||
{
|
||||
context_t *c = su_home_clone(NULL, sizeof(*c));
|
||||
|
||||
if (c)
|
||||
htable2_resize(c->c_home, c->c_hash, 0);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static
|
||||
entry_t *search(context_t *c, unsigned long value, unsigned long n, int add)
|
||||
{
|
||||
htable2_t *ht = c->c_hash;
|
||||
entry_t *e;
|
||||
unsigned long hash = value;
|
||||
|
||||
/* Search for entry in hash table */
|
||||
for (e = htable2_hash(ht, hash);
|
||||
e->e_n != 0;
|
||||
e = htable2_next(ht, e)) {
|
||||
if (e->e_hash == value && e->e_n == n)
|
||||
return e;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
entry_t entry;
|
||||
|
||||
/* Resize hash table */
|
||||
if (htable2_is_full(ht)) {
|
||||
htable2_resize(c->c_home, ht, 0);
|
||||
fprintf(stderr, "htable: resized to "MOD_ZU" with "MOD_ZU" entries\n",
|
||||
ht->ht2_size, ht->ht2_used);
|
||||
}
|
||||
|
||||
/* Add an entry */
|
||||
e = &entry, e->e_hash = value, e->e_n = n;
|
||||
|
||||
return htable2_append(ht, *e);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int add(context_t *c, unsigned long value, unsigned long n)
|
||||
{
|
||||
return search(c, value, n, 1) != NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void zap(context_t *c, entry_t e)
|
||||
{
|
||||
htable2_remove(c->c_hash, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that all n entries with hash h are in hash table
|
||||
* and they are stored in same order
|
||||
* in which they were added to the hash
|
||||
*/
|
||||
static unsigned long count(context_t *c, hash_value_t h)
|
||||
{
|
||||
entry_t *e;
|
||||
unsigned long n;
|
||||
unsigned long expect = 1;
|
||||
|
||||
for (e = htable2_hash(c->c_hash, h), n = 0;
|
||||
e->e_n != 0;
|
||||
e = htable2_next(c->c_hash, e)) {
|
||||
if (e->e_hash != h)
|
||||
continue;
|
||||
if (e->e_n == expect)
|
||||
n++, expect++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int table2_test(int flags)
|
||||
{
|
||||
context_t *c;
|
||||
entry_t *e, e0;
|
||||
|
||||
BEGIN();
|
||||
|
||||
TEST_1(c = context_create());
|
||||
TEST_1(add(c, 0, 1)); TEST_1(c->c_hash->ht2_table[0].e_n == 1);
|
||||
TEST_1(add(c, 1, 2)); TEST_1(c->c_hash->ht2_table[1].e_n == 2);
|
||||
TEST_1(add(c, 2, 3)); TEST_1(c->c_hash->ht2_table[2].e_n == 3);
|
||||
TEST_1(add(c, 0, 4)); TEST_1(c->c_hash->ht2_table[3].e_n == 4);
|
||||
TEST_1(add(c, 2, 5)); TEST_1(c->c_hash->ht2_table[4].e_n == 5);
|
||||
|
||||
TEST_1(e = search(c, 1, 2, 0));
|
||||
e0 = *e;
|
||||
TEST(htable2_remove(c->c_hash, e0), 0);
|
||||
TEST(htable2_remove(c->c_hash, e0), -1);
|
||||
|
||||
/* after remove , 4 is mode to [1], 5 to [4] */
|
||||
TEST(c->c_hash->ht2_table[0].e_n, 1);
|
||||
TEST(c->c_hash->ht2_table[1].e_n, 4);
|
||||
TEST(c->c_hash->ht2_table[2].e_n, 3);
|
||||
TEST(c->c_hash->ht2_table[3].e_n, 5);
|
||||
TEST(c->c_hash->ht2_table[4].e_n, 0);
|
||||
|
||||
zap(c, c->c_hash->ht2_table[0]);
|
||||
|
||||
/* after remove , 4 is mode to [1], 5 to [4] */
|
||||
TEST(c->c_hash->ht2_table[0].e_n, 4);
|
||||
TEST(c->c_hash->ht2_table[1].e_n, 0);
|
||||
TEST(c->c_hash->ht2_table[2].e_n, 3);
|
||||
TEST(c->c_hash->ht2_table[3].e_n, 5);
|
||||
TEST(c->c_hash->ht2_table[4].e_n, 0);
|
||||
|
||||
TEST_1(add(c, 0, 6)); TEST(c->c_hash->ht2_table[1].e_n, 6);
|
||||
TEST_1(add(c, 1, 7)); TEST(c->c_hash->ht2_table[4].e_n, 7);
|
||||
|
||||
/* Test that zapping entry 0 does not move 2 and 3 */
|
||||
zap(c, c->c_hash->ht2_table[0]);
|
||||
TEST(c->c_hash->ht2_table[4].e_n, 0);
|
||||
|
||||
{
|
||||
/* Insert entries at the end of hash, then resize and check
|
||||
for correct ordering */
|
||||
size_t size = c->c_hash->ht2_size;
|
||||
hash_value_t h = (hash_value_t)size - 1;
|
||||
|
||||
TEST_1(add(c, h, 1)); TEST_1(add(c, h, 2)); TEST_1(add(c, h, 3));
|
||||
TEST_1(add(c, h, 4)); TEST_1(add(c, h, 5)); TEST_1(add(c, h, 6));
|
||||
TEST_1(add(c, h, 7)); TEST_1(add(c, h, 8)); TEST_1(add(c, h, 9));
|
||||
|
||||
TEST(count(c, h), 9);
|
||||
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
TEST(htable2_resize(c->c_home, c->c_hash, ++size), 0);
|
||||
TEST(count(c, h), 9);
|
||||
}
|
||||
|
||||
TEST_VOID(su_home_unref(c->c_home));
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ struct pinger;
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
char const name[] = "su_test";
|
||||
char const name[] = "test_su";
|
||||
|
||||
#if HAVE_FUNC
|
||||
#define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __func__))
|
||||
@@ -64,7 +64,7 @@ char const name[] = "su_test";
|
||||
#else
|
||||
#define enter ((void)0)
|
||||
#define nh_enter ((void)0)
|
||||
#define __func__ "su_test"
|
||||
#define __func__ "test_su"
|
||||
#endif
|
||||
|
||||
struct pinger {
|
||||
|
||||
@@ -69,6 +69,7 @@ static int test_alloc(void)
|
||||
{
|
||||
exhome_t *h0, *h1, *h2, *h3;
|
||||
su_home_t home[1] = { SU_HOME_INIT(home) };
|
||||
su_home_t home0[1];
|
||||
enum { N = 40 };
|
||||
void *m0[N], *m1[N], *m;
|
||||
char *c, *c0, *p0, *p1;
|
||||
@@ -78,6 +79,11 @@ static int test_alloc(void)
|
||||
|
||||
BEGIN();
|
||||
|
||||
/* su_home_init() was not initializing suh_locks */
|
||||
memset(home0, 0xff, sizeof home0);
|
||||
TEST(su_home_init(home0), 0);
|
||||
TEST_VOID(su_home_deinit(home0));
|
||||
|
||||
TEST_1(h0 = su_home_new(sizeof(*h0)));
|
||||
TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
|
||||
|
||||
|
||||
@@ -165,6 +165,8 @@ void *suspend_resume_test_thread(void *_rt)
|
||||
{
|
||||
root_test_t *rt = _rt;
|
||||
|
||||
su_init();
|
||||
|
||||
pthread_mutex_lock(rt->rt_sr.mutex);
|
||||
rt->rt_root = su_root_create(rt);
|
||||
rt->rt_sr.done = 1;
|
||||
@@ -177,6 +179,9 @@ void *suspend_resume_test_thread(void *_rt)
|
||||
su_root_destroy(rt->rt_root);
|
||||
rt->rt_root = NULL;
|
||||
pthread_mutex_unlock(rt->rt_sr.deinit);
|
||||
|
||||
su_deinit();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -192,8 +197,6 @@ int init_test(root_test_t *rt,
|
||||
|
||||
BEGIN();
|
||||
|
||||
su_init();
|
||||
|
||||
su_port_prefer(create, start);
|
||||
|
||||
#if SU_HAVE_PTHREADS
|
||||
@@ -257,8 +260,6 @@ static int deinit_test(root_test_t *rt)
|
||||
TEST_VOID(su_root_destroy(rt->rt_root)); rt->rt_root = NULL;
|
||||
#endif
|
||||
|
||||
su_deinit();
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
@@ -724,6 +725,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
i = 0;
|
||||
|
||||
su_init();
|
||||
|
||||
do {
|
||||
rt = rt1, *rt = *rt0;
|
||||
|
||||
@@ -739,5 +742,7 @@ int main(int argc, char *argv[])
|
||||
retval |= deinit_test(rt);
|
||||
} while (prefer[++i].create);
|
||||
|
||||
su_deinit();
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -824,7 +824,7 @@ static int tcp_test(tp_test_t *tt)
|
||||
BEGIN();
|
||||
|
||||
msg_t *msg = NULL;
|
||||
int i;
|
||||
int i, N;
|
||||
tport_t *tp, *tp0;
|
||||
char ident[16];
|
||||
su_time_t started;
|
||||
@@ -853,12 +853,15 @@ static int tcp_test(tp_test_t *tt)
|
||||
pending_server_close = tport_pend(tp, NULL, server_closed_callback, NULL);
|
||||
TEST_1(pending_server_close > 0);
|
||||
|
||||
N = 0; tt->tt_received = 0;
|
||||
|
||||
#ifndef WIN32 /* Windows seems to be buffering too much */
|
||||
|
||||
/* Create a large message, just to force queueing in sending end */
|
||||
TEST(new_test_msg(tt, &msg, "tcp-0", 1, 16 * 64 * 1024), 0);
|
||||
test_create_md5(tt, msg);
|
||||
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
||||
N++;
|
||||
TEST_S(tport_name(tp)->tpn_ident, "client");
|
||||
TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
|
||||
msg_destroy(msg);
|
||||
@@ -869,6 +872,7 @@ static int tcp_test(tp_test_t *tt)
|
||||
|
||||
TEST(new_test_msg(tt, &msg, ident, 1, 64 * 1024), 0);
|
||||
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
||||
N++;
|
||||
TEST_S(tport_name(tp)->tpn_ident, "client");
|
||||
TEST_P(tport_incref(tp), tp0); tport_decref(&tp);
|
||||
msg_destroy(msg);
|
||||
@@ -879,8 +883,6 @@ static int tcp_test(tp_test_t *tt)
|
||||
TEST_1(!tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name, TAG_END()));
|
||||
msg_destroy(msg);
|
||||
|
||||
tt->tt_received = 0;
|
||||
|
||||
TEST(tport_test_run(tt, 60), 1);
|
||||
TEST_1(!check_msg(tt, tt->tt_rmsg, "tcp-0"));
|
||||
test_check_md5(tt, tt->tt_rmsg);
|
||||
@@ -892,13 +894,15 @@ static int tcp_test(tp_test_t *tt)
|
||||
TEST_1(!check_msg(tt, tt->tt_rmsg, ident));
|
||||
msg_destroy(tt->tt_rmsg), tt->tt_rmsg = NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
(void)i; (void)ident;
|
||||
#endif
|
||||
|
||||
/* This uses a new connection */
|
||||
TEST_1(!new_test_msg(tt, &msg, "tcp-no-reuse", 1, 1024));
|
||||
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
||||
TPTAG_REUSE(0), TAG_END()));
|
||||
N++;
|
||||
TEST_S(tport_name(tp)->tpn_ident, "client");
|
||||
TEST_1(tport_incref(tp) != tp0); tport_decref(&tp);
|
||||
msg_destroy(msg);
|
||||
@@ -907,12 +911,13 @@ static int tcp_test(tp_test_t *tt)
|
||||
TEST_1(!new_test_msg(tt, &msg, "tcp-reuse", 1, 1024));
|
||||
TEST_1(tp = tport_tsend(tt->tt_tports, msg, tt->tt_tcp_name,
|
||||
TPTAG_REUSE(1), TAG_END()));
|
||||
N++;
|
||||
TEST_S(tport_name(tp)->tpn_ident, "client");
|
||||
TEST_1(tport_incref(tp) == tp0); tport_decref(&tp);
|
||||
msg_destroy(msg);
|
||||
|
||||
/* Receive every message from queue */
|
||||
while (tt->tt_received < TPORT_QUEUESIZE + 2) {
|
||||
while (tt->tt_received < N) {
|
||||
TEST(tport_test_run(tt, 5), 1);
|
||||
/* Validate message */
|
||||
TEST_1(!check_msg(tt, tt->tt_rmsg, NULL));
|
||||
@@ -1005,7 +1010,7 @@ static int test_incomplete(tp_test_t *tt)
|
||||
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
TEST_1(s != SOCKET_ERROR);
|
||||
|
||||
connected = connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
connected = connect(s, ai->ai_addr, (socklen_t)ai->ai_addrlen);
|
||||
|
||||
su_root_step(tt->tt_root, 50);
|
||||
|
||||
|
||||
Reference in new issue
Block a user