@ -63,6 +63,7 @@ int mosquitto_main_loop(struct mosquitto_db *db, int *listensock, int listensock
time_t now_time ;
int time_count ;
int fdcount ;
struct mosquitto * context , * ctxt_tmp ;
# ifndef WIN32
sigset_t sigblock , origsig ;
# endif
@ -74,21 +75,32 @@ int mosquitto_main_loop(struct mosquitto_db *db, int *listensock, int listensock
int bridge_sock ;
int rc ;
# endif
int context_count ;
time_t expiration_check_time = 0 ;
# ifndef WIN32
sigemptyset ( & sigblock ) ;
sigaddset ( & sigblock , SIGINT ) ;
# endif
if ( db - > config - > persistent_client_expiration > 0 ) {
expiration_check_time = time ( NULL ) + db - > config - > persistent_client_expiration ;
}
while ( run ) {
HASH_ITER ( hh_for_free , db - > contexts_for_free , context , ctxt_tmp ) {
HASH_DELETE ( hh_for_free , db - > contexts_for_free , context ) ;
mqtt3_context_cleanup ( db , context , true ) ;
}
# ifdef WITH_SYS_TREE
if ( db - > config - > sys_interval > 0 ) {
mqtt3_db_sys_update ( db , db - > config - > sys_interval , start_time ) ;
}
# endif
if ( listensock_count + db - > context_count > pollfd_count | | ! pollfds ) {
pollfd_count = listensock_count + db - > context_count ;
context_count = HASH_CNT ( hh_sock , db - > contexts_by_sock ) ;
if ( listensock_count + context_count > pollfd_count | | ! pollfds ) {
pollfd_count = listensock_count + context_count ;
pollfds = _mosquitto_realloc ( pollfds , sizeof ( struct pollfd ) * pollfd_count ) ;
if ( ! pollfds ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_ERR , " Error: Out of memory. " ) ;
@ -109,130 +121,137 @@ int mosquitto_main_loop(struct mosquitto_db *db, int *listensock, int listensock
now_time = time ( NULL ) ;
time_count = 0 ;
for ( i = 0 ; i < db - > context_count ; i + + ) {
if ( db - > contexts [ i ] ) {
HASH_ITER ( hh_sock , db - > contexts_by_sock , context , ctxt_tmp ) {
if ( time_count > 0 ) {
time_count - - ;
} else {
time_count = 1000 ;
now = mosquitto_time ( ) ;
}
context - > pollfd_index = - 1 ;
if ( context - > sock ! = INVALID_SOCKET ) {
# ifdef WITH_BRIDGE
if ( context - > bridge ) {
_mosquitto_check_keepalive ( db , context ) ;
if ( context - > bridge - > round_robin = = false
& & context - > bridge - > cur_address ! = 0
& & now > context - > bridge - > primary_retry ) {
/* FIXME - this should be non-blocking */
if ( _mosquitto_try_connect ( context - > bridge - > addresses [ 0 ] . address , context - > bridge - > addresses [ 0 ] . port , & bridge_sock , NULL , true ) = = MOSQ_ERR_SUCCESS ) {
COMPAT_CLOSE ( bridge_sock ) ;
_mosquitto_socket_close ( db , context ) ;
context - > bridge - > cur_address = context - > bridge - > address_count - 1 ;
}
}
}
# endif
/* Local bridges never time out in this fashion. */
if ( ! ( context - > keepalive )
| | context - > bridge
| | now - context - > last_msg_in < ( time_t ) ( context - > keepalive ) * 3 / 2 ) {
if ( mqtt3_db_message_write ( context ) = = MOSQ_ERR_SUCCESS ) {
pollfds [ pollfd_index ] . fd = context - > sock ;
pollfds [ pollfd_index ] . events = POLLIN ;
pollfds [ pollfd_index ] . revents = 0 ;
if ( context - > current_out_packet ) {
pollfds [ pollfd_index ] . events | = POLLOUT ;
}
context - > pollfd_index = pollfd_index ;
pollfd_index + + ;
} else {
mqtt3_context_disconnect ( db , context ) ;
}
} else {
if ( db - > config - > connection_messages = = true ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Client %s has exceeded timeout, disconnecting. " , context - > id ) ;
}
/* Client has exceeded keepalive*1.5 */
mqtt3_context_disconnect ( db , context ) ;
}
}
}
# ifdef WITH_BRIDGE
time_count = 0 ;
HASH_ITER ( hh_bridge , db - > contexts_bridge , context , ctxt_tmp ) {
if ( context - > sock = = INVALID_SOCKET ) {
if ( time_count > 0 ) {
time_count - - ;
} else {
time_count = 1000 ;
now = mosquitto_time ( ) ;
}
db - > contexts [ i ] - > pollfd_index = - 1 ;
if ( db - > contexts [ i ] - > sock ! = INVALID_SOCKET ) {
# ifdef WITH_BRIDGE
if ( db - > contexts [ i ] - > bridge ) {
_mosquitto_check_keepalive ( db - > contexts [ i ] ) ;
if ( db - > contexts [ i ] - > bridge - > round_robin = = false
& & db - > contexts [ i ] - > bridge - > cur_address ! = 0
& & now > db - > contexts [ i ] - > bridge - > primary_retry ) {
/* FIXME - this should be non-blocking */
if ( _mosquitto_try_connect ( db - > contexts [ i ] - > bridge - > addresses [ 0 ] . address , db - > contexts [ i ] - > bridge - > addresses [ 0 ] . port , & bridge_sock , NULL , true ) = = MOSQ_ERR_SUCCESS ) {
COMPAT_CLOSE ( bridge_sock ) ;
_mosquitto_socket_close ( db - > contexts [ i ] ) ;
db - > contexts [ i ] - > bridge - > cur_address = db - > contexts [ i ] - > bridge - > address_count - 1 ;
/* Want to try to restart the bridge connection */
if ( ! context - > bridge - > restart_t ) {
context - > bridge - > restart_t = now + context - > bridge - > restart_timeout ;
context - > bridge - > cur_address + + ;
if ( context - > bridge - > cur_address = = context - > bridge - > address_count ) {
context - > bridge - > cur_address = 0 ;
}
if ( context - > bridge - > round_robin = = false & & context - > bridge - > cur_address ! = 0 ) {
context - > bridge - > primary_retry = now + 5 ;
}
} else {
if ( context - > bridge - > start_type = = bst_lazy & & context - > bridge - > lazy_reconnect ) {
rc = mqtt3_bridge_connect ( db , context ) ;
if ( rc ) {
context - > bridge - > cur_address + + ;
if ( context - > bridge - > cur_address = = context - > bridge - > address_count ) {
context - > bridge - > cur_address = 0 ;
}
}
}
# endif
/* Local bridges never time out in this fashion. */
if ( ! ( db - > contexts [ i ] - > keepalive )
| | db - > contexts [ i ] - > bridge
| | now - db - > contexts [ i ] - > last_msg_in < ( time_t ) ( db - > contexts [ i ] - > keepalive ) * 3 / 2 ) {
if ( mqtt3_db_message_write ( db - > contexts [ i ] ) = = MOSQ_ERR_SUCCESS ) {
pollfds [ pollfd_index ] . fd = db - > contexts [ i ] - > sock ;
if ( context - > bridge - > start_type = = bst_automatic & & now > context - > bridge - > restart_t ) {
context - > bridge - > restart_t = 0 ;
rc = mqtt3_bridge_connect ( db , context ) ;
if ( rc = = MOSQ_ERR_SUCCESS ) {
pollfds [ pollfd_index ] . fd = context - > sock ;
pollfds [ pollfd_index ] . events = POLLIN ;
pollfds [ pollfd_index ] . revents = 0 ;
if ( db - > contexts [ i ] - > current_out_packet ) {
if ( context - > current_out_packet ) {
pollfds [ pollfd_index ] . events | = POLLOUT ;
}
db - > contexts [ i ] - > pollfd_index = pollfd_index ;
context- > pollfd_index = pollfd_index ;
pollfd_index + + ;
} else {
mqtt3_context_disconnect ( db , db - > contexts [ i ] ) ;
}
} else {
if ( db - > config - > connection_messages = = true ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Client %s has exceeded timeout, disconnecting. " , db - > contexts [ i ] - > id ) ;
}
/* Client has exceeded keepalive*1.5 */
mqtt3_context_disconnect ( db , db - > contexts [ i ] ) ;
}
} else {
# ifdef WITH_BRIDGE
if ( db - > contexts [ i ] - > bridge ) {
/* Want to try to restart the bridge connection */
if ( ! db - > contexts [ i ] - > bridge - > restart_t ) {
db - > contexts [ i ] - > bridge - > restart_t = now + db - > contexts [ i ] - > bridge - > restart_timeout ;
db - > contexts [ i ] - > bridge - > cur_address + + ;
if ( db - > contexts [ i ] - > bridge - > cur_address = = db - > contexts [ i ] - > bridge - > address_count ) {
db - > contexts [ i ] - > bridge - > cur_address = 0 ;
}
if ( db - > contexts [ i ] - > bridge - > round_robin = = false & & db - > contexts [ i ] - > bridge - > cur_address ! = 0 ) {
db - > contexts [ i ] - > bridge - > primary_retry = now + 5 ;
}
} else {
if ( db - > contexts [ i ] - > bridge - > start_type = = bst_lazy & & db - > contexts [ i ] - > bridge - > lazy_reconnect ) {
rc = mqtt3_bridge_connect ( db , db - > contexts [ i ] ) ;
if ( rc ) {
db - > contexts [ i ] - > bridge - > cur_address + + ;
if ( db - > contexts [ i ] - > bridge - > cur_address = = db - > contexts [ i ] - > bridge - > address_count ) {
db - > contexts [ i ] - > bridge - > cur_address = 0 ;
}
}
}
if ( db - > contexts [ i ] - > bridge - > start_type = = bst_automatic & & now > db - > contexts [ i ] - > bridge - > restart_t ) {
db - > contexts [ i ] - > bridge - > restart_t = 0 ;
rc = mqtt3_bridge_connect ( db , db - > contexts [ i ] ) ;
if ( rc = = MOSQ_ERR_SUCCESS ) {
pollfds [ pollfd_index ] . fd = db - > contexts [ i ] - > sock ;
pollfds [ pollfd_index ] . events = POLLIN ;
pollfds [ pollfd_index ] . revents = 0 ;
if ( db - > contexts [ i ] - > current_out_packet ) {
pollfds [ pollfd_index ] . events | = POLLOUT ;
}
db - > contexts [ i ] - > pollfd_index = pollfd_index ;
pollfd_index + + ;
} else {
/* Retry later. */
db - > contexts [ i ] - > bridge - > restart_t = now + db - > contexts [ i ] - > bridge - > restart_timeout ;
db - > contexts [ i ] - > bridge - > cur_address + + ;
if ( db - > contexts [ i ] - > bridge - > cur_address = = db - > contexts [ i ] - > bridge - > address_count ) {
db - > contexts [ i ] - > bridge - > cur_address = 0 ;
}
}
/* Retry later. */
context - > bridge - > restart_t = now + context - > bridge - > restart_timeout ;
context - > bridge - > cur_address + + ;
if ( context - > bridge - > cur_address = = context - > bridge - > address_count ) {
context - > bridge - > cur_address = 0 ;
}
}
} else {
}
}
}
}
# endif
if ( db - > contexts [ i ] - > clean_session = = true ) {
mqtt3_context_cleanup ( db , db - > contexts [ i ] , true ) ;
db - > contexts [ i ] = NULL ;
} else if ( db - > config - > persistent_client_expiration > 0 ) {
/* This is a persistent client, check to see if the
* last time it connected was longer than
* persistent_client_expiration seconds ago . If so ,
* expire it and clean up .
*/
if ( now_time > db- > contexts[ i ] - > disconnect_t + db - > config - > persistent_client_expiration ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Expiring persistent client %s due to timeout. " , db- > contexts[ i ] - > id ) ;
now_time = time ( NULL ) ;
if ( db - > config - > persistent_client_expiration > 0 & & now_time > expiration_check_time ) {
HASH_ITER ( hh_id , db - > contexts_by_id , context , ctxt_tmp ) {
if ( context - > sock = = - 1 & & context - > clean_session = = 0 ) {
/* This is a persistent client, check to see if the
* last time it connected was longer than
* persistent_client_expiration seconds ago . If so ,
* expire it and clean up .
*/
if ( now_time > context - > disconnect_t + db - > config - > persistent_client_expiration ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Expiring persistent client %s due to timeout. " , context - > id ) ;
# ifdef WITH_SYS_TREE
g_clients_expired + + ;
g_clients_expired + + ;
# endif
db - > contexts [ i ] - > clean_session = true ;
mqtt3_context_cleanup ( db , db - > contexts [ i ] , true ) ;
db - > contexts [ i ] = NULL ;
}
}
# ifdef WITH_BRIDGE
context - > clean_session = true ;
mqtt3_context_cleanup ( db , context , true ) ;
context = NULL ;
}
# endif
}
}
expiration_check_time = time ( NULL ) + db - > config - > persistent_client_expiration ;
}
mqtt3_db_message_timeout_check ( db , db - > config - > retry_interval ) ;
@ -319,16 +338,16 @@ int mosquitto_main_loop(struct mosquitto_db *db, int *listensock, int listensock
return MOSQ_ERR_SUCCESS ;
}
static void do_disconnect ( struct mosquitto_db * db , int context_index )
static void do_disconnect ( struct mosquitto_db * db , struct mosquitto * context )
{
if ( db - > config - > connection_messages = = true ) {
if ( db- > contexts[ context_index ] - > state ! = mosq_cs_disconnecting ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Socket error on client %s, disconnecting. " , db- > contexts[ context_index ] - > id ) ;
if ( context- > state ! = mosq_cs_disconnecting ) {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Socket error on client %s, disconnecting. " , context- > id ) ;
} else {
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Client %s disconnected. " , db- > contexts[ context_index ] - > id ) ;
_mosquitto_log_printf ( NULL , MOSQ_LOG_NOTICE , " Client %s disconnected. " , context- > id ) ;
}
}
mqtt3_context_disconnect ( db , db- > contexts[ context_index ] ) ;
mqtt3_context_disconnect ( db , context) ;
}
/* Error ocurred, probably an fd has been closed.
@ -336,53 +355,51 @@ static void do_disconnect(struct mosquitto_db *db, int context_index)
*/
static void loop_handle_errors ( struct mosquitto_db * db , struct pollfd * pollfds )
{
int i ;
struct mosquitto * context , * ctxt_tmp ;
for ( i = 0 ; i < db - > context_count ; i + + ) {
if ( db - > contexts [ i ] & & db - > contexts [ i ] - > sock ! = INVALID_SOCKET ) {
if ( pollfds [ db - > contexts [ i ] - > pollfd_index ] . revents & ( POLLERR | POLLNVAL ) ) {
do_disconnect ( db , i ) ;
}
HASH_ITER ( hh_sock , db - > contexts_by_sock , context , ctxt_tmp ) {
if ( pollfds [ context - > pollfd_index ] . revents & ( POLLERR | POLLNVAL ) ) {
do_disconnect ( db , context ) ;
}
}
}
static void loop_handle_reads_writes ( struct mosquitto_db * db , struct pollfd * pollfds )
{
int i ;
struct mosquitto * context , * ctxt_tmp ;
for ( i = 0 ; i < db - > context_count ; i + + ) {
if ( db - > contexts [ i ] & & db - > contexts [ i ] - > sock ! = INVALID_SOCKET ) {
assert ( pollfds [ db - > contexts [ i ] - > pollfd_index ] . fd = = db - > contexts [ i ] - > sock ) ;
HASH_ITER ( hh_sock , db - > contexts_by_sock , context , ctxt_tmp ) {
assert ( pollfds [ context - > pollfd_index ] . fd = = context - > sock ) ;
# ifdef WITH_TLS
if ( pollfds [ db - > context s[ i ] - > pollfd_index ] . revents & POLLOUT | |
db - > context s[ i ] - > want_write | |
( db - > context s[ i ] - > ssl & & db- > contexts[ i ] - > state = = mosq_cs_new ) ) {
if ( pollfds [ context - > pollfd_index ] . revents & POLLOUT | |
context - > want_write | |
( context - > ssl & & context- > state = = mosq_cs_new ) ) {
# else
if ( pollfds [ db - > context s[ i ] - > pollfd_index ] . revents & POLLOUT ) {
if ( pollfds [ context - > pollfd_index ] . revents & POLLOUT ) {
# endif
if ( _mosquitto_packet_write ( db- > contexts[ i ] ) ) {
do_disconnect ( db , i ) ;
}
if ( _mosquitto_packet_write ( context) ) {
do_disconnect ( db , context ) ;
continue ;
}
}
if ( db - > contexts [ i ] & & db - > contexts [ i ] - > sock ! = INVALID_SOCKET ) {
assert ( pollfds [ db - > contexts [ i ] - > pollfd_index ] . fd = = db - > contexts [ i ] - > sock ) ;
}
HASH_ITER ( hh_sock , db - > contexts_by_sock , context , ctxt_tmp ) {
# ifdef WITH_TLS
if ( pollfds [ db - > context s[ i ] - > pollfd_index ] . revents & POLLIN | |
( db - > context s[ i ] - > ssl & & db- > contexts[ i ] - > state = = mosq_cs_new ) ) {
if ( pollfds [ context - > pollfd_index ] . revents & POLLIN | |
( context - > ssl & & context- > state = = mosq_cs_new ) ) {
# else
if ( pollfds [ db - > context s[ i ] - > pollfd_index ] . revents & POLLIN ) {
if ( pollfds [ context - > pollfd_index ] . revents & POLLIN ) {
# endif
if ( _mosquitto_packet_read ( db , db- > contexts[ i ] ) ) {
do_disconnect ( db , i ) ;
}
if ( _mosquitto_packet_read ( db , context) ) {
do_disconnect ( db , context ) ;
continue ;
}
}
if ( db - > contexts [ i ] & & db - > contexts [ i ] - > sock ! = INVALID_SOCKET ) {
if ( pollfds [ db - > context s[ i ] - > pollfd_index ] . revents & ( POLLERR | POLLNVAL ) ) {
do_disconnect ( db , i ) ;
}
if ( pollfds [ context - > pollfd_index ] . revents & ( POLLERR | POLLNVAL ) ) {
do_disconnect ( db , context ) ;
continue ;
}
}
}