6363#undef _GNU_SOURCE
6464
6565#include "epoll-internal.h"
66+ #include "epoll_name_lookup.h"
6667#include "proactor-internal.h"
6768#include "core/engine-internal.h"
6869#include "core/logger_private.h"
@@ -632,6 +633,10 @@ static inline pn_listener_t *task_listener(task_t *t) {
632633 return t -> type == LISTENER ? containerof (t , pn_listener_t , task ) : NULL ;
633634}
634635
636+ static inline pname_lookup_t * task_name_lookup (task_t * t ) {
637+ return t -> type == NAME_LOOKUP ? containerof (t , pname_lookup_t , task ) : NULL ;
638+ }
639+
635640static pn_event_t * listener_batch_next (pn_event_batch_t * batch );
636641static pn_event_t * proactor_batch_next (pn_event_batch_t * batch );
637642static pn_event_t * pconnection_batch_next (pn_event_batch_t * batch );
@@ -1408,15 +1413,6 @@ static void pconnection_maybe_connect_lh(pconnection_t *pc) {
14081413 pc -> disconnected = true;
14091414}
14101415
1411- int pgetaddrinfo (const char * host , const char * port , int flags , struct addrinfo * * res )
1412- {
1413- // NOTE: getaddrinfo can block on DNS lookup (PROTON-2812).
1414- struct addrinfo hints = { 0 };
1415- hints .ai_family = AF_UNSPEC ;
1416- hints .ai_socktype = SOCK_STREAM ;
1417- hints .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | flags ;
1418- return getaddrinfo (host , port , & hints , res );
1419- }
14201416
14211417static inline bool is_inactive (pn_proactor_t * p ) {
14221418 return (!p -> tasks && !p -> disconnects_pending && !p -> timeout_set && !p -> shutting_down );
@@ -1431,23 +1427,39 @@ bool schedule_if_inactive(pn_proactor_t *p) {
14311427 return false;
14321428}
14331429
1430+ /* Called when connection name lookup completes (from name_lookup done_cb). Call with task lock held. */
1431+ static void connection_lookup_done_lh (pconnection_t * pc , struct addrinfo * ai , int gai_error ) {
1432+ pn_proactor_t * p = pc -> task .proactor ;
1433+ bool notify = false;
1434+ if (gai_error ) {
1435+ psocket_gai_error (& pc -> psocket , gai_error , "connect to " );
1436+ } else if (ai ) {
1437+ pc -> addrinfo = ai ;
1438+ pc -> ai = ai ;
1439+ pconnection_maybe_connect_lh (pc );
1440+ if (pc -> psocket .epoll_io .fd != -1 && !pc -> queued_disconnect && !pni_task_wake_pending (& pc -> task )) {
1441+ return ;
1442+ }
1443+ }
1444+ notify = schedule (& pc -> task );
1445+ if (notify ) notify_poller (p );
1446+ }
1447+
1448+ static void connection_done_cb (void * user_data , struct addrinfo * ai , int gai_error ) {
1449+ pconnection_t * pc = (pconnection_t * )user_data ;
1450+ lock (& pc -> task .mutex );
1451+ connection_lookup_done_lh (pc , ai , gai_error );
1452+ unlock (& pc -> task .mutex );
1453+ }
1454+
14341455// Call from pconnection_process with task lock held.
14351456// Return true if the socket is connecting and there are no Proton events to deliver.
14361457static bool pconnection_first_connect_lh (pconnection_t * pc ) {
1458+ pn_proactor_t * p = pc -> task .proactor ;
14371459 unlock (& pc -> task .mutex );
1438- // TODO: move this step to a separate worker thread that scales in response to multiple blocking DNS lookups.
1439- int gai_error = pgetaddrinfo (pc -> host , pc -> port , 0 , & pc -> addrinfo );
1460+ bool rc = pni_name_lookup_start (& p -> name_lookup , pc -> host , pc -> port , pc , connection_done_cb );
14401461 lock (& pc -> task .mutex );
1441-
1442- if (!gai_error ) {
1443- pc -> ai = pc -> addrinfo ;
1444- pconnection_maybe_connect_lh (pc ); /* Start connection attempts */
1445- if (pc -> psocket .epoll_io .fd != -1 && !pc -> queued_disconnect && !pni_task_wake_pending (& pc -> task ))
1446- return true;
1447- } else {
1448- psocket_gai_error (& pc -> psocket , gai_error , "connect to " );
1449- }
1450- return false;
1462+ return rc ;
14511463}
14521464
14531465void pn_proactor_connect2 (pn_proactor_t * p , pn_connection_t * c , pn_transport_t * t , const char * addr ) {
@@ -1579,7 +1591,7 @@ void pn_proactor_listen(pn_proactor_t *p, pn_listener_t *l, const char *addr, in
15791591 pni_parse_addr (addr , l -> addr_buf , sizeof (l -> addr_buf ), & l -> host , & l -> port );
15801592
15811593 struct addrinfo * addrinfo = NULL ;
1582- int gai_err = pgetaddrinfo (l -> host , l -> port , AI_PASSIVE | AI_ALL , & addrinfo );
1594+ int gai_err = pni_name_lookup_blocking (l -> host , l -> port , AI_PASSIVE | AI_ALL , & addrinfo );
15831595 if (!gai_err ) {
15841596 /* Count addresses, allocate enough space for sockets */
15851597 size_t len = 0 ;
@@ -2021,23 +2033,27 @@ pn_proactor_t *pn_proactor(void) {
20212033 if ((p -> epollfd = epoll_create (1 )) >= 0 ) {
20222034 if ((p -> eventfd = eventfd (0 , EFD_NONBLOCK )) >= 0 ) {
20232035 if ((p -> interruptfd = eventfd (0 , EFD_NONBLOCK )) >= 0 ) {
2024- if (pni_timer_manager_init (& p -> timer_manager ))
2025- if ((p -> collector = pn_collector ()) != NULL ) {
2026- p -> batch .next_event = & proactor_batch_next ;
2027- start_polling (& p -> timer_manager .epoll_timer , p -> epollfd ); // TODO: check for error
2028- epoll_eventfd_init (& p -> epoll_schedule , p -> eventfd , p -> epollfd , true);
2029- epoll_eventfd_init (& p -> epoll_interrupt , p -> interruptfd , p -> epollfd , false);
2030- p -> tslot_map = pn_hash (PN_VOID , 0 , 0.75 );
2031- grow_poller_bufs (p );
2032- p -> ready_list_generation = 1 ;
2033- return p ;
2036+ if (pni_timer_manager_init (& p -> timer_manager )) {
2037+ if (pni_name_lookup_init (& p -> name_lookup , p )) {
2038+ if ((p -> collector = pn_collector ()) != NULL ) {
2039+ p -> batch .next_event = & proactor_batch_next ;
2040+ start_polling (& p -> timer_manager .epoll_timer , p -> epollfd ); // TODO: check for error
2041+ epoll_eventfd_init (& p -> epoll_schedule , p -> eventfd , p -> epollfd , true);
2042+ epoll_eventfd_init (& p -> epoll_interrupt , p -> interruptfd , p -> epollfd , false);
2043+ p -> tslot_map = pn_hash (PN_VOID , 0 , 0.75 );
2044+ grow_poller_bufs (p );
2045+ p -> ready_list_generation = 1 ;
2046+ return p ;
2047+ }
20342048 }
2049+ }
20352050 }
20362051 }
20372052 }
20382053 if (p -> epollfd >= 0 ) close (p -> epollfd );
20392054 if (p -> eventfd >= 0 ) close (p -> eventfd );
20402055 if (p -> interruptfd >= 0 ) close (p -> interruptfd );
2056+ pni_name_lookup_cleanup (& p -> name_lookup , p );
20412057 pni_timer_manager_finalize (& p -> timer_manager );
20422058 pmutex_finalize (& p -> timeout_mutex );
20432059 pmutex_finalize (& p -> tslot_mutex );
@@ -2071,11 +2087,15 @@ void pn_proactor_free(pn_proactor_t *p) {
20712087 case RAW_CONNECTION :
20722088 pni_raw_connection_forced_shutdown (pni_task_raw_connection (tsk ));
20732089 break ;
2090+ case NAME_LOOKUP :
2091+ pni_name_lookup_forced_shutdown (task_name_lookup (tsk ));
2092+ break ;
20742093 default :
20752094 break ;
20762095 }
20772096 }
20782097
2098+ pni_name_lookup_cleanup (& p -> name_lookup , p );
20792099 pni_timer_manager_finalize (& p -> timer_manager );
20802100 pn_collector_free (p -> collector );
20812101 pmutex_finalize (& p -> timeout_mutex );
@@ -2309,6 +2329,11 @@ static pn_event_batch_t *process(task_t *tsk) {
23092329 batch = pni_timer_manager_process (tm , timeout , tsk_ready );
23102330 break ;
23112331 }
2332+ case NAME_LOOKUP :
2333+ unlock (& p -> sched_mutex );
2334+ pni_name_lookup_process_events (& p -> name_lookup );
2335+ batch = NULL ;
2336+ break ;
23122337 default :
23132338 assert (NULL );
23142339 }
@@ -2350,6 +2375,11 @@ static task_t *post_event(pn_proactor_t *p, struct epoll_event *evp) {
23502375 }
23512376 // else if (ee->fd == p->eventfd)... schedule_ready_list already performed by poller task.
23522377 break ;
2378+ case NAME_LOOKUP_EPOLL : {
2379+ tsk = & p -> name_lookup .task ;
2380+ tsk -> sched_pending = true;
2381+ break ;
2382+ }
23532383 case PCONNECTION_IO : {
23542384 psocket_t * ps = containerof (ee , psocket_t , epoll_io );
23552385 pconnection_t * pc = psocket_pconnection (ps );
@@ -2581,11 +2611,10 @@ static bool poller_do_epoll(struct pn_proactor_t* p, tslot_t *ts, bool can_block
25812611 unlock (& p -> eventfd_mutex );
25822612 }
25832613
2584- int timeout = (epoll_immediate ) ? 0 : -1 ;
2585- p -> poller_suspended = (timeout == -1 );
2614+ p -> poller_suspended = !epoll_immediate ;
25862615 unlock (& p -> sched_mutex );
25872616
2588- n_events = epoll_wait (p -> epollfd , p -> kevents , p -> kevents_capacity , timeout );
2617+ n_events = epoll_wait (p -> epollfd , p -> kevents , p -> kevents_capacity , epoll_immediate ? 0 : -1 );
25892618
25902619 lock (& p -> sched_mutex );
25912620 p -> poller_suspended = false;
@@ -2612,8 +2641,9 @@ static bool poller_do_epoll(struct pn_proactor_t* p, tslot_t *ts, bool can_block
26122641 unlock (& p -> eventfd_mutex );
26132642
26142643 if (n_events < 0 ) {
2615- if (errno != EINTR )
2644+ if (errno != EINTR ) {
26162645 perror ("epoll_wait" ); // TODO: proper log
2646+ }
26172647 if (!can_block && !unpolled_work )
26182648 return true;
26192649 else
@@ -2622,8 +2652,9 @@ static bool poller_do_epoll(struct pn_proactor_t* p, tslot_t *ts, bool can_block
26222652 if (!can_block && !unpolled_work )
26232653 return true;
26242654 else {
2625- if (!epoll_immediate )
2655+ if (!epoll_immediate ) {
26262656 perror ("epoll_wait unexpected timeout" ); // TODO: proper log
2657+ }
26272658 if (!unpolled_work )
26282659 continue ;
26292660 }
0 commit comments