static void mrcp_unirtsp_session_destroy(mrcp_unirtsp_session_t *session)
{
	if(session->home) {
		su_home_unref(session->home);
		session->home = NULL;
	}
	rtsp_server_session_object_set(session->rtsp_session,NULL);
	mrcp_session_destroy(session->mrcp_session);
}
示例#2
0
static int luasofia_nua_create(lua_State *L)
{
    luasofia_su_root_t *lroot = NULL;
    luasofia_nua_t *lnua = NULL;
    nua_t *nua = NULL;
    tagi_t *tags = NULL;
    su_home_t *home = su_home_create();

    /* get and check first argument (should be a root_t) */
    lroot = (luasofia_su_root_t*)luaL_checkudata(L, 1, SU_ROOT_MTABLE);

    /* check the callback table */
    if (!lua_isnoneornil(L, 2))
        luaL_checktype(L, 2, LUA_TTABLE);

    tags = luasofia_tags_table_to_taglist(L, 4, home);

    /* create a nua object */
    lnua = (luasofia_nua_t*) lua_newuserdata(L, sizeof(luasofia_nua_t));

    /* create the nua_t */
    nua = nua_create(lroot->root, nua_event_callback, L, TAG_NEXT(tags));
    if (!nua) {
        luaL_error(L, "nua_create failed!");
    }
    /* save nua object */
    lnua->nua = nua;

    /* set its metatable */
    luaL_getmetatable(L, NUA_MTABLE);
    lua_setmetatable(L, -2);

    /* store nua at luasofia userdata table */
    luasofia_userdata_table_set(L, nua);

    /* create env table */
    lua_createtable(L, 2, 0);

    /* save second argument (callbacks) on env table */
    if (!lua_isnoneornil(L, 2)) {
        lua_pushvalue(L, 2);
        lua_rawseti(L, -2, ENV_CALLBACK_INDEX);
    }

    /* save third argument (magic) on env table */
    if (!lua_isnoneornil(L, 3)) {
        lua_pushvalue(L, 3);
        lua_rawseti(L, -2, ENV_MAGIC_INDEX);
    }

    /* set env table as environment for udata */
    lua_setfenv(L, -2);

    su_home_unref(home);
    return 1;
}
static void mrcp_unirtsp_session_destroy(mrcp_unirtsp_session_t *session)
{
	if(session->home) {
		su_home_unref(session->home);
		session->home = NULL;
	}
	rtsp_server_session_object_set(session->rtsp_session,NULL);
	apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Session "APT_SID_FMT,MRCP_SESSION_SID(session->mrcp_session));
	mrcp_session_destroy(session->mrcp_session);
}
示例#4
0
static int luasofia_nua_get_params(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_t) */
    su_home_t *home = su_home_create();
    luasofia_nua_t *lnua = (luasofia_nua_t*)luaL_checkudata(L, 1, NUA_MTABLE);
    tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);

    nua_get_params(lnua->nua, TAG_NEXT(tags));
    su_home_unref(home);
    return 0;
}
示例#5
0
static int luasofia_nua_handle_invite(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_handle_t) */
    luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*)luaL_checkudata(L, 1, NUA_HANDLE_MTABLE);
    if (lnh->nh) {
        su_home_t *home = su_home_create();
        tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);
        nua_invite(lnh->nh, TAG_NEXT(tags));
        su_home_unref(home);
    }
    return 0;
}
static apt_bool_t mrcp_sofia_session_destroy(mrcp_sofia_session_t *sofia_session)
{
	if(sofia_session->mutex) {
		apr_thread_mutex_destroy(sofia_session->mutex);
		sofia_session->mutex = NULL;
	}
	if(sofia_session->home) {
		su_home_unref(sofia_session->home);
		sofia_session->home = NULL;
	}
	return TRUE;
}
/** Create a port using /dev/poll or poll().
 */
