@ -81,6 +81,7 @@ import java.util.ArrayList;
import java.util.List ;
import java.util.Optional ;
import java.util.UUID ;
import java.util.concurrent.Callable ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ConcurrentMap ;
import java.util.concurrent.TimeUnit ;
@ -153,10 +154,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
if ( message . decoderResult ( ) . isSuccess ( ) ) {
processMqttMsg ( ctx , message ) ;
} else {
log . error ( "[{}] Message process ing failed: {}" , sessionId , message . decoderResult ( ) . cause ( ) . getMessage ( ) ) ;
log . error ( "[{}] Message decod ing failed: {}" , sessionId , message . decoderResult ( ) . cause ( ) . getMessage ( ) ) ;
ctx . close ( ) ;
}
} else {
log . debug ( "[{}] Received non mqtt message: {}" , sessionId , msg . getClass ( ) . getSimpleName ( ) ) ;
ctx . close ( ) ;
}
} finally {
@ -168,7 +170,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
address = getAddress ( ctx ) ;
if ( msg . fixedHeader ( ) = = null ) {
log . info ( "[{}:{}] Invalid message received" , address . getHostName ( ) , address . getPort ( ) ) ;
processDisconnect ( ctx ) ;
ctx . close ( ) ;
return ;
}
deviceSessionCtx . setChannel ( ctx ) ;
@ -208,8 +210,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
} else {
log . debug ( "[{}] Unsupported topic for provisioning requests: {}!" , sessionId , topicName ) ;
ctx . close ( ) ;
throw new RuntimeException ( "Unsupported topic for provisioning requests!" ) ;
}
} catch ( RuntimeException | AdaptorException e ) {
log . warn ( "[{}] Failed to process publish msg [{}][{}]" , sessionId , topicName , msgId , e ) ;
@ -220,48 +222,30 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
ctx . writeAndFlush ( new MqttMessage ( new MqttFixedHeader ( PINGRESP , false , AT_MOST_ONCE , false , 0 ) ) ) ;
break ;
case DISCONNECT :
if ( checkConnected ( ctx , msg ) ) {
processDisconnect ( ctx ) ;
}
ctx . close ( ) ;
break ;
}
}
void enqueueRegularSessionMsg ( ChannelHandlerContext ctx , MqttMessage msg ) {
final int queueSize = deviceSessionCtx . getMsgQueueSize ( ) . incrementAndGet ( ) ;
if ( queueSize > context . getMessageQueueSizePerDeviceLimit ( ) ) {
log . warn ( "Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}" ,
deviceSessionCtx . getDeviceId ( ) , context . getMessageQueueSizePerDeviceLimit ( ) , queueSize , deviceSessionCtx . getMsgQueue ( ) . s ize( ) ) ;
final int queueSize = deviceSessionCtx . getMsgQueueSize ( ) ;
if ( queueSize > = context . getMessageQueueSizePerDeviceLimit ( ) ) {
log . info ( "Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}" ,
deviceSessionCtx . getDeviceId ( ) , context . getMessageQueueSizePerDeviceLimit ( ) , queueSize , deviceSessionCtx . getMsgQueueS ize ( ) ) ;
ctx . close ( ) ;
return ;
}
deviceSessionCtx . getMsgQueue ( ) . add ( msg ) ;
ReferenceCountUtil . retain ( msg ) ;
deviceSessionCtx . addToQueue ( msg ) ;
processMsgQueue ( ctx ) ; //Under the normal conditions the msg queue will contain 0 messages. Many messages will be processed on device connect event in separate thread pool
}
void processMsgQueue ( ChannelHandlerContext ctx ) {
if ( ! deviceSessionCtx . isConnected ( ) ) {
log . trace ( "[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}" , sessionId , deviceSessionCtx . getDeviceId ( ) , deviceSessionCtx . getMsgQueue ( ) . s ize( ) ) ;
log . trace ( "[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}" , sessionId , deviceSessionCtx . getDeviceId ( ) , deviceSessionCtx . getMsgQueueS ize ( ) ) ;
return ;
}
while ( ! deviceSessionCtx . getMsgQueue ( ) . isEmpty ( ) ) {
if ( deviceSessionCtx . getMsgQueueProcessorLock ( ) . tryLock ( ) ) {
try {
MqttMessage msg ;
while ( ( msg = deviceSessionCtx . getMsgQueue ( ) . poll ( ) ) ! = null ) {
deviceSessionCtx . getMsgQueueSize ( ) . decrementAndGet ( ) ;
processRegularSessionMsg ( ctx , msg ) ;
ReferenceCountUtil . safeRelease ( msg ) ;
}
} finally {
deviceSessionCtx . getMsgQueueProcessorLock ( ) . unlock ( ) ;
}
} else {
return ;
}
}
deviceSessionCtx . tryProcessQueuedMsgs ( msg - > processRegularSessionMsg ( ctx , msg ) ) ;
}
void processRegularSessionMsg ( ChannelHandlerContext ctx , MqttMessage msg ) {
@ -282,9 +266,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
break ;
case DISCONNECT :
if ( checkConnected ( ctx , msg ) ) {
processDisconnect ( ctx ) ;
}
ctx . close ( ) ;
break ;
case PUBACK :
int msgId = ( ( MqttPubAckMessage ) msg ) . variableHeader ( ) . messageId ( ) ;
@ -438,7 +420,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void onError ( Throwable e ) {
log . trace ( "[{}] Failed to publish msg: {}" , sessionId , msg , e ) ;
processDisconnect ( ctx ) ;
ctx . close ( ) ;
}
} ;
}
@ -464,7 +446,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
} else {
deviceSessionCtx . getContext ( ) . getProtoMqttAdaptor ( ) . convertToPublish ( deviceSessionCtx , provisionResponseMsg ) . ifPresent ( deviceSessionCtx . getChannel ( ) : : writeAndFlush ) ;
}
scheduler . schedule ( ( ) - > processDisconnect ( ctx ) , 60 , TimeUnit . SECONDS ) ;
scheduler . schedule ( ( Callable < ChannelFuture > ) ctx : : close , 60 , TimeUnit . SECONDS ) ;
} catch ( Exception e ) {
log . trace ( "[{}] Failed to convert device attributes response to MQTT msg" , sessionId , e ) ;
}
@ -473,7 +455,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void onError ( Throwable e ) {
log . trace ( "[{}] Failed to publish msg: {}" , sessionId , msg , e ) ;
processDisconnect ( ctx ) ;
ctx . close ( ) ;
}
}
@ -508,7 +490,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void onError ( Throwable e ) {
log . trace ( "[{}] Failed to get firmware: {}" , sessionId , msg , e ) ;
processDisconnect ( ctx ) ;
ctx . close ( ) ;
}
}
@ -530,7 +512,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
deviceSessionCtx . getChannel ( ) . writeAndFlush ( deviceSessionCtx
. getPayloadAdaptor ( )
. createMqttPublishMsg ( deviceSessionCtx , MqttTopics . DEVICE_FIRMWARE_ERROR_TOPIC , error . getBytes ( ) ) ) ;
processDisconnect ( ctx ) ;
ctx . close ( ) ;
}
private void processSubscribe ( ChannelHandlerContext ctx , MqttSubscribeMessage mqttMsg ) {
@ -699,6 +681,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
} ) ;
} catch ( Exception e ) {
ctx . writeAndFlush ( createMqttConnAckMsg ( CONNECTION_REFUSED_NOT_AUTHORIZED , connectMessage ) ) ;
log . trace ( "[{}] X509 auth failure: {}" , sessionId , address , e ) ;
ctx . close ( ) ;
}
}
@ -716,12 +699,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
return null ;
}
void processDisconnect ( ChannelHandlerContext ctx ) {
ctx . close ( ) ;
log . info ( "[{}] Client disconnected!" , sessionId ) ;
doDisconnect ( ) ;
}
private MqttConnAckMessage createMqttConnAckMsg ( MqttConnectReturnCode returnCode , MqttConnectMessage msg ) {
MqttFixedHeader mqttFixedHeader =
new MqttFixedHeader ( CONNACK , false , AT_MOST_ONCE , false , 0 ) ;
@ -766,7 +743,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
return true ;
} else {
log . info ( "[{}] Closing current session due to invalid msg order: {}" , sessionId , msg ) ;
ctx . close ( ) ;
return false ;
}
}
@ -791,11 +767,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void operationComplete ( Future < ? super Void > future ) throws Exception {
log . trace ( "[{}] Channel closed!" , sessionId ) ;
doDisconnect ( ) ;
}
private void doDisconnect ( ) {
public void doDisconnect ( ) {
if ( deviceSessionCtx . isConnected ( ) ) {
log . info ( "[{}] Client disconnected!" , sessionId ) ;
transportService . process ( deviceSessionCtx . getSessionInfo ( ) , DefaultTransportService . getSessionEventMsg ( SessionEvent . CLOSED ) , null ) ;
transportService . deregisterSession ( deviceSessionCtx . getSessionInfo ( ) ) ;
if ( gatewaySessionHandler ! = null ) {
@ -803,11 +781,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
deviceSessionCtx . setDisconnected ( ) ;
}
if ( ! deviceSessionCtx . getMsgQueue ( ) . isEmpty ( ) ) {
log . warn ( "doDisconnect for device {} but unprocessed messages {} left in the msg queue" , deviceSessionCtx . getDeviceId ( ) , deviceSessionCtx . getMsgQueue ( ) . size ( ) ) ;
deviceSessionCtx . getMsgQueue ( ) . clear ( ) ;
}
deviceSessionCtx . release ( ) ;
}
@ -866,7 +840,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void onRemoteSessionCloseCommand ( UUID sessionId , TransportProtos . SessionCloseNotificationProto sessionCloseNotification ) {
log . trace ( "[{}] Received the remote command to close the session: {}" , sessionId , sessionCloseNotification . getMessage ( ) ) ;
processDisconnect ( deviceSessionCtx . getChannel ( ) ) ;
deviceSessionCtx . getChannel ( ) . close ( ) ;
}
@Override