int send__connack(struct mosquitto_db *db, struct mosquitto *context, int ack, int reason_code, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; int rc; mosquitto_property *connack_props = NULL; int proplen, varbytes; uint32_t remaining_length; rc = mosquitto_property_copy_all(&connack_props, properties); if(rc){ return rc; } if(context->id){ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->id, ack, reason_code); }else{ log__printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d, %d)", context->address, ack, reason_code); } remaining_length = 2; if(context->protocol == mosq_p_mqtt5){ if(reason_code < 128 && db->config->retain_available == false){ rc = mosquitto_property_add_byte(&connack_props, MQTT_PROP_RETAIN_AVAILABLE, 0); if(rc){ mosquitto_property_free_all(&connack_props); return rc; } } if(db->config->max_packet_size > 0){ rc = mosquitto_property_add_int32(&connack_props, MQTT_PROP_MAXIMUM_PACKET_SIZE, db->config->max_packet_size); if(rc){ mosquitto_property_free_all(&connack_props); return rc; } } proplen = property__get_length_all(connack_props); varbytes = packet__varint_bytes(proplen); remaining_length += proplen + varbytes; } if(packet__check_oversize(context, remaining_length)){ mosquitto_property_free_all(&connack_props); mosquitto__free(packet); return MOSQ_ERR_OVERSIZE_PACKET; } packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = CMD_CONNACK; packet->remaining_length = remaining_length; rc = packet__alloc(packet); if(rc){ mosquitto_property_free_all(&connack_props); mosquitto__free(packet); return rc; } packet__write_byte(packet, ack); packet__write_byte(packet, reason_code); if(context->protocol == mosq_p_mqtt5){ property__write_all(packet, connack_props, true); } mosquitto_property_free_all(&connack_props); return packet__queue(context, packet); }
int send__unsubscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, const mosquitto_property *properties) { /* FIXME - only deals with a single topic */ struct mosquitto__packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; int proplen, varbytes; int i; assert(mosq); assert(topic); packet = mosquitto__calloc(1, sizeof(struct mosquitto__packet)); if(!packet) return MOSQ_ERR_NOMEM; packetlen = 2; for(i=0; i<topic_count; i++){ packetlen += 2+strlen(topic[i]); } if(mosq->protocol == mosq_p_mqtt5){ proplen = property__get_length_all(properties); varbytes = packet__varint_bytes(proplen); packetlen += proplen + varbytes; } packet->command = CMD_UNSUBSCRIBE | (1<<1); packet->remaining_length = packetlen; rc = packet__alloc(packet); if(rc){ mosquitto__free(packet); return rc; } /* Variable header */ local_mid = mosquitto__mid_generate(mosq); if(mid) *mid = (int)local_mid; packet__write_uint16(packet, local_mid); if(mosq->protocol == mosq_p_mqtt5){ /* We don't use User Property yet. */ property__write_all(packet, properties, true); } /* Payload */ for(i=0; i<topic_count; i++){ packet__write_string(packet, topic[i], strlen(topic[i])); } #ifdef WITH_BROKER # ifdef WITH_BRIDGE for(i=0; i<topic_count; i++){ log__printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic[i]); } # endif #else for(i=0; i<topic_count; i++){ log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending UNSUBSCRIBE (Mid: %d, Topic: %s)", mosq->id, local_mid, topic[i]); } #endif return packet__queue(mosq, packet); }
int bridge__connect(struct mosquitto_db *db, struct mosquitto *context) { int rc, rc2; int i; char *notification_topic; int notification_topic_len; uint8_t notification_payload; if(!context || !context->bridge) return MOSQ_ERR_INVAL; context->state = mosq_cs_new; context->sock = INVALID_SOCKET; context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + context->bridge->keepalive; context->keepalive = context->bridge->keepalive; context->clean_session = context->bridge->clean_session; context->in_packet.payload = NULL; context->ping_t = 0; context->bridge->lazy_reconnect = false; bridge__packet_cleanup(context); db__message_reconnect_reset(db, context); if(context->clean_session){ db__messages_delete(db, context); } /* Delete all local subscriptions even for clean_session==false. We don't * remove any messages and the next loop carries out the resubscription * anyway. This means any unwanted subs will be removed. */ sub__clean_session(db, context); for(i=0; i<context->bridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ log__printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); if(sub__add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; } } if(context->bridge->notifications){ if(context->bridge->notification_topic){ if(!context->bridge->initial_notification_done){ notification_payload = '0'; db__messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } if (!context->bridge->notifications_local_only) { notification_payload = '0'; rc = will__set(context, context->bridge->notification_topic, 1, ¬ification_payload, 1, true); if(rc != MOSQ_ERR_SUCCESS){ return rc; } } }else{ notification_topic_len = strlen(context->bridge->remote_clientid)+strlen("$SYS/broker/connection//state"); notification_topic = mosquitto__malloc(sizeof(char)*(notification_topic_len+1)); if(!notification_topic) return MOSQ_ERR_NOMEM; snprintf(notification_topic, notification_topic_len+1, "$SYS/broker/connection/%s/state", context->bridge->remote_clientid); if(!context->bridge->initial_notification_done){ notification_payload = '0'; db__messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } if (!context->bridge->notifications_local_only) { notification_payload = '0'; rc = will__set(context, notification_topic, 1, ¬ification_payload, 1, true); mosquitto__free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; } } } } log__printf(NULL, MOSQ_LOG_NOTICE, "Connecting bridge %s (%s:%d)", context->bridge->name, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port); rc = net__socket_connect(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, false); if(rc > 0){ if(rc == MOSQ_ERR_TLS){ net__socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; }else if(rc == MOSQ_ERR_CONN_PENDING){ context->state = mosq_cs_connect_pending; } HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); rc2 = send__connect(context, context->keepalive, context->clean_session); if(rc2 == MOSQ_ERR_SUCCESS){ return rc; }else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc2 == MOSQ_ERR_TLS){ return rc2; /* Error already printed */ }else if(rc2 == MOSQ_ERR_ERRNO){ log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc2 == MOSQ_ERR_EAI){ log__printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } net__socket_close(db, context); return rc2; } }
int handle__unsubscribe(struct mosquitto_db *db, struct mosquitto *context) { uint16_t mid; char *sub; int slen; int rc; uint8_t reason; int reason_code_count = 0; int reason_code_max; uint8_t *reason_codes = NULL, *reason_tmp; mosquitto_property *properties = NULL; if(!context) return MOSQ_ERR_INVAL; if(context->state != mosq_cs_connected){ return MOSQ_ERR_PROTOCOL; } log__printf(NULL, MOSQ_LOG_DEBUG, "Received UNSUBSCRIBE from %s", context->id); if(context->protocol != mosq_p_mqtt31){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } if(packet__read_uint16(&context->in_packet, &mid)) return 1; if(mid == 0) return MOSQ_ERR_PROTOCOL; if(context->protocol == mosq_p_mqtt5){ rc = property__read_all(CMD_UNSUBSCRIBE, &context->in_packet, &properties); if(rc) return rc; /* Immediately free, we don't do anything with User Property at the moment */ mosquitto_property_free_all(&properties); } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt5){ if(context->in_packet.pos == context->in_packet.remaining_length){ /* No topic specified, protocol error. */ return MOSQ_ERR_PROTOCOL; } } reason_code_max = 10; reason_codes = mosquitto__malloc(reason_code_max); if(!reason_codes){ return MOSQ_ERR_NOMEM; } while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(packet__read_string(&context->in_packet, &sub, &slen)){ return 1; } if(!slen){ log__printf(NULL, MOSQ_LOG_INFO, "Empty unsubscription string from %s, disconnecting.", context->id); mosquitto__free(sub); return 1; } if(mosquitto_sub_topic_check(sub)){ log__printf(NULL, MOSQ_LOG_INFO, "Invalid unsubscription string from %s, disconnecting.", context->id); mosquitto__free(sub); return 1; } log__printf(NULL, MOSQ_LOG_DEBUG, "\t%s", sub); rc = sub__remove(db, context, sub, db->subs, &reason); log__printf(NULL, MOSQ_LOG_UNSUBSCRIBE, "%s %s", context->id, sub); mosquitto__free(sub); if(rc) return rc; reason_codes[reason_code_count] = reason; reason_code_count++; if(reason_code_count == reason_code_max){ reason_tmp = mosquitto__realloc(reason_codes, reason_code_max*2); if(!reason_tmp){ mosquitto__free(reason_codes); return MOSQ_ERR_NOMEM; } reason_codes = reason_tmp; reason_code_max *= 2; } } #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif log__printf(NULL, MOSQ_LOG_DEBUG, "Sending UNSUBACK to %s", context->id); /* We don't use Reason String or User Property yet. */ rc = send__unsuback(context, mid, reason_code_count, reason_codes, NULL); mosquitto__free(reason_codes); return rc; }
int persist__chunk_message_store_write_v5(FILE *db_fptr, struct P_msg_store *chunk) { struct PF_header header; uint32_t payloadlen = chunk->F.payloadlen; uint16_t source_id_len = chunk->F.source_id_len; uint16_t source_username_len = chunk->F.source_username_len; uint16_t topic_len = chunk->F.topic_len; uint32_t proplen = 0; struct mosquitto__packet prop_packet; int rc; memset(&prop_packet, 0, sizeof(struct mosquitto__packet)); if(chunk->properties){ proplen = property__get_length_all(chunk->properties); proplen += packet__varint_bytes(proplen); } chunk->F.payloadlen = htonl(chunk->F.payloadlen); chunk->F.source_mid = htons(chunk->F.source_mid); chunk->F.source_id_len = htons(chunk->F.source_id_len); chunk->F.source_username_len = htons(chunk->F.source_username_len); chunk->F.topic_len = htons(chunk->F.topic_len); chunk->F.source_port = htons(chunk->F.source_port); header.chunk = htonl(DB_CHUNK_MSG_STORE); header.length = htonl(sizeof(struct PF_msg_store) + topic_len + payloadlen + source_id_len + source_username_len + proplen); write_e(db_fptr, &header, sizeof(struct PF_header)); write_e(db_fptr, &chunk->F, sizeof(struct PF_msg_store)); if(source_id_len){ write_e(db_fptr, chunk->source.id, source_id_len); } if(source_username_len){ write_e(db_fptr, chunk->source.username, source_username_len); } write_e(db_fptr, chunk->topic, topic_len); if(payloadlen){ write_e(db_fptr, UHPA_ACCESS(chunk->payload, payloadlen), (unsigned int)payloadlen); } if(chunk->properties){ if(proplen > 0){ prop_packet.remaining_length = proplen; prop_packet.packet_length = proplen; prop_packet.payload = mosquitto__malloc(proplen); if(!prop_packet.payload){ return MOSQ_ERR_NOMEM; } rc = property__write_all(&prop_packet, chunk->properties, true); if(rc) return rc; write_e(db_fptr, prop_packet.payload, proplen); mosquitto__free(prop_packet.payload); } } return MOSQ_ERR_SUCCESS; error: log__printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); mosquitto__free(prop_packet.payload); return 1; }