su_port_t *su_devpoll_port_create(void)
{
  su_port_t *self;
  int devpoll = open("/dev/poll", O_RDWR);

  if (devpoll == -1) {
    /* Fallback to poll() */
    SU_DEBUG_3(("%s(): open(\"%s\") => %u: %s\n",
		"su_devpoll_port_create", "/dev/poll",
		errno, strerror(errno)));
    return su_poll_port_create();
  }

  self = su_home_new(sizeof *self);
  if (!self) {
    close(devpoll);
    return self;
  }

  if (su_home_destructor(su_port_home(self), su_devpoll_port_deinit) < 0 ||
      !(self->sup_indices =
	su_zalloc(su_port_home(self),
		  (sizeof self->sup_indices[0]) *
		  (self->sup_size_indices = 64)))) {
    su_home_unref(su_port_home(self));
    close(devpoll);
    return NULL;
  }

  self->sup_devpoll = devpoll;
  self->sup_multishot = SU_ENABLE_MULTISHOT_POLL;

  if (su_socket_port_init(self->sup_base, su_devpoll_port_vtable) < 0)
    return su_home_unref(su_port_home(self)), NULL;

  SU_DEBUG_9(("%s(%p): devpoll_create() => %u: %s\n",
	      "su_port_create", (void *)self, self->sup_devpoll, "OK"));

  return self;
}
static apt_bool_t mrcp_sofia_session_destroy(mrcp_sofia_session_t *sofia_session)
{
	if(sofia_session->nh) {
		nua_handle_bind(sofia_session->nh, NULL);
		nua_handle_destroy(sofia_session->nh);
	}
	if(sofia_session->home) {
		sofia_session->session->obj = NULL;
		su_home_unref(sofia_session->home);
		sofia_session->home = NULL;
	}
	return TRUE;
}
示例#9
0
void outbound_unref(outbound_t *ob)
{
  if (ob->ob_keepalive.timer)
    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;

  if (ob->ob_keepalive.orq)
    nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;

  if (ob->ob_keepalive.msg)
    msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;

  su_home_unref(ob->ob_home);
}
示例#10
0
/** Create a resolver cache object.
 *
 * @param n initial size of cache
 */
