/* Test waking up a connection that is idle */ static void test_connection_wake(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; pn_listener_t *l = test_listen(&tps[1], ""); pn_connection_t *c = pn_connection(); pn_incref(c); /* Keep a reference for wake() after free */ pn_proactor_connect2(client, c, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_CHECK(t, pn_proactor_get(client) == NULL); /* Should be idle */ pn_connection_wake(c); TEST_ETYPE_EQUAL(t, PN_CONNECTION_WAKE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* Both ends */ /* The pn_connection_t is still valid so wake is legal but a no-op */ TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_EVENT_NONE, TEST_PROACTORS_GET(tps)); /* No more wake */ /* Verify we don't get a wake after close even if they happen together */ pn_connection_t *c2 = pn_connection(); pn_proactor_connect2(client, c2, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_connection_wake(c2); pn_proactor_disconnect(client, NULL); pn_connection_wake(c2); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, test_proactors_run(&tps[0], 1)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, test_proactors_run(&tps[0], 1)); TEST_ETYPE_EQUAL(t, PN_EVENT_NONE, test_proactors_get(&tps[0], 1)); /* No late wake */ TEST_PROACTORS_DESTROY(tps); /* The pn_connection_t is still valid so wake is legal but a no-op */ pn_connection_wake(c); pn_decref(c); }
/* Make sure we clean up released connections and open sockets correctly */ static void test_release_free(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; pn_listener_t *l = test_listen(&tps[1], ""); /* leave one connection to the proactor */ pn_proactor_connect2(client, NULL, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); /* release c1 and free immediately */ pn_connection_t *c1 = pn_connection(); pn_proactor_connect2(client, c1, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_proactor_release_connection(c1); /* We free but socket should still be cleaned up */ pn_connection_free(c1); TEST_CHECK(t, pn_proactor_get(client) == NULL); /* Should be idle */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* Server closed */ /* release c2 and but don't free till after proactor free */ pn_connection_t *c2 = pn_connection(); pn_proactor_connect2(client, c2, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_proactor_release_connection(c2); TEST_CHECK(t, pn_proactor_get(client) == NULL); /* Should be idle */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* Server closed */ TEST_PROACTORS_DESTROY(tps); pn_connection_free(c2); /* Check freeing a listener or connection that was never given to a proactor */ pn_listener_free(pn_listener()); pn_connection_free(pn_connection()); }
/* 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); }
/* Test pn_proactor_disconnect */ static void test_disconnect(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; /* Start two listeners */ pn_listener_t *l = test_listen(&tps[1], ""); pn_listener_t *l2 = test_listen(&tps[1], ""); /* Only wait for one connection to remote-open before disconnect */ 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_t *c2 = pn_connection(); pn_proactor_connect2(client, c2, NULL, listener_info(l2).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_PROACTORS_DRAIN(tps); /* Disconnect the client proactor */ pn_condition_t *cond = pn_condition(); pn_condition_set_name(cond, "test-name"); pn_condition_set_description(cond, "test-description"); pn_proactor_disconnect(client, cond); /* Verify expected client side first */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, test_proactors_run(&tps[0], 1)); TEST_COND_NAME(t, "test-name", last_condition); TEST_COND_DESC(t, "test-description", last_condition); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, test_proactors_run(&tps[0], 1)); TEST_COND_NAME(t, "test-name", last_condition); TEST_COND_DESC(t, "test-description", last_condition); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, test_proactors_run(&tps[0], 1)); /* Now check server sees the disconnects */ TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); /* Now disconnect the server end (the listeners) */ pn_proactor_disconnect(server, cond); pn_condition_free(cond); TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_LISTENER_CLOSE, TEST_PROACTORS_RUN(tps)); TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps)); /* Make sure the proactors are still functional */ pn_listener_t *l3 = test_listen(&tps[1], ""); pn_proactor_connect2(client, NULL, NULL, listener_info(l3).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); pn_proactor_disconnect(client, NULL); TEST_PROACTORS_DRAIN(tps); TEST_PROACTORS_DESTROY(tps); }
/* Test various SSL connections between proactors*/ static void test_ssl(test_t *t) { if (!pn_ssl_present()) { TEST_LOGF(t, "Skip SSL test, no support"); return; } test_proactor_t tps[] ={ test_proactor(t, ssl_client_handler), test_proactor(t, ssl_server_handler) }; test_proactor_t *client = &tps[0], *server = &tps[1]; pn_ssl_domain_t *cd = client->handler.ssl_domain = pn_ssl_domain(PN_SSL_MODE_CLIENT); pn_ssl_domain_t *sd = server->handler.ssl_domain = pn_ssl_domain(PN_SSL_MODE_SERVER); TEST_CHECK(t, 0 == SET_CREDENTIALS(sd, "tserver")); pn_listener_t *l = test_listen(server, ""); /* Basic SSL connection */ pn_proactor_connect2(client->proactor, NULL, NULL, listener_info(l).connect); /* Open ok at both ends */ TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_COND_EMPTY(t, last_condition); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_COND_EMPTY(t, last_condition); TEST_PROACTORS_RUN_UNTIL(tps, PN_TRANSPORT_CLOSED); TEST_PROACTORS_RUN_UNTIL(tps, PN_TRANSPORT_CLOSED); /* Verify peer with good hostname */ TEST_INT_EQUAL(t, 0, pn_ssl_domain_set_trusted_ca_db(cd, CERTIFICATE("tserver"))); TEST_INT_EQUAL(t, 0, pn_ssl_domain_set_peer_authentication(cd, PN_SSL_VERIFY_PEER_NAME, NULL)); pn_connection_t *c = pn_connection(); pn_connection_set_hostname(c, "test_server"); pn_proactor_connect2(client->proactor, c, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_COND_EMPTY(t, last_condition); TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps)); TEST_COND_EMPTY(t, last_condition); TEST_PROACTORS_RUN_UNTIL(tps, PN_TRANSPORT_CLOSED); TEST_PROACTORS_RUN_UNTIL(tps, PN_TRANSPORT_CLOSED); /* Verify peer with bad hostname */ c = pn_connection(); pn_connection_set_hostname(c, "wrongname"); pn_proactor_connect2(client->proactor, c, NULL, listener_info(l).connect); TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps)); TEST_COND_NAME(t, "amqp:connection:framing-error", last_condition); TEST_COND_DESC(t, "SSL", last_condition); TEST_PROACTORS_DRAIN(tps); pn_ssl_domain_free(cd); pn_ssl_domain_free(sd); TEST_PROACTORS_DESTROY(tps); }
int pn_messenger_tsync(pn_messenger_t *messenger, bool (*predicate)(pn_messenger_t *), int timeout) { for (int i = 0; i < messenger->size; i++) { pn_connector_process(messenger->connectors[i]); } struct timeval now; if (gettimeofday(&now, NULL)) pn_fatal("gettimeofday failed\n"); long int deadline = millis(now) + timeout; bool pred; while (true) { pred = predicate(messenger); int remaining = deadline - millis(now); if (pred || (timeout >= 0 && remaining < 0)) break; pn_driver_wait(messenger->driver, remaining); pn_listener_t *l; while ((l = pn_driver_listener(messenger->driver))) { pn_connector_t *c = pn_listener_accept(l); pn_sasl_t *sasl = pn_connector_sasl(c); pn_sasl_mechanisms(sasl, "ANONYMOUS"); pn_sasl_server(sasl); pn_sasl_done(sasl, PN_SASL_OK); pn_connection_t *conn = pn_connection(); pn_connection_set_container(conn, messenger->name); pn_connector_set_connection(c, conn); messenger->connectors[messenger->size++] = c; } pn_connector_t *c; while ((c = pn_driver_connector(messenger->driver))) { pn_connector_process(c); pn_connection_t *conn = pn_connector_connection(c); pn_messenger_endpoints(messenger, conn); if (pn_connector_closed(c)) { for (int i = 0; i < messenger->size; i++) { if (c == messenger->connectors[i]) { memmove(messenger->connectors + i, messenger->connectors + i + 1, messenger->size - i - 1); messenger->size--; pn_connector_free(c); pn_messenger_reclaim(messenger, conn); pn_connection_free(conn); pn_messenger_flow(messenger); break; } } } else { pn_connector_process(c); } } if (timeout >= 0) { if (gettimeofday(&now, NULL)) pn_fatal("gettimeofday failed\n"); } } return pred ? 0 : PN_TIMEOUT; }
connection_engine::connection_engine(class handler &h, const connection_options& opts) { connection_ = proton::connection(take_ownership(pn_connection()).get()); pn_ptr<pn_transport_t> transport = take_ownership(pn_transport()); pn_ptr<pn_collector_t> collector = take_ownership(pn_collector()); if (!connection_ || !transport || !collector) throw proton::error("engine create"); int err = pn_transport_bind(transport.get(), connection_.pn_object()); if (err) throw error(msg() << "transport bind:" << pn_code(err)); pn_connection_collect(connection_.pn_object(), collector.get()); ctx_ = &connection_engine_context::get(connection_); // Creates context ctx_->engine_handler = &h; ctx_->transport = transport.release(); ctx_->collector = collector.release(); opts.apply(connection_); // Provide defaults for connection_id and link_prefix if not set. std::string cid = connection_.container_id(); if (cid.empty()) { cid = make_id(); pn_connection_set_container(connection_.pn_object(), cid.c_str()); } id_generator &link_gen = connection_context::get(connection_).link_gen; if (link_gen.prefix().empty()) { link_gen.prefix(make_id()+"/"); } }
/* 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); }
/* 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 */ } }
pn_connection_t *pn_reactor_connection(pn_reactor_t *reactor, pn_handler_t *handler) { assert(reactor); pn_connection_t *connection = pn_connection(); pn_record_t *record = pn_connection_attachments(connection); pn_record_set_handler(record, handler); pn_connection_collect(connection, pn_reactor_collector(reactor)); pn_list_add(pn_reactor_children(reactor), connection); pni_record_init_reactor(record, reactor); pn_decref(connection); return connection; }
connection_engine::connection_engine(class container& cont, link_namer& namer, event_loop* loop) : handler_(0), connection_(make_wrapper(internal::take_ownership(pn_connection()).get())), transport_(make_wrapper(internal::take_ownership(pn_transport()).get())), collector_(internal::take_ownership(pn_collector()).get()), container_(cont) { if (!connection_ || !transport_ || !collector_) throw proton::error("connection_engine create failed"); pn_transport_bind(unwrap(transport_), unwrap(connection_)); pn_connection_collect(unwrap(connection_), collector_.get()); connection_context& ctx = connection_context::get(connection_); ctx.container = &container_; ctx.link_gen = &namer; ctx.event_loop.reset(loop); }
/* Like common_handler but does not auto-close the listener after one accept, and returns on LISTENER_CLOSE */ static pn_event_type_t listen_handler(test_handler_t *th, pn_event_t *e) { switch (pn_event_type(e)) { case PN_LISTENER_ACCEPT: /* No automatic listener close/free for tests that accept multiple connections */ last_accepted = pn_connection(); pn_listener_accept2(pn_event_listener(e), last_accepted, NULL); /* No automatic close */ return PN_EVENT_NONE; case PN_LISTENER_CLOSE: return PN_LISTENER_CLOSE; default: return common_handler(th, e); } }
static void test_netaddr(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; /* Use IPv4 to get consistent results all platforms */ pn_listener_t *l = test_listen(&tps[1], "127.0.0.1"); pn_connection_t *c = pn_connection(); pn_proactor_connect2(client, c, NULL, listener_info(l).connect); if (!TEST_ETYPE_EQUAL(t, PN_CONNECTION_REMOTE_OPEN, TEST_PROACTORS_RUN(tps))) { TEST_COND_EMPTY(t, last_condition); /* Show the last condition */ return; /* don't continue if connection is closed */ } /* client remote, client local, server remote and server local address strings */ char cr[1024], cl[1024], sr[1024], sl[1024]; pn_transport_t *ct = pn_connection_transport(c); const pn_netaddr_t *na = pn_transport_remote_addr(ct); pn_netaddr_str(na, cr, sizeof(cr)); TEST_STR_IN(t, listener_info(l).port, cr); /* remote address has listening port */ pn_connection_t *s = last_accepted; /* server side of the connection */ pn_transport_t *st = pn_connection_transport(s); if (!TEST_CHECK(t, st)) return; pn_netaddr_str(pn_transport_local_addr(st), sl, sizeof(sl)); TEST_STR_EQUAL(t, cr, sl); /* client remote == server local */ pn_netaddr_str(pn_transport_local_addr(ct), cl, sizeof(cl)); pn_netaddr_str(pn_transport_remote_addr(st), sr, sizeof(sr)); TEST_STR_EQUAL(t, cl, sr); /* client local == server remote */ char host[MAX_STR] = ""; char serv[MAX_STR] = ""; int err = pn_netaddr_host_port(na, host, sizeof(host), serv, sizeof(serv)); TEST_CHECK(t, 0 == err); TEST_STR_EQUAL(t, "127.0.0.1", host); TEST_STR_EQUAL(t, listener_info(l).port, serv); /* Make sure you can use NULL, 0 to get length of address string without a crash */ size_t len = pn_netaddr_str(pn_transport_local_addr(ct), NULL, 0); TEST_CHECKF(t, strlen(cl) == len, "%d != %d", strlen(cl), len); TEST_PROACTORS_DRAIN(tps); TEST_PROACTORS_DESTROY(tps); }
/* Test sending/receiving a message in chunks */ static void test_message_stream(test_t *t) { test_proactor_t tps[] ={ test_proactor(t, message_stream_handler), test_proactor(t, message_stream_handler) }; pn_proactor_t *client = tps[0].proactor; pn_listener_t *l = test_listen(&tps[1], ""); struct message_stream_context ctx = { 0 }; tps[0].handler.context = &ctx; tps[1].handler.context = &ctx; /* Encode a large (not very) message to send in chunks */ char *body = (char*)malloc(BODY); memset(body, 'x', BODY); pn_message_t *m = pn_message(); pn_data_put_binary(pn_message_body(m), pn_bytes(BODY, body)); free(body); ctx.size = message_encode(m, &ctx.send_buf); pn_message_free(m); pn_connection_t *c = pn_connection(); pn_proactor_connect2(client, c, NULL, listener_info(l).connect); pn_session_t *ssn = pn_session(c); pn_session_open(ssn); pn_link_t *snd = pn_sender(ssn, "x"); pn_link_open(snd); TEST_PROACTORS_RUN_UNTIL(tps, PN_LINK_FLOW); /* Send and receive the message in chunks */ do { pn_connection_wake(c); /* Initiate send/receive of one chunk */ do { /* May be multiple receives for one send */ TEST_PROACTORS_RUN_UNTIL(tps, PN_DELIVERY); } while (ctx.received < ctx.sent); } while (!ctx.complete); TEST_CHECK(t, ctx.received == ctx.size); TEST_CHECK(t, ctx.sent == ctx.size); TEST_CHECK(t, !memcmp(ctx.send_buf.start, ctx.recv_buf.start, ctx.size)); free(ctx.send_buf.start); free(ctx.recv_buf.start); TEST_PROACTORS_DESTROY(tps); }
pn_connection_t *pn_messenger_domain(pn_messenger_t *messenger, const char *domain) { char buf[domain ? strlen(domain) + 1 : 1]; if (domain) { strcpy(buf, domain); } else { buf[0] = '\0'; } char *user = NULL; char *pass = NULL; char *host = "0.0.0.0"; char *port = "5672"; parse_url(buf, &user, &pass, &host, &port); for (int i = 0; i < messenger->size; i++) { pn_connection_t *connection = pn_connector_connection(messenger->connectors[i]); const char *container = pn_connection_remote_container(connection); const char *hostname = pn_connection_hostname(connection); if (pn_streq(container, domain) || pn_streq(hostname, domain)) return connection; } pn_connector_t *connector = pn_connector(messenger->driver, host, port, NULL); if (!connector) return NULL; messenger->connectors[messenger->size++] = connector; pn_sasl_t *sasl = pn_connector_sasl(connector); if (user) { pn_sasl_plain(sasl, user, pass); } else { pn_sasl_mechanisms(sasl, "ANONYMOUS"); pn_sasl_client(sasl); } pn_connection_t *connection = pn_connection(); pn_connection_set_container(connection, messenger->name); pn_connection_set_hostname(connection, domain); pn_connection_open(connection); pn_connector_set_connection(connector, connection); return connection; }
bool get_sasl_over_with ( pn_connector_t * connector ) { pn_sasl_t *sasl = pn_connector_sasl ( connector ); while ( pn_sasl_state(sasl) != PN_SASL_PASS ) { switch ( pn_sasl_state(sasl)) { case PN_SASL_IDLE: return false; break; case PN_SASL_CONF: pn_sasl_mechanisms(sasl, "PLAIN ANONYMOUS"); pn_sasl_server(sasl); break; case PN_SASL_STEP: { char response [ MY_BUF_SIZE ]; pn_sasl_recv(sasl, response, pn_sasl_pending(sasl) ); pn_sasl_done(sasl, PN_SASL_OK); pn_connector_set_connection(connector, pn_connection()); } break; case PN_SASL_PASS: break; case PN_SASL_FAIL: return false; break; } } return true; }
void server_callback(pn_connector_t *ctor) { pn_sasl_t *sasl = pn_connector_sasl(ctor); while (pn_sasl_state(sasl) != PN_SASL_PASS) { switch (pn_sasl_state(sasl)) { case PN_SASL_IDLE: return; case PN_SASL_CONF: pn_sasl_mechanisms(sasl, "PLAIN ANONYMOUS"); pn_sasl_server(sasl); break; case PN_SASL_STEP: { size_t n = pn_sasl_pending(sasl); char iresp[n]; pn_sasl_recv(sasl, iresp, n); printf("%s", pn_sasl_remote_mechanisms(sasl)); printf(" response = "); pn_print_data(iresp, n); printf("\n"); pn_sasl_done(sasl, PN_SASL_OK); pn_connector_set_connection(ctor, pn_connection()); } break; case PN_SASL_PASS: break; case PN_SASL_FAIL: return; } } pn_connection_t *conn = pn_connector_connection(ctor); struct server_context *ctx = pn_connector_context(ctor); char tagstr[1024]; char msg[10*1024]; char data[ctx->size + 16]; for (int i = 0; i < ctx->size; i++) { msg[i] = 'x'; } size_t ndata = pn_message_data(data, ctx->size + 16, msg, ctx->size); if (pn_connection_state(conn) == (PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE)) { pn_connection_open(conn); } pn_session_t *ssn = pn_session_head(conn, PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE); while (ssn) { pn_session_open(ssn); ssn = pn_session_next(ssn, PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE); } pn_link_t *link = pn_link_head(conn, PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE); while (link) { printf("%s, %s\n", pn_remote_source(link), pn_remote_target(link)); pn_set_source(link, pn_remote_source(link)); pn_set_target(link, pn_remote_target(link)); pn_link_open(link); if (pn_is_receiver(link)) { pn_flow(link, 100); } else { pn_delivery(link, pn_dtag("blah", 4)); } link = pn_link_next(link, PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE); } pn_delivery_t *delivery = pn_work_head(conn); while (delivery) { pn_delivery_tag_t tag = pn_delivery_tag(delivery); pn_quote_data(tagstr, 1024, tag.bytes, tag.size); pn_link_t *link = pn_link(delivery); if (pn_readable(delivery)) { if (!ctx->quiet) { printf("received delivery: %s\n", tagstr); printf(" payload = \""); } while (true) { ssize_t n = pn_recv(link, msg, 1024); if (n == PN_EOS) { pn_advance(link); pn_disposition(delivery, PN_ACCEPTED); break; } else if (!ctx->quiet) { pn_print_data(msg, n); } } if (!ctx->quiet) printf("\"\n"); if (pn_credit(link) < 50) pn_flow(link, 100); } else if (pn_writable(delivery)) { pn_send(link, data, ndata); if (pn_advance(link)) { if (!ctx->quiet) printf("sent delivery: %s\n", tagstr); char tagbuf[16]; sprintf(tagbuf, "%i", ctx->count++); pn_delivery(link, pn_dtag(tagbuf, strlen(tagbuf))); } } if (pn_updated(delivery)) { if (!ctx->quiet) printf("disposition for %s: %u\n", tagstr, pn_remote_disposition(delivery)); pn_settle(delivery); } delivery = pn_work_next(delivery); } if (pn_connection_state(conn) == (PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED)) { pn_connection_close(conn); } ssn = pn_session_head(conn, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED); while (ssn) { pn_session_close(ssn); ssn = pn_session_next(ssn, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED); } link = pn_link_head(conn, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED); while (link) { pn_link_close(link); link = pn_link_next(link, PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED); } }
int main(int argc, char **argv) { char *url = NULL; char *address = "queue"; char *mechanism = "ANONYMOUS"; int count = 1; bool quiet = false; int high = 100; int low = 50; int size = 32; int opt; while ((opt = getopt(argc, argv, "c:a:m:n:s:u:l:qhVXY")) != -1) { switch (opt) { case 'c': if (url) pn_fatal("multiple connect urls not allowed\n"); url = optarg; break; case 'a': address = optarg; break; case 'm': mechanism = optarg; break; case 'n': count = atoi(optarg); break; case 's': size = atoi(optarg); break; case 'u': high = atoi(optarg); break; case 'l': low = atoi(optarg); break; case 'q': quiet = true; break; case 'V': printf("proton version %i.%i\n", PN_VERSION_MAJOR, PN_VERSION_MINOR); exit(EXIT_SUCCESS); case 'X': value(argc, argv); exit(EXIT_SUCCESS); case 'Y': buffer(argc, argv); exit(EXIT_SUCCESS); case 'h': printf("Usage: %s [-h] [-c [user[:password]@]host[:port]] [-a <address>] [-m <sasl-mech>]\n", argv[0]); printf("\n"); printf(" -c The connect url.\n"); printf(" -a The AMQP address.\n"); printf(" -m The SASL mechanism.\n"); printf(" -n The number of messages.\n"); printf(" -s Message size.\n"); printf(" -u Upper flow threshold.\n"); printf(" -l Lower flow threshold.\n"); printf(" -q Supress printouts.\n"); printf(" -h Print this help.\n"); exit(EXIT_SUCCESS); default: /* '?' */ pn_fatal("Usage: %s -h\n", argv[0]); } } char *user = NULL; char *pass = NULL; char *host = "0.0.0.0"; char *port = "5672"; parse_url(url, &user, &pass, &host, &port); pn_driver_t *drv = pn_driver(); if (url) { struct client_context ctx = {false, false, count, count, drv, quiet, size, high, low}; ctx.username = user; ctx.password = pass; ctx.mechanism = mechanism; ctx.hostname = host; ctx.address = address; pn_connector_t *ctor = pn_connector(drv, host, port, &ctx); if (!ctor) pn_fatal("connector failed\n"); pn_connector_set_connection(ctor, pn_connection()); while (!ctx.done) { pn_driver_wait(drv, -1); pn_connector_t *c; while ((c = pn_driver_connector(drv))) { pn_connector_process(c); client_callback(c); if (pn_connector_closed(c)) { pn_connection_free(pn_connector_connection(c)); pn_connector_free(c); } else { pn_connector_process(c); } } } } else { struct server_context ctx = {0, quiet, size}; if (!pn_listener(drv, host, port, &ctx)) pn_fatal("listener failed\n"); while (true) { pn_driver_wait(drv, -1); pn_listener_t *l; pn_connector_t *c; while ((l = pn_driver_listener(drv))) { c = pn_listener_accept(l); pn_connector_set_context(c, &ctx); } while ((c = pn_driver_connector(drv))) { pn_connector_process(c); server_callback(c); if (pn_connector_closed(c)) { pn_connection_free(pn_connector_connection(c)); pn_connector_free(c); } else { pn_connector_process(c); } } } } pn_driver_free(drv); return 0; }