int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { struct mosquitto_message_all *message; uint16_t local_mid; if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(strlen(topic) == 0) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(_mosquitto_topic_wildcard_len_check(topic) != MOSQ_ERR_SUCCESS) { return MOSQ_ERR_INVAL; } //获取总共发送信息数,并加1返回 local_mid = _mosquitto_mid_generate(mosq); if(mid) { *mid = local_mid; } if(qos == 0) { return _mosquitto_send_publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false); } else { message = _mosquitto_calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; message->next = NULL; message->timestamp = time(NULL); message->direction = mosq_md_out; if(qos == 1) { message->state = mosq_ms_wait_puback; } else if(qos == 2) { message->state = mosq_ms_wait_pubrec; } message->msg.mid = local_mid; message->msg.topic = _mosquitto_strdup(topic); if(!message->msg.topic) { _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } if(payloadlen) { message->msg.payloadlen = payloadlen; message->msg.payload = _mosquitto_malloc(payloadlen*sizeof(uint8_t)); if(!message->msg.payload) { _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t)); } else { message->msg.payloadlen = 0; message->msg.payload = NULL; } message->msg.qos = qos; message->msg.retain = retain; message->dup = false; _mosquitto_message_queue(mosq, message); return _mosquitto_send_publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup); } }
int mqtt3_handle_publish(struct mosquitto_db *db, struct mosquitto *context) { char *topic; void *payload = NULL; uint32_t payloadlen; uint8_t dup, qos, retain; uint16_t mid = 0; int rc = 0; uint8_t header = context->in_packet.command; int res = 0; struct mosquitto_msg_store *stored = NULL; int len; char *topic_mount; #ifdef WITH_BRIDGE char *topic_temp; int i; struct _mqtt3_bridge_topic *cur_topic; bool match; #endif dup = (header & 0x08)>>3; qos = (header & 0x06)>>1; if(qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in PUBLISH from %s, disconnecting.", context->id); return 1; } retain = (header & 0x01); if(_mosquitto_read_string(&context->in_packet, &topic)) return 1; if(strlen(topic) == 0){ /* Invalid publish topic, disconnect client. */ _mosquitto_free(topic); return 1; } if(!strlen(topic)){ _mosquitto_free(topic); return 1; } #ifdef WITH_BRIDGE if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ for(i=0; i<context->bridge->topic_count; i++){ cur_topic = &context->bridge->topics[i]; if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) && (cur_topic->remote_prefix || cur_topic->local_prefix)){ /* Topic mapping required on this topic if the message matches */ rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, topic, &match); if(rc){ _mosquitto_free(topic); return rc; } if(match){ if(cur_topic->remote_prefix){ /* This prefix needs removing. */ if(!strncmp(cur_topic->remote_prefix, topic, strlen(cur_topic->remote_prefix))){ topic_temp = _mosquitto_strdup(topic+strlen(cur_topic->remote_prefix)); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } _mosquitto_free(topic); topic = topic_temp; } } if(cur_topic->local_prefix){ /* This prefix needs adding. */ len = strlen(topic) + strlen(cur_topic->local_prefix)+1; topic_temp = _mosquitto_calloc(len+1, sizeof(char)); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); _mosquitto_free(topic); topic = topic_temp; } break; } } } } #endif if(_mosquitto_topic_wildcard_len_check(topic) != MOSQ_ERR_SUCCESS){ /* Invalid publish topic, just swallow it. */ _mosquitto_free(topic); return 1; } if(qos > 0){ if(_mosquitto_read_uint16(&context->in_packet, &mid)){ _mosquitto_free(topic); return 1; } } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; #ifdef WITH_SYS_TREE g_pub_bytes_received += payloadlen; #endif if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(topic) + 1; topic_mount = _mosquitto_calloc(len, sizeof(char)); if(!topic_mount){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); _mosquitto_free(topic); topic = topic_mount; } if(payloadlen){ if(db->config->message_size_limit && payloadlen > db->config->message_size_limit){ _mosquitto_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, mid, topic, (long)payloadlen); goto process_bad_message; } payload = _mosquitto_calloc(payloadlen+1, sizeof(uint8_t)); if(!payload){ _mosquitto_free(topic); return 1; } if(_mosquitto_read_bytes(&context->in_packet, payload, payloadlen)){ _mosquitto_free(topic); _mosquitto_free(payload); return 1; } } /* Check for topic access */ rc = mosquitto_acl_check(db, context, topic, MOSQ_ACL_WRITE); if(rc == MOSQ_ERR_ACL_DENIED){ _mosquitto_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, mid, topic, (long)payloadlen); goto process_bad_message; }else if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; } _mosquitto_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, mid, topic, (long)payloadlen); if(qos > 0){ mqtt3_db_message_store_find(context, mid, &stored); } if(!stored){ dup = 0; if(mqtt3_db_message_store(db, context->id, mid, topic, qos, payloadlen, payload, retain, &stored, 0)){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return 1; } }else{ dup = 1; } switch(qos){ case 0: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, stored)) rc = 1; break; case 1: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, stored)) rc = 1; if(_mosquitto_send_puback(context, mid)) rc = 1; break; case 2: if(!dup){ res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, retain, stored); }else{ res = 0; } /* mqtt3_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(_mosquitto_send_pubrec(context, mid)) rc = 1; }else if(res == 1){ rc = 1; } break; } _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; process_bad_message: _mosquitto_free(topic); if(payload) _mosquitto_free(payload); switch(qos){ case 0: return MOSQ_ERR_SUCCESS; case 1: return _mosquitto_send_puback(context, mid); case 2: mqtt3_db_message_store_find(context, mid, &stored); if(!stored){ if(mqtt3_db_message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ return 1; } res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, false, stored); }else{ res = 0; } if(!res){ res = _mosquitto_send_pubrec(context, mid); } return res; } return 1; }
int mqtt3_handle_publish(struct mosquitto_db *db, struct mosquitto *context) { char *topic; void *payload = NULL; uint32_t payloadlen; uint8_t dup, qos, retain; uint16_t mid = 0; int rc = 0; uint8_t header = context->in_packet.command; int res = 0; struct mosquitto_msg_store *stored = NULL; int len; char *topic_mount; dup = (header & 0x08)>>3; qos = (header & 0x06)>>1; retain = (header & 0x01); if(_mosquitto_read_string(&context->in_packet, &topic)) return 1;//读取TOPIC if(strlen(topic) == 0){ /* Invalid publish topic, disconnect client. */ _mosquitto_free(topic); return 1; } if(_mosquitto_fix_sub_topic(&topic)){//去掉topic上面多余的斜杠 _mosquitto_free(topic); return 1; } if(!strlen(topic)){ _mosquitto_free(topic); return 1; } //检查topic中是否有通配符,不允许publish到通配符地址 if(_mosquitto_topic_wildcard_len_check(topic) != MOSQ_ERR_SUCCESS){ /* Invalid publish topic, just swallow it. */ _mosquitto_free(topic); return 1; } if(qos > 0){ if(_mosquitto_read_uint16(&context->in_packet, &mid)){ _mosquitto_free(topic); return 1; } } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; #ifdef WITH_SYS_TREE g_pub_bytes_received += payloadlen; #endif if(context->listener && context->listener->mount_point){//追加一个配置的前缀 len = strlen(context->listener->mount_point) + strlen(topic) + 1; topic_mount = _mosquitto_calloc(len, sizeof(char)); if(!topic_mount){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); _mosquitto_free(topic); topic = topic_mount; } if(payloadlen){//有数据部分,不是空,检查一下消息大小是否不合格, if(db->config->message_size_limit && payloadlen > db->config->message_size_limit){ _mosquitto_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, mid, topic, (long)payloadlen); goto process_bad_message; } //读消息体 payload = _mosquitto_calloc(payloadlen+1, sizeof(uint8_t)); if(_mosquitto_read_bytes(&context->in_packet, payload, payloadlen)){ _mosquitto_free(topic); return 1; } } /* Check for topic access */ rc = mosquitto_acl_check(db, context, topic, MOSQ_ACL_WRITE); if(rc == MOSQ_ERR_ACL_DENIED){ _mosquitto_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, mid, topic, (long)payloadlen); goto process_bad_message; }else if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; } _mosquitto_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, mid, topic, (long)payloadlen); if(qos > 0){//检查这个用户是否曾经发过这条消息,QOS大于0的消息ID只能出现一次 mqtt3_db_message_store_find(context, mid, &stored); } if(!stored){ dup = 0;//创建一个mosquitto_msg_store结构,放到db->msg_store的头部,结构里面存储了这条消息的所有信息 if(mqtt3_db_message_store(db, context->id, mid, topic, qos, payloadlen, payload, retain, &stored, 0)){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return 1; } }else{ dup = 1; } switch(qos){ case 0: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, stored)) rc = 1; break; case 1: //1级消息可以立即发布出去 if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, stored)) rc = 1; //发送回包 if(_mosquitto_send_puback(context, mid)) rc = 1; break; case 2: if(!dup){ //对于2级的消息,不能立即发布,得跟客户端协商后才行。文档: //Log the message to persistent storage, do not make it available to interested //parties yet, and return a PUBREC message to the sender. //将一条消息插入到context->msg链表后面,设置相关的状态。然后记录这条消息给哪些人发送过等 res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, retain, stored); }else{ res = 0; } /* mqtt3_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(_mosquitto_send_pubrec(context, mid)) rc = 1; }else if(res == 1){ rc = 1; } break; } _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; process_bad_message: if(topic) _mosquitto_free(topic); if(payload) _mosquitto_free(payload); switch(qos){ case 0: return MOSQ_ERR_SUCCESS; case 1: return _mosquitto_send_puback(context, mid); case 2: mqtt3_db_message_store_find(context, mid, &stored); if(!stored){ if(mqtt3_db_message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ return 1; } res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, false, stored); }else{ res = 0; } if(!res){ res = _mosquitto_send_pubrec(context, mid); } return res; } return 1; }