sres_cache_t *sres_cache_new(int n)
{
  sres_cache_t *cache = su_home_new(sizeof *cache);

  if (cache) {
    su_home_threadsafe(cache->cache_home);
    if (sres_htable_resize(cache->cache_home, cache->cache_hash, n) < 0 ||
	sres_heap_resize(cache->cache_home, &cache->cache_heap, 0) < 0)
      su_home_unref(cache->cache_home), cache = NULL;
  }

  return cache;
}
示例#11
0
int luasofia_nta_agent_create(lua_State * L)
{
    luasofia_su_root_t *lroot = NULL;
    url_string_t * contact = NULL;
    luasofia_nta_agent_t* u_nta_agent = NULL;
    su_home_t *home = su_home_create();
    tagi_t *tags = NULL;

    /* get and check first argument (should be a root_t) */
    lroot = (luasofia_su_root_t*)luaL_checkudata(L, -4, SU_ROOT_MTABLE);

    if(lua_isuserdata (L, -3)) {
        //Since there is no metatable for url_t or url_string_t we cant perform a checkudata here.
        contact = (url_string_t *) lua_touserdata (L, -3);
    } else {
        contact = URL_STRING_MAKE(luaL_checkstring (L, -3));
    }

    /* check the callback function */
    if(!lua_isfunction(L, -2))
        luaL_error(L, "nta_agent_create failed!, expected a callback function !");

    /* check if there is tags */
    tags = luasofia_tags_table_to_taglist(L, -1, home);

    u_nta_agent           = (luasofia_nta_agent_t *) lua_newuserdata(L, sizeof(luasofia_nta_agent_t));
    u_nta_agent->L        = L;
    u_nta_agent->agent    = nta_agent_create (lroot->root,
                                              (url_string_t const *)contact,
                                              nta_agent_message_callback,
                                              (nta_agent_magic_t *)u_nta_agent,
                                              TAG_NEXT(tags));

    // lets hold the ref to the lua callback function.
    lua_pushvalue(L, -3);
    u_nta_agent->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);

    if (!u_nta_agent->agent)
        luaL_error(L, "nta_agent_create failed!");

    /* set its metatable */
    luaL_getmetatable(L, NTA_AGENT_MTABLE);
    lua_setmetatable(L, -2);

    /* store nta_agent at luasofia userdata table 
       userdata_table[nta_agent_lightudata] = nta_agent_fulludata */
    luasofia_userdata_table_set(L, u_nta_agent->agent);

    su_home_unref(home);
    return 1;
}
示例#12
0
void s2_nua_teardown(void)
{
  if (s2) {
    struct s2nua *zap = s2;
    nua_destroy(s2->nua), s2->nua = NULL;
    s2 = NULL;
    su_home_unref(zap->home);
  }

  s2_dns_teardown();
  s2_sip_teardown();
  s2_teardown();

}
示例#13
0
static int luasofia_nua_handle_get_hparams(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_handle_t) */
    luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*) luaL_checkudata(L, 1, NUA_HANDLE_MTABLE);
    if (lnh->nh) {
        su_home_t *home = su_home_create();
      
        /* get and check second argument (should be a tag table) */
        //tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home);

        nua_get_hparams(lnh->nh, TAG_ANY(), TAG_NULL()); //FIXME TAG_NEXT(tags));

        su_home_unref(home);
    }
    return 0;
}
示例#14
0
void tls_free(tls_t *tls)
{
  if (!tls)
    return;

  if (tls->con != NULL) {
	SSL_shutdown(tls->con);
	SSL_free(tls->con), tls->con = NULL;
  }

  if (tls->ctx != NULL && tls->type != tls_slave) {
    SSL_CTX_free(tls->ctx);
  }

  su_home_unref(tls->home);
}
示例#15
0
void tls_free(tls_t *tls)
{
  if (!tls)
    return;

  if (tls->con != NULL)
    SSL_shutdown(tls->con);

  if (tls->ctx != NULL && tls->type != tls_slave)
    SSL_CTX_free(tls->ctx);

  if (tls->bio_con != NULL)
    BIO_free(tls->bio_con);

  su_home_unref(tls->home);
}
示例#16
0
void nth_engine_destroy(nth_engine_t * he)
{
  if (he) {
    size_t i;
    hc_htable_t *hct = he->he_clients;

    for (i = 0; i < hct->hct_size; i++)
      hc_free(hct->hct_table[i]);

    tport_destroy(he->he_tports);

    su_timer_destroy(he->he_timer), he->he_timer = NULL;

    su_home_unref(he->he_home);
  }
}
示例#17
0
/** Create a new outbound object */
outbound_t *
outbound_new(outbound_owner_t *owner,
	     outbound_owner_vtable const *owner_methods,
	     su_root_t *root,
	     nta_agent_t *agent,
	     char const *instance)
{
  outbound_t *ob;

  if (!owner || !owner_methods || !root || !agent)
    return NULL;

  ob = su_home_clone((su_home_t *)owner, sizeof *ob);

  if (ob) {
    su_md5_t md5[1];
    uint8_t digest[SU_MD5_DIGEST_SIZE];
    su_guid_t guid[1];

    ob->ob_owner = owner;
    ob->ob_oo = owner_methods;
    ob->ob_root = root;
    ob->ob_nta = agent;

    if (instance)
      ob->ob_instance =
	su_sprintf(ob->ob_home, "+sip.instance=\"<%s>\"", instance);
    ob->ob_reg_id = 0;

    outbound_peer_info(ob, NULL);

    /* Generate a random cookie (used as Call-ID) for us */
    su_md5_init(md5);
    su_guid_generate(guid);
    if (instance)
      su_md5_update(md5, (void *)instance, strlen(instance));
    su_md5_update(md5, (void *)guid, sizeof guid);
    su_md5_digest(md5, digest);
    token64_e(ob->ob_cookie, sizeof ob->ob_cookie, digest, sizeof digest);

    if (instance && !ob->ob_instance)
      su_home_unref(ob->ob_home), ob = NULL;
  }

  return ob;
}
示例#18
0
int su_base_port_decref(su_port_t *self, int blocking, char const *who)
{
  int zapped = su_home_unref(self->sup_home);

  PORT_REFCOUNT_DEBUG(("%s(%p) to %u%s by %s\n",
		       blocking ? "zapref" : "decref",
		       self, zapped ? 0 : su_home_refcount(self->sup_home),
		       blocking && !zapped ? " FAILED" :"",
		       who));

  /* We should block until all references are destroyed */
  if (blocking)
    /* ...but we just abort() */
    assert(zapped);

  return zapped;
}
示例#19
0
END_TEST

