int mqtt3_db_messages_easy_queue(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int qos, uint32_t payloadlen, const void *payload, int retain) { struct mosquitto_msg_store *stored; char *source_id; assert(db); if(!topic) return MOSQ_ERR_INVAL; if(context){ source_id = context->id; }else{ source_id = ""; } if(mqtt3_db_message_store(db, source_id, 0, topic, qos, payloadlen, payload, retain, &stored, 0)) return 1; return mqtt3_db_messages_queue(db, source_id, topic, qos, retain, stored); }
static int _db_retain_chunk_restore(mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; struct mosquitto_msg_store *store; if(fread(&i64temp, 1, sizeof(dbid_t), db_fptr) != sizeof(dbid_t)){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); return 1; } store_id = i64temp; store = db->msg_store; while(store){ if(store->db_id == store_id){ mqtt3_db_messages_queue(db, NULL, store->msg.topic, store->msg.qos, store->msg.retain, store); break; } store = store->next; } return MOSQ_ERR_SUCCESS; }
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(STREMPTY(topic)){ /* Invalid publish topic, disconnect client. */ _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_malloc(len+1); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); topic_temp[len] = '\0'; _mosquitto_free(topic); topic = topic_temp; } break; } } } } #endif if(mosquitto_pub_topic_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_malloc(len+1); if(!topic_mount){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); topic_mount[len] = '\0'; _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, 1); 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_INFO, "Received PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes) payload %s)", context->id, dup, qos, retain, mid, topic, (long)payloadlen, (char *)payload); //Prathamesh write(pipeFDS[1],payload, 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_db_message_release(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_client_msg *tail, *last = NULL; int qos; int retain; char *topic; char *source_id; int msg_index = 0; bool deleted = false; if(!context) return MOSQ_ERR_INVAL; tail = context->msgs; while(tail){ msg_index++; if(tail->state == mosq_ms_queued && msg_index <= max_inflight){ tail->timestamp = mosquitto_time(); if(tail->direction == mosq_md_out){ switch(tail->qos){ case 0: tail->state = mosq_ms_publish_qos0; break; case 1: tail->state = mosq_ms_publish_qos1; break; case 2: tail->state = mosq_ms_publish_qos2; break; } }else{ if(tail->qos == 2){ _mosquitto_send_pubrec(context, tail->mid); tail->state = mosq_ms_wait_for_pubrel; } } } if(tail->mid == mid && tail->direction == dir){ qos = tail->store->msg.qos; topic = tail->store->msg.topic; retain = tail->retain; source_id = tail->store->source_id; /* topic==NULL should be a QoS 2 message that was * denied/dropped and is being processed so the client doesn't * keep resending it. That means we don't send it to other * clients. */ if(!topic || !mqtt3_db_messages_queue(db, source_id, topic, qos, retain, tail->store)){ _message_remove(context, &tail, last); deleted = true; }else{ return 1; } }else{ last = tail; tail = tail->next; } if(msg_index > max_inflight && deleted){ return MOSQ_ERR_SUCCESS; } } if(deleted){ return MOSQ_ERR_SUCCESS; }else{ 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; }