@ -34,22 +34,18 @@ Contributors:
int handle__publish ( struct mosquitto_db * db , struct mosquitto * context )
{
char * topic ;
mosquitto__payload_uhpa payload ;
uint32_t payloadlen ;
uint8_t dup , qos , retain ;
uint16_t mid = 0 ;
uint8_t dup ;
int rc = 0 ;
int rc2 ;
uint8_t header = context - > in_packet . command ;
int res = 0 ;
struct mosquitto_msg_store * stored = NULL ;
struct mosquitto_msg_store * msg, * stored = NULL ;
int len ;
int slen ;
char * topic_mount ;
mosquitto_property * properties = NULL ;
mosquitto_property * p , * p_prev ;
mosquitto_property * msg_properties = NULL , * msg_properties _last;
mosquitto_property * msg_properties _last;
uint32_t message_expiry_interval = 0 ;
int topic_alias = - 1 ;
uint8_t reason_code = 0 ;
@ -58,43 +54,53 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
return MOSQ_ERR_PROTOCOL ;
}
payload . ptr = NULL ;
msg = mosquitto__calloc ( 1 , sizeof ( struct mosquitto_msg_store ) ) ;
if ( msg = = NULL ) {
return MOSQ_ERR_NOMEM ;
}
msg - > ref_count = 1 ;
dup = ( header & 0x08 ) > > 3 ;
qos = ( header & 0x06 ) > > 1 ;
if ( qos = = 3 ) {
msg- > qos = ( header & 0x06 ) > > 1 ;
if ( msg- > qos = = 3 ) {
log__printf ( NULL , MOSQ_LOG_INFO ,
" Invalid QoS in PUBLISH from %s, disconnecting. " , context - > id ) ;
db__msg_store_free ( msg ) ;
return 1 ;
}
if ( qos > context - > maximum_qos ) {
if ( msg- > qos > context - > maximum_qos ) {
log__printf ( NULL , MOSQ_LOG_INFO ,
" Too high QoS in PUBLISH from %s, disconnecting. " , context - > id ) ;
db__msg_store_free ( msg ) ;
return 1 ;
}
retain = ( header & 0x01 ) ;
msg- > retain = ( header & 0x01 ) ;
if ( retain & & db - > config - > retain_available = = false ) {
if ( msg- > retain & & db - > config - > retain_available = = false ) {
if ( context - > protocol = = mosq_p_mqtt5 ) {
send__disconnect ( context , MQTT_RC_RETAIN_NOT_SUPPORTED , NULL ) ;
}
db__msg_store_free ( msg ) ;
return 1 ;
}
if ( packet__read_string ( & context - > in_packet , & topic , & slen ) ) return 1 ;
if ( packet__read_string ( & context - > in_packet , & msg - > topic , & slen ) ) {
db__msg_store_free ( msg ) ;
return 1 ;
}
if ( ! slen & & context - > protocol ! = mosq_p_mqtt5 ) {
/* Invalid publish topic, disconnect client. */
mosquitto__free ( topic ) ;
db__msg_store_free( msg ) ;
return 1 ;
}
if ( qos > 0 ) {
if ( packet__read_uint16 ( & context - > in_packet , & m id) ) {
mosquitto__free( topic ) ;
if ( msg- > qos > 0 ) {
if ( packet__read_uint16 ( & context - > in_packet , & m sg- > source_m id) ) {
db__msg_store_free( msg ) ;
return 1 ;
}
if ( m id = = 0 ) {
mosquitto__free( topic ) ;
if ( m sg- > source_m id = = 0 ) {
db__msg_store_free( msg ) ;
return MOSQ_ERR_PROTOCOL ;
}
}
@ -102,11 +108,14 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
/* Handle properties */
if ( context - > protocol = = mosq_p_mqtt5 ) {
rc = property__read_all ( CMD_PUBLISH , & context - > in_packet , & properties ) ;
if ( rc ) return rc ;
if ( rc ) {
db__msg_store_free ( msg ) ;
return rc ;
}
p = properties ;
p_prev = NULL ;
msg _ properties = NULL ;
msg - > properties = NULL ;
msg_properties_last = NULL ;
while ( p ) {
switch ( p - > identifier ) {
@ -115,11 +124,11 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR :
case MQTT_PROP_RESPONSE_TOPIC :
case MQTT_PROP_USER_PROPERTY :
if ( msg _ properties) {
if ( msg - > properties) {
msg_properties_last - > next = p ;
msg_properties_last = p ;
} else {
msg _ properties = p ;
msg - > properties = p ;
msg_properties_last = p ;
}
if ( p_prev ) {
@ -158,132 +167,127 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
mosquitto_property_free_all ( & properties ) ;
if ( topic_alias = = 0 | | ( context - > listener & & topic_alias > context - > listener - > max_topic_alias ) ) {
mosquitto__free( topic ) ;
db__msg_store_free( msg ) ;
send__disconnect ( context , MQTT_RC_TOPIC_ALIAS_INVALID , NULL ) ;
return MOSQ_ERR_PROTOCOL ;
} else if ( topic_alias > 0 ) {
if ( topic) {
rc = alias__add ( context , topic, topic_alias ) ;
if ( msg- > topic) {
rc = alias__add ( context , msg- > topic, topic_alias ) ;
if ( rc ) {
mosquitto__free( topic ) ;
db__msg_store_free( msg ) ;
return rc ;
}
} else {
rc = alias__find ( context , & topic, topic_alias ) ;
rc = alias__find ( context , & msg- > topic, topic_alias ) ;
if ( rc ) {
send__disconnect ( context , MQTT_RC_TOPIC_ALIAS_INVALID , NULL ) ;
mosquitto__free( topic ) ;
db__msg_store_free( msg ) ;
return rc ;
}
}
}
# ifdef WITH_BRIDGE
rc = bridge__remap_topic_in ( context , & topic ) ;
if ( rc ) return rc ;
rc = bridge__remap_topic_in ( context , & msg - > topic ) ;
if ( rc ) {
db__msg_store_free ( msg ) ;
return rc ;
}
# endif
if ( mosquitto_pub_topic_check ( topic ) ! = MOSQ_ERR_SUCCESS ) {
if ( mosquitto_pub_topic_check ( msg- > topic) ! = MOSQ_ERR_SUCCESS ) {
/* Invalid publish topic, just swallow it. */
mosquitto__free( topic ) ;
db__msg_store_free( msg ) ;
return 1 ;
}
payloadlen = context - > in_packet . remaining_length - context - > in_packet . pos ;
G_PUB_BYTES_RECEIVED_INC ( payloadlen) ;
msg- > payloadlen = context - > in_packet . remaining_length - context - > in_packet . pos ;
G_PUB_BYTES_RECEIVED_INC ( msg- > payloadlen) ;
if ( context - > listener & & context - > listener - > mount_point ) {
len = strlen ( context - > listener - > mount_point ) + strlen ( topic) + 1 ;
len = strlen ( context - > listener - > mount_point ) + strlen ( msg- > topic) + 1 ;
topic_mount = mosquitto__malloc ( len + 1 ) ;
if ( ! topic_mount ) {
mosquitto__free ( topic ) ;
mosquitto_property_free_all ( & msg_properties ) ;
db__msg_store_free ( msg ) ;
return MOSQ_ERR_NOMEM ;
}
snprintf ( topic_mount , len , " %s%s " , context - > listener - > mount_point , topic) ;
snprintf ( topic_mount , len , " %s%s " , context - > listener - > mount_point , msg- > topic) ;
topic_mount [ len ] = ' \0 ' ;
mosquitto__free ( topic) ;
topic = topic_mount ;
mosquitto__free ( msg- > topic) ;
msg- > topic = topic_mount ;
}
if ( payloadlen) {
if ( db - > config - > message_size_limit & & payloadlen > db - > config - > message_size_limit ) {
log__printf ( NULL , MOSQ_LOG_DEBUG , " Dropped too large PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , qos, retain, m id, topic, ( long ) payloadlen ) ;
if ( msg- > payloadlen) {
if ( db - > config - > message_size_limit & & msg- > payloadlen > db - > config - > message_size_limit ) {
log__printf ( NULL , MOSQ_LOG_DEBUG , " Dropped too large PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , msg- > qos, msg- > retain, m sg- > source_m id, msg- > topic, ( long ) msg - > payloadlen ) ;
reason_code = MQTT_RC_IMPLEMENTATION_SPECIFIC ;
goto process_bad_message ;
}
if ( UHPA_ALLOC ( payload , payloadlen ) = = 0 ) {
mosquitto__free ( topic ) ;
mosquitto_property_free_all ( & msg_properties ) ;
if ( UHPA_ALLOC ( msg - > payload , msg - > payloadlen ) = = 0 ) {
db__msg_store_free ( msg ) ;
return MOSQ_ERR_NOMEM ;
}
if ( packet__read_bytes ( & context - > in_packet , UHPA_ACCESS ( payload , payloadlen ) , payloadlen ) ) {
mosquitto__free ( topic ) ;
UHPA_FREE ( payload , payloadlen ) ;
mosquitto_property_free_all ( & msg_properties ) ;
return 1 ;
if ( packet__read_bytes ( & context - > in_packet , UHPA_ACCESS ( msg - > payload , msg - > payloadlen ) , msg - > payloadlen ) ) {
db__msg_store_free ( msg ) ;
return MOSQ_ERR_UNKNOWN ;
}
}
/* Check for topic access */
rc = mosquitto_acl_check ( db , context , topic, payloadlen, UHPA_ACCESS ( payload , payloadlen) , qos, retain , MOSQ_ACL_WRITE ) ;
rc = mosquitto_acl_check ( db , context , msg- > topic, msg- > payloadlen, UHPA_ACCESS ( msg - > payload , msg- > payloadlen) , msg- > qos, msg - > retain , MOSQ_ACL_WRITE ) ;
if ( rc = = MOSQ_ERR_ACL_DENIED ) {
log__printf ( NULL , MOSQ_LOG_DEBUG , " Denied PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , qos, retain, m id, topic, ( long ) payloadlen ) ;
log__printf ( NULL , MOSQ_LOG_DEBUG , " Denied PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , msg- > qos, msg- > retain, m sg- > source_m id, msg- > topic, ( long ) msg - > payloadlen ) ;
reason_code = MQTT_RC_NOT_AUTHORIZED ;
goto process_bad_message ;
} else if ( rc ! = MOSQ_ERR_SUCCESS ) {
mosquitto__free ( topic ) ;
UHPA_FREE ( payload , payloadlen ) ;
mosquitto_property_free_all ( & msg_properties ) ;
db__msg_store_free ( msg ) ;
return rc ;
}
log__printf ( NULL , MOSQ_LOG_DEBUG , " Received PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , qos, retain, m id, topic, ( long ) payloadlen ) ;
if ( qos > 0 ) {
db__message_store_find ( context , m id, & stored ) ;
log__printf ( NULL , MOSQ_LOG_DEBUG , " Received PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) " , context - > id , dup , msg- > qos, msg- > retain, m sg- > source_m id, msg- > topic, ( long ) msg - > payloadlen ) ;
if ( msg- > qos > 0 ) {
db__message_store_find ( context , m sg- > source_m id, & stored ) ;
}
if ( ! stored ) {
dup = 0 ;
if ( db__message_store ( db , context , mid , topic , qos , payloadlen , & payload , retain , & stored , message_expiry_interval , msg_properties , 0 , mosq_mo_client ) ) {
mosquitto_property_free_all ( & msg_properties ) ;
if ( db__message_store ( db , context , msg , message_expiry_interval , 0 , mosq_mo_client ) ) {
return 1 ;
}
msg_properties = NULL ; /* Now belongs to db__message_store() */
stored = msg ;
msg = NULL ;
} else {
mosquitto__free( topic ) ;
topic = stored - > topic ;
db__msg_store_free( msg ) ;
msg = NULL ;
dup = 1 ;
mosquitto_property_free_all ( & msg_properties ) ;
UHPA_FREE ( payload , payloadlen ) ;
}
switch ( qos) {
switch ( stored- > qos) {
case 0 :
rc2 = sub__messages_queue ( db , context - > id , topic, qos, retain , & stored ) ;
rc2 = sub__messages_queue ( db , context - > id , stored- > topic, stored- > qos, stored - > retain , & stored ) ;
if ( rc2 > 0 ) rc = 1 ;
break ;
case 1 :
util__decrement_receive_quota ( context ) ;
rc2 = sub__messages_queue ( db , context - > id , topic, qos, retain , & stored ) ;
rc2 = sub__messages_queue ( db , context - > id , stored- > topic, stored- > qos, stored - > retain , & stored ) ;
if ( rc2 = = MOSQ_ERR_SUCCESS | | context - > protocol ! = mosq_p_mqtt5 ) {
if ( send__puback ( context , mid, 0 , NULL ) ) rc = 1 ;
if ( send__puback ( context , stored- > source_ mid, 0 , NULL ) ) rc = 1 ;
} else if ( rc2 = = MOSQ_ERR_NO_SUBSCRIBERS ) {
if ( send__puback ( context , mid, MQTT_RC_NO_MATCHING_SUBSCRIBERS , NULL ) ) rc = 1 ;
if ( send__puback ( context , stored- > source_ mid, MQTT_RC_NO_MATCHING_SUBSCRIBERS , NULL ) ) rc = 1 ;
} else {
rc = rc2 ;
}
break ;
case 2 :
if ( dup = = 0 ) {
res = db__message_insert ( db , context , mid, mosq_md_in , qos, retain , stored , NULL ) ;
res = db__message_insert ( db , context , stored- > source_ mid, mosq_md_in , stored- > qos, stored - > retain , stored , NULL ) ;
} else {
res = 0 ;
}
/* db__message_insert() returns 2 to indicate dropped message
* due to queue . This isn ' t an error so don ' t disconnect them . */
if ( ! res ) {
if ( send__pubrec ( context , mid, 0 , NULL ) ) rc = 1 ;
if ( send__pubrec ( context , stored- > source_ mid, 0 , NULL ) ) rc = 1 ;
} else if ( res = = 1 ) {
rc = 1 ;
}
@ -292,20 +296,25 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context)
return rc ;
process_bad_message :
mosquitto__free ( topic ) ;
UHPA_FREE ( payload , payloadlen ) ;
switch ( qos ) {
case 0 :
return MOSQ_ERR_SUCCESS ;
case 1 :
return send__puback ( context , mid , reason_code , NULL ) ;
case 2 :
if ( context - > protocol = = mosq_p_mqtt5 ) {
return send__pubrec ( context , mid , reason_code , NULL ) ;
} else {
return send__pubrec ( context , mid , 0 , NULL ) ;
}
rc = 1 ;
if ( msg ) {
switch ( msg - > qos ) {
case 0 :
rc = MOSQ_ERR_SUCCESS ;
break ;
case 1 :
rc = send__puback ( context , msg - > source_mid , reason_code , NULL ) ;
break ;
case 2 :
if ( context - > protocol = = mosq_p_mqtt5 ) {
rc = send__pubrec ( context , msg - > source_mid , reason_code , NULL ) ;
} else {
rc = send__pubrec ( context , msg - > source_mid , 0 , NULL ) ;
}
break ;
}
db__msg_store_free ( msg ) ;
}
return 1 ;
return rc ;
}