START_TEST(subscribe_6_1_4)
{
    nua_handle_t *nh;
    struct message *response;
    struct event *notify, *event;

    S2_CASE("6.1.4", "Subscription terminated by notifier, re-established",
            "NUA sends SUBSCRIBE, waits for NOTIFY, "
            "gets NOTIFY terminating the subscription,");

    nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END());
    nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), TAG_END());
    notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
    s2_free_event(notify);

    fail_if(s2_sip_request_to(dialog, SIP_METHOD_NOTIFY, NULL,
                              SIPTAG_EVENT_STR(event_type),
                              SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=deactivated"),
                              TAG_END()));
    event = s2_wait_for_event(nua_i_notify, 200);
    fail_if(!event);
    fail_unless(s2_check_substate(event, nua_substate_embryonic));
    s2_free_event(event);
    response = s2_sip_wait_for_response(200, SIP_METHOD_NOTIFY);
    fail_if(!response);
    s2_sip_free_message(response);

    su_home_unref((void *)dialog), dialog = su_home_new(sizeof *dialog);
    fail_if(!dialog);

    s2_nua_fast_forward(5, s2base->root);
    /* nua re-establishes the subscription */
    notify = subscription_by_nua(nh, nua_substate_embryonic, TAG_END());
    s2_free_event(notify);

    /* Unsubscribe with nua_subscribe() Expires: 0 */
    nua_subscribe(nh, SIPTAG_EVENT_STR(event_type), SIPTAG_EXPIRES_STR("0"), TAG_END());
    notify = subscription_by_nua(nh, nua_substate_active, TAG_END());
    s2_free_event(notify);

    nua_handle_destroy(nh);
}
static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session)
{
	mrcp_sofia_session_t *sofia_session = session->obj;
	if(sofia_session) {
		if(sofia_session->nh) {
			nua_handle_bind(sofia_session->nh, NULL);
			nua_handle_destroy(sofia_session->nh);
		}
		if(sofia_session->home) {
			su_home_unref(sofia_session->home);
			sofia_session->home = NULL;
		}
		sofia_session->session = NULL;
	}
	
	apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Destroy Session "APT_SID_FMT, MRCP_SESSION_SID(session));
	mrcp_session_destroy(session);
	return TRUE;
}
static apt_bool_t mrcp_sofia_on_session_terminate(mrcp_session_t *session)
{
    mrcp_sofia_session_t *sofia_session = session->obj;
    if(sofia_session) {
        if(sofia_session->session) {
            apt_log(APT_PRIO_NOTICE,"Destroy Session");
            mrcp_session_destroy(sofia_session->session);
            sofia_session->session = NULL;
        }
        if(sofia_session->nh) {
            nua_handle_bind(sofia_session->nh, NULL);
            nua_handle_destroy(sofia_session->nh);
        }
        if(sofia_session->home) {
            su_home_unref(sofia_session->home);
            sofia_session->home = NULL;
        }
    }
    return TRUE;
}
示例#22
0
tls_t *tls_init_secondary(tls_t *master, int sock, int accept)
{
  tls_t *tls = tls_create(tls_slave);

  if (tls) {
    tls->ctx = master->ctx;
    tls->type = master->type;
    tls->accept = accept ? 1 : 0;
    tls->verify_outgoing = master->verify_outgoing;
    tls->verify_incoming = master->verify_incoming;
    tls->verify_subj_out = master->verify_subj_out;
    tls->verify_subj_in  = master->verify_subj_in;
    tls->verify_date     = master->verify_date;
    tls->x509_verified   = master->x509_verified;

    if (!(tls->read_buffer = su_alloc(tls->home, tls_buffer_size)))
      su_home_unref(tls->home), tls = NULL;
  }
  if (!tls)
    return tls;

  assert(sock != -1);

  tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE);
  tls->con = SSL_new(tls->ctx);

  if (tls->con == NULL) {
    tls_log_errors(1, "tls_init_secondary", 0);
    tls_free(tls);
    errno = EIO;
    return NULL;
  }

  SSL_set_bio(tls->con, tls->bio_con, tls->bio_con);
  SSL_set_mode(tls->con, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  SSL_set_ex_data(tls->con, tls_ex_data_idx, tls);

  su_setblocking(sock, 0);

  return tls;
}
示例#23
0
static int luasofia_nua_handle_respond(lua_State *L)
{
    /* get and check first argument (should be a luasofia_nua_handle_t) */
    luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*) luaL_checkudata(L, 1, NUA_HANDLE_MTABLE);
    if (lnh->nh) {
        char const* phrase = NULL;
        su_home_t *home = su_home_create();
        /* get and check second argument (should be a int) */
        int status = luaL_checkinteger(L, 2);
      
        /* get and check fourth argument (should be a tag table) */
        tagi_t *tags = luasofia_tags_table_to_taglist(L, 4, home);

        /* get and check third argument (should be a string) */
        if (!lua_isnoneornil(L, 3))
            phrase = luaL_checkstring (L, 3);

        nua_respond(lnh->nh, status, phrase, TAG_NEXT(tags));
        su_home_unref(home);
    }
    return 0;
}
示例#24
0
int su_home_mutex_unlock(su_home_t *home)
#endif
{
  if (home == NULL)
    return su_seterrno(EFAULT);

  if (home->suh_lock) {
    int error = _su_home_mutex_unlocker(home->suh_lock);
    if (error)
      return su_seterrno(error);
  }

  if (home->suh_blocks == NULL)
    return su_seterrno(EINVAL), -1; /* Uninitialized home */

#if (defined(HAVE_MEMLEAK_LOG) && (HAVE_MEMLEAK_LOG != 1))
  _su_home_unref_by(home, file, line, function);
#else
  su_home_unref(home);
#endif

  return 0;
}
示例#25
0
void server_destroy(server_t *srv)
{
  tport_destroy(srv->srv_tports);
  su_timer_destroy(srv->srv_timer);
  su_home_unref(srv->srv_home);
}
示例#26
0
/** Destroy a reference to an authentication module. */
void auth_mod_unref(auth_mod_t *am)
{
    su_home_unref(am->am_home);
}
示例#27
0
/** Destroy (a reference to) an auth_status_t structure. @relates auth_status_t
 */
