#include "config.h"
#include <stdio.h>
#include <string.h>
#include "mosquitto_broker_internal.h"
#include "memory_mosq.h"
#include "mqtt_protocol.h"
#include "packet_mosq.h"
#include "send_mosq.h"
#include "util_mosq.h"
int handle__connack(struct mosquitto *context)
{
int rc;
uint8_t connect_acknowledge;
uint8_t reason_code;
mosquitto_property *properties = NULL;
uint32_t maximum_packet_size;
uint8_t retain_available;
uint16_t server_keepalive;
uint8_t max_qos = 255;
if(!context){
return MOSQ_ERR_INVAL;
}
log__printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id);
if(packet__read_byte(&context->in_packet, &connect_acknowledge)) return MOSQ_ERR_MALFORMED_PACKET;
if(packet__read_byte(&context->in_packet, &reason_code)) return MOSQ_ERR_MALFORMED_PACKET;
if(context->protocol == mosq_p_mqtt5){
if(context->in_packet.remaining_length == 2 && reason_code == CONNACK_REFUSED_PROTOCOL_VERSION){
log__printf(NULL, MOSQ_LOG_NOTICE,
"Warning: Remote bridge %s does not support MQTT v5.0, reconnecting using MQTT v3.1.1.",
context->bridge->name);
context->protocol = mosq_p_mqtt311;
context->bridge->protocol_version = mosq_p_mqtt311;
return MOSQ_ERR_PROTOCOL;
}
rc = property__read_all(CMD_CONNACK, &context->in_packet, &properties);
if(rc) return rc;
mosquitto_property_read_byte(properties, MQTT_PROP_MAXIMUM_QOS,
&max_qos, false);
if(mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE,
&maximum_packet_size, false)){
if(context->maximum_packet_size == 0 || context->maximum_packet_size > maximum_packet_size){
context->maximum_packet_size = maximum_packet_size;
}
}
mosquitto_property_read_int16(properties, MQTT_PROP_RECEIVE_MAXIMUM,
&context->msgs_out.inflight_maximum, false);
context->msgs_out.inflight_quota = context->msgs_out.inflight_maximum;
if(mosquitto_property_read_byte(properties, MQTT_PROP_RETAIN_AVAILABLE,
&retain_available, false)){
if(context->retain_available){
context->retain_available = retain_available;
}
}
if(mosquitto_property_read_int16(properties, MQTT_PROP_SERVER_KEEP_ALIVE,
&server_keepalive, false)){
context->keepalive = server_keepalive;
}
mosquitto_property_free_all(&properties);
}
mosquitto_property_free_all(&properties);
if(reason_code == MQTT_RC_SUCCESS){
#ifdef WITH_BRIDGE
if(context->bridge){
rc = bridge__on_connect(context);
if(rc) return rc;
}
#endif
if(max_qos != 255){
context->max_qos = max_qos;
}
mosquitto__set_state(context, mosq_cs_active);
rc = db__message_write_queued_out(context);
if(rc) return rc;
rc = db__message_write_inflight_out_all(context);
return rc;
}else{
if(context->protocol == mosq_p_mqtt5){
switch(reason_code){
case MQTT_RC_RETAIN_NOT_SUPPORTED:
context->retain_available = 0;
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: retain not available (will retry)");
return MOSQ_ERR_CONN_LOST;
case MQTT_RC_QOS_NOT_SUPPORTED:
if(max_qos == 255){
if(context->max_qos != 0){
context->max_qos--;
}
}else{
context->max_qos = max_qos;
}
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: QoS not supported (will retry)");
return MOSQ_ERR_CONN_LOST;
default:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: %s", mosquitto_reason_string(reason_code));
return MOSQ_ERR_CONN_LOST;
}
}else{
switch(reason_code){
case CONNACK_REFUSED_PROTOCOL_VERSION:
if(context->bridge){
context->bridge->try_private_accepted = false;
}
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unacceptable protocol version");
return MOSQ_ERR_CONN_LOST;
case CONNACK_REFUSED_IDENTIFIER_REJECTED:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: identifier rejected");
return MOSQ_ERR_CONN_LOST;
case CONNACK_REFUSED_SERVER_UNAVAILABLE:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
return MOSQ_ERR_CONN_LOST;
case CONNACK_REFUSED_BAD_USERNAME_PASSWORD:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable");
return MOSQ_ERR_CONN_LOST;
case CONNACK_REFUSED_NOT_AUTHORIZED:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: not authorised");
return MOSQ_ERR_CONN_LOST;
default:
log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: unknown reason");
return MOSQ_ERR_CONN_LOST;
}
}
}
return MOSQ_ERR_CONN_LOST;
}