/* Test that we can control listen/select on ipv6/v4 and listen on both by default */ static void test_ipv4_ipv6(test_t *t) { test_proactor_t tps[] ={ test_proactor(t, open_close_handler), test_proactor(t, listen_handler) }; pn_proactor_t *client = tps[0].proactor, *server = tps[1].proactor; /* Listen on all interfaces for IPv4 only. */ pn_listener_t *l4 = test_listen(&tps[1], "0.0.0.0"); TEST_PROACTORS_DRAIN(tps); /* Empty address listens on both IPv4 and IPv6 on all interfaces */ pn_listener_t *l = test_listen(&tps[1], ""); TEST_PROACTORS_DRAIN(tps); #define EXPECT_CONNECT(LISTENER, HOST) do { \ char addr[1024]; \ pn_proactor_addr(addr, sizeof(addr), HOST, listener_info(LISTENER).port); \ pn_proactor_connect2(client, NULL, NULL, addr); \ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); \ TEST_COND_EMPTY(t, last_condition); \ TEST_PROACTORS_DRAIN(tps); \ } while(0) EXPECT_CONNECT(l4, "127.0.0.1"); /* v4->v4 */ EXPECT_CONNECT(l4, ""); /* local->v4*/ EXPECT_CONNECT(l, "127.0.0.1"); /* v4->all */ EXPECT_CONNECT(l, ""); /* local->all */ /* Listen on ipv6 loopback, if it fails skip ipv6 tests. NOTE: Don't use the unspecified address "::" here - ipv6-disabled platforms may allow listening on "::" without complaining. However they won't have a local ipv6 loopback configured, so "::1" will force an error. */ TEST_PROACTORS_DRAIN(tps); pn_listener_t *l6 = pn_listener(); pn_proactor_listen(server, l6, "::1:0", 4); pn_event_type_t e = TEST_PROACTORS_RUN(tps); if (e == PN_LISTENER_OPEN && !pn_condition_is_set(last_condition)) { TEST_PROACTORS_DRAIN(tps); EXPECT_CONNECT(l6, "::1"); /* v6->v6 */ EXPECT_CONNECT(l6, ""); /* local->v6 */ EXPECT_CONNECT(l, "::1"); /* v6->all */ pn_listener_close(l6); } else { const char *d = pn_condition_get_description(last_condition); TEST_LOGF(t, "skip IPv6 tests: %s %s", pn_event_type_name(e), d ? d : "no condition"); } pn_listener_close(l); pn_listener_close(l4); TEST_PROACTORS_DESTROY(tps); }
/* Verify that pn_transport_close_head/tail aborts a connection without an AMQP protocol close */ static void test_refuse(test_t *t) { test_proactor_t tps[] = { test_proactor(t, open_close_handler), test_proactor(t, listen_refuse_handler) }; pn_proactor_t *client = tps[0].proactor; pn_listener_t *l = test_listen(&tps[1], ""); pn_proactor_connect2(client, NULL, NULL, listener_info(l).connect); /* client transport closes */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* client */ TEST_COND_NAME(t, "amqp:connection:framing-error", last_condition); pn_listener_close(l); while (TEST_PROACTORS_RUN(tps) != PN_PROACTOR_INACTIVE) {} while (TEST_PROACTORS_RUN(tps) != PN_PROACTOR_INACTIVE) {} /* Verify expected event sequences, no unexpected events */ TEST_HANDLER_EXPECT( &tps[0].handler, PN_CONNECTION_INIT, PN_CONNECTION_LOCAL_OPEN, PN_CONNECTION_BOUND, PN_TRANSPORT_TAIL_CLOSED, PN_TRANSPORT_ERROR, PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT_CLOSED, PN_PROACTOR_INACTIVE, 0); TEST_HANDLER_EXPECT( &tps[1].handler, PN_LISTENER_OPEN, PN_LISTENER_ACCEPT, PN_CONNECTION_INIT, PN_CONNECTION_BOUND, PN_TRANSPORT_TAIL_CLOSED, PN_TRANSPORT_ERROR, PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT_CLOSED, PN_LISTENER_CLOSE, PN_PROACTOR_INACTIVE, 0); TEST_PROACTORS_DESTROY(tps); }
int pn_messenger_stop(pn_messenger_t *messenger) { if (!messenger) return PN_ARG_ERR; for (int i = 0; i < messenger->size; i++) { pn_connector_t *ctor = messenger->connectors[i]; pn_connection_t *conn = pn_connector_connection(ctor); pn_link_t *link = pn_link_head(conn, PN_LOCAL_ACTIVE); while (link) { pn_link_close(link); link = pn_link_next(link, PN_LOCAL_ACTIVE); } pn_connection_close(conn); } pn_listener_t *l = pn_listener_head(messenger->driver); while (l) { pn_listener_close(l); pn_listener_t *prev = l; l = pn_listener_next(l); pn_listener_free(prev); } return pn_messenger_sync(messenger, pn_messenger_stopped); }
/* Common handler for simple client/server interactions, */ static pn_event_type_t common_handler(test_handler_t *th, pn_event_t *e) { pn_connection_t *c = pn_event_connection(e); pn_listener_t *l = pn_event_listener(e); switch (pn_event_type(e)) { /* Stop on these events */ case PN_TRANSPORT_CLOSED: case PN_PROACTOR_INACTIVE: case PN_PROACTOR_TIMEOUT: case PN_LISTENER_OPEN: return pn_event_type(e); case PN_LISTENER_ACCEPT: last_accepted = pn_connection(); pn_listener_accept2(l, last_accepted, NULL); pn_listener_close(l); /* Only accept one connection */ return PN_EVENT_NONE; case PN_CONNECTION_REMOTE_OPEN: pn_connection_open(c); /* Return the open (no-op if already open) */ return PN_EVENT_NONE; case PN_SESSION_REMOTE_OPEN: pn_session_open(pn_event_session(e)); return PN_EVENT_NONE; case PN_LINK_REMOTE_OPEN: pn_link_open(pn_event_link(e)); return PN_EVENT_NONE; case PN_CONNECTION_REMOTE_CLOSE: pn_connection_close(c); /* Return the close */ return PN_EVENT_NONE; /* Ignore these events */ case PN_CONNECTION_BOUND: case PN_CONNECTION_INIT: case PN_CONNECTION_LOCAL_CLOSE: case PN_CONNECTION_LOCAL_OPEN: case PN_LINK_INIT: case PN_LINK_LOCAL_OPEN: case PN_LISTENER_CLOSE: case PN_SESSION_INIT: case PN_SESSION_LOCAL_OPEN: case PN_TRANSPORT: case PN_TRANSPORT_ERROR: case PN_TRANSPORT_HEAD_CLOSED: case PN_TRANSPORT_TAIL_CLOSED: return PN_EVENT_NONE; default: TEST_ERRORF(th->t, "unexpected event %s", pn_event_type_name(pn_event_type(e))); return PN_EVENT_NONE; /* Fail the test but keep going */ } }
/* Tests for error handling */ static void test_errors(test_t *t) { test_proactor_t tps[] = { test_proactor(t, open_wake_handler), test_proactor(t, listen_handler) }; pn_proactor_t *client = tps[0].proactor, *server = tps[1].proactor; /* Invalid connect/listen service name */ pn_connection_t *c = pn_connection(); pn_proactor_connect2(client, c, NULL, "127.0.0.1:xxx"); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_COND_DESC(t, "xxx", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); pn_proactor_listen(server, pn_listener(), "127.0.0.1:xxx", 1); TEST_PROACTORS_RUN(tps); TEST_HANDLER_EXPECT(&tps[1].handler, PN_LISTENER_CLOSE, 0); /* CLOSE only, no OPEN */ TEST_COND_DESC(t, "xxx", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Invalid connect/listen host name */ c = pn_connection(); pn_proactor_connect2(client, c, NULL, "nosuch.example.com:"); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_COND_DESC(t, "nosuch", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); test_handler_clear(&tps[1].handler, 0); pn_proactor_listen(server, pn_listener(), "nosuch.example.com:", 1); TEST_PROACTORS_RUN(tps); TEST_HANDLER_EXPECT(&tps[1].handler, PN_LISTENER_CLOSE, 0); /* CLOSE only, no OPEN */ TEST_COND_DESC(t, "nosuch", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Listen on a port already in use */ pn_listener_t *l = pn_listener(); pn_proactor_listen(server, l, ":0", 1); TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, TEST_PROACTORS_RUN(tps)); test_handler_clear(&tps[1].handler, 0); struct addrinfo laddr = listener_info(l); pn_proactor_listen(server, pn_listener(), laddr.connect, 1); /* Busy */ TEST_PROACTORS_RUN(tps); TEST_HANDLER_EXPECT(&tps[1].handler, PN_LISTENER_CLOSE, 0); /* CLOSE only, no OPEN */ TEST_COND_NAME(t, "proton:io", last_condition); pn_listener_close(l); TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Connect with no listener */ c = pn_connection(); pn_proactor_connect2(client, c, NULL, laddr.connect); if (TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps))) { TEST_COND_DESC(t, "refused", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); } TEST_PROACTORS_DESTROY(tps); }
void qd_connection_manager_delete_listener(qd_dispatch_t *qd, void *impl) { qd_listener_t *li = (qd_listener_t*) impl; if (li) { if (li->pn_listener) { pn_listener_close(li->pn_listener); } DEQ_REMOVE(qd->connection_manager->listeners, li); qd_listener_decref(li); } }
/* Test that INACTIVE event is generated when last connections/listeners closes. */ static void test_inactive(test_t *t) { test_proactor_t tps[] = { test_proactor(t, open_wake_handler), test_proactor(t, listen_handler) }; pn_proactor_t *client = tps[0].proactor, *server = tps[1].proactor; /* Listen, connect, disconnect */ pn_listener_t *l = test_listen(&tps[1], ""); pn_connection_t *c = pn_connection(); pn_proactor_connect2(client, c, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_connection_wake(c); TEST_ETYPE_EQUAL(t, PN_CONNECTION_WAKE, TEST_PROACTORS_RUN(tps)); /* Expect TRANSPORT_CLOSED from client and server, INACTIVE from client */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Immediate timer generates INACTIVE on client (no connections) */ pn_proactor_set_timeout(client, 0); TEST_ETYPE_EQUAL(t, PN_PROACTOR_TIMEOUT, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Connect, set-timer, disconnect */ pn_proactor_set_timeout(client, 1000000); c = pn_connection(); pn_proactor_connect2(client, c, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_connection_wake(c); TEST_ETYPE_EQUAL(t, PN_CONNECTION_WAKE, TEST_PROACTORS_RUN(tps)); /* Expect TRANSPORT_CLOSED from client and server */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* No INACTIVE till timer is cancelled */ TEST_CHECK(t, pn_proactor_get(server) == NULL); pn_proactor_cancel_timeout(client); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Server won't be INACTIVE until listener is closed */ TEST_CHECK(t, pn_proactor_get(server) == NULL); pn_listener_close(l); TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); TEST_PROACTORS_DESTROY(tps); }