void auth_status_unref(auth_status_t *as)
{
    su_home_unref(as->as_home);
}
示例#28
0
/** Decrease the reference count on a resolver cache object. */
void sres_cache_unref(sres_cache_t *cache)
{
  su_home_unref(cache->cache_home);
}
示例#29
0
void janus_sdp_deinit(void) {
	su_home_deinit(home);
	su_home_unref(home);
	home = NULL;
}
/** Test basic memory home operations  */
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;
  int i;
  enum { destructed_once = 1 };
  int d0, d1a, d1, d2, d3;

  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)));

  d0 = d1a = d1 = d2 = d3 = 0;
  h0->p = &d0; h1->p = &d1a;
  TEST(su_home_destructor(h0->home, exdestructor), 0);
  TEST(su_home_destructor(h1->home, exdestructor), 0);

  TEST_1(h2 = su_home_ref(h0->home));
  su_home_unref(h0->home);
  TEST(d0, 0);

  for (i = 0; i < 128; i++)
    TEST_1(su_alloc(h0->home, 16));

  for (i = 0; i < 128; i++)
    TEST_1(su_alloc(h1->home, 16));

  su_home_unref(h1->home);
  TEST(d1a, destructed_once);

  TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
  TEST(su_home_destructor(h1->home, exdestructor), 0);
  h1->p = &d1;

  for (i = 0; i < 128; i++)
    TEST_1(su_alloc(h1->home, 16));

  for (i = 0; i < 128; i++)
    TEST_1(su_alloc(h2->home, 16));

  su_home_unref(h2->home); /* Should call destructor of cloned home, too */

  TEST(d0, destructed_once);
  TEST(d1, destructed_once);

  TEST_1(h0 = su_home_new(sizeof(*h0)));
  TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1)));
  TEST_1(h2 = su_home_clone(h1->home, sizeof(*h2)));
  TEST_1(h3 = su_home_clone(h2->home, sizeof(*h3)));

  TEST(su_home_threadsafe(h0->home), 0);

  for (i = 0; i < N; i++) {
    TEST_1(m0[i] = su_zalloc(h3->home, 20));
    TEST_1(m1[i] = su_zalloc(h2->home, 20));
  }

  TEST_1(m = su_zalloc(h2->home, 20));

  TEST_1(su_in_home(h2->home, m));
  TEST_1(!su_in_home(h2->home, (char *)m + 1));
  TEST_1(!su_in_home(h2->home, (void *)(intptr_t)su_in_home));
  TEST_1(!su_in_home(h3->home, m));
  TEST_1(!su_in_home(NULL, m));
  TEST_1(!su_in_home(h3->home, NULL));

  TEST(su_home_move(home, NULL), 0);
  TEST(su_home_move(NULL, home), 0);
  TEST(su_home_move(home, h3->home), 0);
  TEST(su_home_move(h2->home, h3->home), 0);
  TEST(su_home_move(h1->home, h2->home), 0);

  su_home_preload(home, 1, 1024 + 2 * 8);

  TEST_1(c = su_zalloc(home, 64)); p0 = c; p1 = c + 1024;
  c0 = c;
  TEST_P(c = su_realloc(home, c0, 127), c0);

  TEST_1(c = c0 = su_zalloc(home, 1024 - 128));
  TEST_1(p0 <= c); TEST_1(c < p1);
  TEST_P(c = su_realloc(home, c, 128), c0);
  TEST_P(c = su_realloc(home, c, 1023 - 128), c0);
  TEST_P(c = su_realloc(home, c, 1024 - 128), c0);
  TEST_1(c = su_realloc(home, c, 1024));
  TEST_1(c = su_realloc(home, c, 2 * 1024));

  TEST_P(c = su_realloc(home, p0, 126), p0);
  TEST_1(c = su_realloc(home, p0, 1024));
  TEST_P(c = su_realloc(home, c, 0), NULL);

  su_home_check(home);
  su_home_deinit(home);

  su_home_check(h2->home);
  su_home_zap(h2->home);
  su_home_check(h0->home);
  su_home_zap(h0->home);

  {
    su_home_t h1[1];

    memset(h1, 0, sizeof h1);

    TEST(su_home_init(h1), 0);
    TEST(su_home_threadsafe(h1), 0);

    TEST_1(su_home_ref(h1));
    TEST_1(su_home_ref(h1));

    TEST(su_home_destructor(h1, test_destructor), 0);

    TEST_1(!su_home_unref(h1));
    TEST_1(!su_home_unref(h1));
    TEST_1(su_home_unref(h1));
    TEST(h1->suh_size, 13);
  }

  /* Test su_home_parent() */
  TEST_1(h0 = su_home_new(sizeof *h0));
  TEST_1(h1 = su_home_clone(h0->home, sizeof *h1));
  TEST_1(h2 = su_home_clone(h1->home, sizeof *h2));
  TEST_1(h3 = su_home_clone(h2->home, sizeof *h3));

  TEST_P(su_home_parent(h0->home), NULL);
  TEST_P(su_home_parent(h1->home), h0);
  TEST_P(su_home_parent(h2->home), h1);
  TEST_P(su_home_parent(h3->home), h2);
  TEST(su_home_move(h0->home, h1->home), 0);
  TEST_P(su_home_parent(h2->home), h0);
  TEST_P(su_home_parent(h3->home), h2);
  TEST(su_home_move(h0->home, h2->home), 0);
  TEST_P(su_home_parent(h3->home), h0);

  su_home_move(NULL, h0->home);

  TEST_P(su_home_parent(h0->home), NULL);
  TEST_P(su_home_parent(h1->home), NULL);
  TEST_P(su_home_parent(h2->home), NULL);
  TEST_P(su_home_parent(h3->home), NULL);

  su_home_unref(h0->home);
  su_home_unref(h1->home);
  su_home_unref(h2->home);
  su_home_unref(h3->home);

  END();
}