static char *client_id_gen(struct mosquitto_db *db) { char *client_id; #ifdef WITH_UUID uuid_t uuid; #else int i; #endif #ifdef WITH_UUID client_id = (char *)_mosquitto_calloc(37 + db->config->auto_id_prefix_len, sizeof(char)); if(!client_id){ return NULL; } if(db->config->auto_id_prefix){ memcpy(client_id, db->config->auto_id_prefix, db->config->auto_id_prefix_len); } uuid_generate_random(uuid); uuid_unparse_lower(uuid, &client_id[db->config->auto_id_prefix_len]); #else client_id = (char *)_mosquitto_calloc(65 + db->config->auto_id_prefix_len, sizeof(char)); if(!client_id){ return NULL; } if(db->config->auto_id_prefix){ memcpy(client_id, db->config->auto_id_prefix, db->config->auto_id_prefix_len); } for(i=0; i<64; i++){ client_id[i+db->config->auto_id_prefix_len] = (rand()%73)+48; } client_id[i] = '\0'; #endif return client_id; }
int mosquitto_sub_topic_tokenise(const char *subtopic, char ***topics, int *count) { int len; int hier_count = 1; int start, stop; int hier; int tlen; int i, j; if(!subtopic || !topics || !count) return MOSQ_ERR_INVAL; len = strlen(subtopic); for(i=0; i<len; i++){ if(subtopic[i] == '/'){ if(i > len-1){ /* Separator at end of line */ }else{ hier_count++; } } } (*topics) = _mosquitto_calloc(hier_count, sizeof(char *)); if(!(*topics)) return MOSQ_ERR_NOMEM; start = 0; stop = 0; hier = 0; for(i=0; i<len+1; i++){ if(subtopic[i] == '/' || subtopic[i] == '\0'){ stop = i; if(start != stop){ tlen = stop-start + 1; (*topics)[hier] = _mosquitto_calloc(tlen, sizeof(char)); if(!(*topics)[hier]){ for(i=0; i<hier_count; i++){ if((*topics)[hier]){ _mosquitto_free((*topics)[hier]); } } _mosquitto_free((*topics)); return MOSQ_ERR_NOMEM; } for(j=start; j<stop; j++){ (*topics)[hier][j-start] = subtopic[j]; } } start = i+1; hier++; } } *count = hier_count; return MOSQ_ERR_SUCCESS; }
int _mosquitto_send_connack(struct mosquitto *context, int result) {//发送一个带2个数字的CONNACK回包给客户端,告诉他连接成功 struct _mosquitto_packet *packet = NULL; int rc; if(context){ if(context->id){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d)", context->id, result); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending CONNACK to %s (%d)", context->address, result); } } packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = CONNACK; packet->remaining_length = 2; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } packet->payload[packet->pos+0] = 0; packet->payload[packet->pos+1] = result; return _mosquitto_packet_queue(context, packet); }
/* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ int _mosquitto_send_command_with_mid(struct mosquitto *mosq, uint8_t command, uint16_t mid, bool dup) { struct _mosquitto_packet *packet = NULL; int rc; assert(mosq); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = command; if(dup){ packet->command |= 8; } packet->remaining_length = 2; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } packet->payload[packet->pos+0] = MOSQ_MSB(mid); packet->payload[packet->pos+1] = MOSQ_LSB(mid); //add by lanhuaiyu for log packet->mid = mid; return _mosquitto_packet_queue(mosq, packet); }
/* Convert ////some////over/slashed///topic/etc/etc// * into some/over/slashed/topic/etc/etc */ int _mosquitto_fix_sub_topic(char **subtopic) { char *fixed = NULL; char *token; char *saveptr = NULL; assert(subtopic); assert(*subtopic); if(strlen(*subtopic) == 0) return MOSQ_ERR_SUCCESS; /* size of fixed here is +1 for the terminating 0 and +1 for the spurious / * that gets appended. */ fixed = _mosquitto_calloc(strlen(*subtopic)+2, 1); if(!fixed) return MOSQ_ERR_NOMEM; if((*subtopic)[0] == '/'){ fixed[0] = '/'; } token = strtok_r(*subtopic, "/", &saveptr); while(token){ strcat(fixed, token); strcat(fixed, "/"); token = strtok_r(NULL, "/", &saveptr); } fixed[strlen(fixed)-1] = '\0'; _mosquitto_free(*subtopic); *subtopic = fixed; return MOSQ_ERR_SUCCESS; }
struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *userdata) { struct mosquitto *mosq = NULL; int rc; if(clean_session == false && id == NULL) { errno = EINVAL; return NULL; } #ifndef WIN32 signal(SIGPIPE, SIG_IGN); #endif mosq = (struct mosquitto *)_mosquitto_calloc(1, sizeof(struct mosquitto)); if(mosq) { mosq->sock = INVALID_SOCKET; #ifdef WITH_THREADING mosq->thread_id = pthread_self(); #endif rc = mosquitto_reinitialise(mosq, id, clean_session, userdata); if(rc) { mosquitto_destroy(mosq); if(rc == MOSQ_ERR_INVAL) { errno = EINVAL; } else if(rc == MOSQ_ERR_NOMEM) { errno = ENOMEM; } return NULL; } } else { errno = ENOMEM; } return mosq; }
/* For PUBACK, PUBCOMP, PUBREC, and PUBREL */ int _mosquitto_send_command_with_mid(struct _mosquitto_core *core, uint8_t command, uint16_t mid, bool dup) { struct _mosquitto_packet *packet = NULL; int rc; assert(core); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = command; if(dup) { packet->command |= 8; } packet->remaining_length = 2; rc = _mosquitto_packet_alloc(packet); if(rc) { _mosquitto_free(packet); return rc; } packet->payload[packet->pos+0] = MOSQ_MSB(mid); packet->payload[packet->pos+1] = MOSQ_LSB(mid); _mosquitto_packet_queue(core, packet); return MOSQ_ERR_SUCCESS; }
static int _sub_add(struct mosquitto_db *db, struct mosquitto *context, int qos, struct _mosquitto_subhier *subhier, struct _sub_token *tokens) { struct _mosquitto_subhier *branch, *last = NULL; struct _mosquitto_subleaf *leaf, *last_leaf; if(!tokens){ if(context){ leaf = subhier->subs; last_leaf = NULL; while(leaf){ if(!strcmp(leaf->context->id, context->id)){ /* Client making a second subscription to same topic. Only * need to update QoS. Return -1 to indicate this to the * calling function. */ leaf->qos = qos; return -1; } last_leaf = leaf; leaf = leaf->next; } leaf = _mosquitto_malloc(sizeof(struct _mosquitto_subleaf)); if(!leaf) return MOSQ_ERR_NOMEM; leaf->next = NULL; leaf->context = context; leaf->qos = qos; if(last_leaf){ last_leaf->next = leaf; leaf->prev = last_leaf; }else{ subhier->subs = leaf; leaf->prev = NULL; } db->subscription_count++; } return MOSQ_ERR_SUCCESS; } branch = subhier->children; while(branch){ if(!strcmp(branch->topic, tokens->topic)){ return _sub_add(db, context, qos, branch, tokens->next); } last = branch; branch = branch->next; } /* Not found */ branch = _mosquitto_calloc(1, sizeof(struct _mosquitto_subhier)); if(!branch) return MOSQ_ERR_NOMEM; branch->topic = _mosquitto_strdup(tokens->topic); if(!branch->topic){ _mosquitto_free(branch); return MOSQ_ERR_NOMEM; } if(!last){ subhier->children = branch; }else{ last->next = branch; } return _sub_add(db, context, qos, branch, tokens->next); }
int _mosquitto_send_real_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) { struct _mosquitto_packet *packet = NULL; int packetlen; int rc; assert(mosq); assert(topic); packetlen = 2+strlen(topic) + payloadlen; if(qos > 0) packetlen += 2; /* For message id */ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->mid = mid; packet->command = PUBLISH | ((dup&0x1)<<3) | (qos<<1) | retain; packet->remaining_length = packetlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header (topic string) */ _mosquitto_write_string(packet, topic, strlen(topic)); if(qos > 0){ _mosquitto_write_uint16(packet, mid); } /* Payload */ if(payloadlen){ _mosquitto_write_bytes(packet, payload, payloadlen); } return _mosquitto_packet_queue(mosq, packet); }
int _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { int rc = MOSQ_ERR_SUCCESS; if(!mosq || !topic) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(payloadlen > 0 && !payload) return MOSQ_ERR_INVAL; if(mosquitto_pub_topic_check(topic)) return MOSQ_ERR_INVAL; if(mosq->will){ if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; } mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!mosq->will) return MOSQ_ERR_NOMEM; mosq->will->topic = _mosquitto_strdup(topic); if(!mosq->will->topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } mosq->will->payloadlen = payloadlen; if(mosq->will->payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } mosq->will->payload = _mosquitto_malloc(sizeof(char)*mosq->will->payloadlen); if(!mosq->will->payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } memcpy(mosq->will->payload, payload, payloadlen); } mosq->will->qos = qos; mosq->will->retain = retain; return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ if(mosq->will->topic) _mosquitto_free(mosq->will->topic); if(mosq->will->payload) _mosquitto_free(mosq->will->payload); } _mosquitto_free(mosq->will); mosq->will = NULL; return rc; }
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 _mosquitto_will_set(struct mosquitto *mosq, bool will, const char *topic, uint32_t payloadlen, const uint8_t *payload, int qos, bool retain) { int rc = MOSQ_ERR_SUCCESS; if(!mosq || (will && !topic)) return MOSQ_ERR_INVAL; if(payloadlen > 268435455) return MOSQ_ERR_PAYLOAD_SIZE; if(mosq->will){ if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; } if(will){ mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!mosq->will) return MOSQ_ERR_NOMEM; mosq->will->topic = _mosquitto_strdup(topic); if(!mosq->will->topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } mosq->will->payloadlen = payloadlen; if(mosq->will->payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } mosq->will->payload = _mosquitto_malloc(sizeof(uint8_t)*mosq->will->payloadlen); if(!mosq->will->payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } memcpy(mosq->will->payload, payload, payloadlen); } mosq->will->qos = qos; mosq->will->retain = retain; } return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ if(mosq->will->topic) _mosquitto_free(mosq->will->topic); if(mosq->will->payload) _mosquitto_free(mosq->will->payload); } _mosquitto_free(mosq->will); mosq->will = NULL; return rc; }
struct mosquitto *mqtt3_context_init(struct mosquitto_db *db, mosq_sock_t sock) { struct mosquitto *context; char address[1024]; context = _mosquitto_calloc(1, sizeof(struct mosquitto)); if(!context) return NULL; context->state = mosq_cs_new; context->sock = sock; context->last_msg_in = mosquitto_time(); context->next_msg_out = mosquitto_time() + 60; context->keepalive = 60; /* Default to 60s */ context->clean_session = true; context->disconnect_t = 0; context->id = NULL; context->last_mid = 0; context->will = NULL; context->username = NULL; context->password = NULL; context->listener = NULL; context->acl_list = NULL; /* is_bridge records whether this client is a bridge or not. This could be * done by looking at context->bridge for bridges that we create ourself, * but incoming bridges need some other way of being recorded. */ context->is_bridge = false; context->in_packet.payload = NULL; _mosquitto_packet_cleanup(&context->in_packet); context->out_packet = NULL; context->current_out_packet = NULL; context->address = NULL; if((int)sock >= 0){ if(!_mosquitto_socket_get_address(sock, address, 1024)){ context->address = _mosquitto_strdup(address); } if(!context->address){ /* getpeername and inet_ntop failed and not a bridge */ _mosquitto_free(context); return NULL; } } context->bridge = NULL; context->msgs = NULL; context->last_msg = NULL; context->msg_count = 0; context->msg_count12 = 0; #ifdef WITH_TLS context->ssl = NULL; #endif if((int)context->sock >= 0){ HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); } return context; }
static int _db_client_msg_restore(mosquitto_db *db, const char *client_id, uint16_t mid, uint8_t qos, uint8_t retain, uint8_t direction, uint8_t state, uint8_t dup, uint64_t store_id) { mosquitto_client_msg *cmsg, *tail; struct mosquitto_msg_store *store; struct mosquitto *context; cmsg = _mosquitto_calloc(1, sizeof(mosquitto_client_msg)); if(!cmsg){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } cmsg->store = NULL; cmsg->mid = mid; cmsg->qos = qos; cmsg->retain = retain; cmsg->direction = direction; cmsg->state = state; cmsg->dup = dup; store = db->msg_store; while(store){ if(store->db_id == store_id){ cmsg->store = store; cmsg->store->ref_count++; break; } store = store->next; } if(!cmsg->store){ _mosquitto_free(cmsg); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error restoring persistent database, message store corrupt."); return 1; } context = _db_find_or_add_context(db, client_id, 0); if(!context){ _mosquitto_free(cmsg); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error restoring persistent database, message store corrupt."); return 1; } if(context->msgs){ tail = context->msgs; while(tail->next){ tail = tail->next; } tail->next = cmsg; }else{ context->msgs = cmsg; } cmsg->next = NULL; return MOSQ_ERR_SUCCESS; }
static int _db_sub_chunk_restore(mosquitto_db *db, FILE *db_fptr) { uint16_t i16temp, slen; uint8_t qos; char *client_id; char *topic; int rc = 0; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); client_id = _mosquitto_calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); topic = _mosquitto_calloc(slen+1, sizeof(char)); if(!topic){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); _mosquitto_free(client_id); return MOSQ_ERR_NOMEM; } read_e(db_fptr, topic, slen); read_e(db_fptr, &qos, sizeof(uint8_t)); if(_db_restore_sub(db, client_id, topic, qos)){ rc = 1; } _mosquitto_free(client_id); _mosquitto_free(topic); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); if(db_fptr) fclose(db_fptr); return 1; }
int mqtt3_pwfile_parse(struct _mosquitto_db *db) { FILE *pwfile; struct _mosquitto_unpwd *unpwd; char buf[256]; char *username, *password; int len; if(!db || !db->config) return MOSQ_ERR_INVAL; if(!db->config->password_file) return MOSQ_ERR_SUCCESS; pwfile = fopen(db->config->password_file, "rt"); if(!pwfile) return 1; while(!feof(pwfile)){ if(fgets(buf, 256, pwfile)){ username = strtok(buf, ":"); if(username){ unpwd = _mosquitto_calloc(1, sizeof(struct _mosquitto_unpwd)); if(!unpwd) return MOSQ_ERR_NOMEM; unpwd->username = _mosquitto_strdup(username); if(!unpwd->username) return MOSQ_ERR_NOMEM; len = strlen(unpwd->username); while(unpwd->username[len-1] == 10 || unpwd->username[len-1] == 13){ unpwd->username[len-1] = '\0'; len = strlen(unpwd->username); } password = strtok(NULL, ":"); if(password){ unpwd->password = _mosquitto_strdup(password); if(!unpwd->password) return MOSQ_ERR_NOMEM; len = strlen(unpwd->password); while(unpwd->password[len-1] == 10 || unpwd->password[len-1] == 13){ unpwd->password[len-1] = '\0'; len = strlen(unpwd->password); } } unpwd->next = db->unpwd; db->unpwd = unpwd; } } } fclose(pwfile); return MOSQ_ERR_SUCCESS; }
struct mosquitto *mosquitto_new(const char *id, void *obj) { struct mosquitto *mosq = NULL; if(!id) return NULL; mosq = (struct mosquitto *)_mosquitto_calloc(1, sizeof(struct mosquitto)); if(mosq){ if(obj){ mosq->obj = obj; }else{ mosq->obj = mosq; } mosq->sock = INVALID_SOCKET; mosq->keepalive = 60; mosq->message_retry = 20; mosq->last_retry_check = 0; mosq->id = _mosquitto_strdup(id); mosq->username = NULL; mosq->password = NULL; mosq->in_packet.payload = NULL; _mosquitto_packet_cleanup(&mosq->in_packet); mosq->out_packet = NULL; mosq->last_msg_in = time(NULL); mosq->last_msg_out = time(NULL); mosq->last_mid = 0; mosq->state = mosq_cs_new; mosq->messages = NULL; mosq->will = NULL; mosq->on_connect = NULL; mosq->on_publish = NULL; mosq->on_message = NULL; mosq->on_subscribe = NULL; mosq->on_unsubscribe = NULL; mosq->log_destinations = MOSQ_LOG_NONE; mosq->log_priorities = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO; mosq->host = NULL; mosq->port = 1883; mosq->in_callback = false; #ifdef WITH_SSL mosq->ssl = NULL; #endif } return mosq; }
static int _db_client_msg_chunk_restore(mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; uint16_t i16temp, slen, mid; uint8_t qos, retain, direction, state, dup; char *client_id = NULL; int rc; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt persistent database."); fclose(db_fptr); return 1; } client_id = _mosquitto_calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; read_e(db_fptr, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); read_e(db_fptr, &direction, sizeof(uint8_t)); read_e(db_fptr, &state, sizeof(uint8_t)); read_e(db_fptr, &dup, sizeof(uint8_t)); rc = _db_client_msg_restore(db, client_id, mid, qos, retain, direction, state, dup, store_id); _mosquitto_free(client_id); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); if(db_fptr) fclose(db_fptr); if(client_id) _mosquitto_free(client_id); return 1; }
int _mosquitto_send_subscribe(struct mosquitto *mosq, int *mid, bool dup, const char *topic, uint8_t topic_qos) { /* FIXME - only deals with a single topic */ struct _mosquitto_packet *packet = NULL; uint32_t packetlen; uint16_t local_mid; int rc; assert(mosq); assert(topic); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packetlen = 2 + 2+strlen(topic) + 1; packet->command = SUBSCRIBE | (dup<<3) | (1<<1); packet->remaining_length = packetlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header */ local_mid = _mosquitto_mid_generate(mosq); if(mid) *mid = (int)local_mid; _mosquitto_write_uint16(packet, local_mid); /* Payload */ _mosquitto_write_string(packet, topic, strlen(topic)); _mosquitto_write_byte(packet, topic_qos); #ifdef WITH_BROKER # ifdef WITH_BRIDGE _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Bridge %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos); # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending SUBSCRIBE (Mid: %d, Topic: %s, QoS: %d)", mosq->id, local_mid, topic, topic_qos); #endif return _mosquitto_packet_queue(mosq, packet); }
/* For DISCONNECT, PINGREQ and PINGRESP */ int _mosquitto_send_simple_command(struct mosquitto *mosq, uint8_t command) { struct _mosquitto_packet *packet = NULL; int rc; assert(mosq); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = command; packet->remaining_length = 0; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } return _mosquitto_packet_queue(mosq, packet); }
int _mosquitto_read_string(struct _mosquitto_packet *packet, char **str) { uint16_t len; int rc; assert(packet); rc = _mosquitto_read_uint16(packet, &len); if(rc) return rc; if(packet->pos+len > packet->remaining_length) return MOSQ_ERR_PROTOCOL; *str = _mosquitto_calloc(len+1, sizeof(char)); if(*str){ memcpy(*str, &(packet->payload[packet->pos]), len); packet->pos += len; }else{ return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; }
static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) { struct _mosquitto_db *db; struct mosquitto *context; struct _mqtt3_listener *listener; char *psk_key = NULL; int len; const char *psk_hint; if(!identity) return 0; db = _mosquitto_get_db(); context = SSL_get_ex_data(ssl, tls_ex_index_context); if(!context) return 0; listener = SSL_get_ex_data(ssl, tls_ex_index_listener); if(!listener) return 0; psk_hint = listener->psk_hint; /* The hex to BN conversion results in the length halving, so we can pass * max_psk_len*2 as the max hex key here. */ psk_key = _mosquitto_calloc(1, max_psk_len*2 + 1); if(!psk_key) return 0; if(mosquitto_psk_key_get(db, psk_hint, identity, psk_key, max_psk_len*2) != MOSQ_ERR_SUCCESS){ return 0; } len = _mosquitto_hex2bin(psk_key, psk, max_psk_len); if (len < 0) return 0; if(listener->use_identity_as_username){ context->username = _mosquitto_strdup(identity); if(!context->username) return 0; } return len; }
static int _db_client_chunk_restore(mosquitto_db *db, FILE *db_fptr) { uint16_t i16temp, slen, last_mid; char *client_id = NULL; int rc = 0; struct mosquitto *context; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(!slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Corrupt persistent database."); fclose(db_fptr); return 1; } client_id = _mosquitto_calloc(slen+1, sizeof(char)); if(!client_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } read_e(db_fptr, client_id, slen); read_e(db_fptr, &i16temp, sizeof(uint16_t)); last_mid = ntohs(i16temp); context = _db_find_or_add_context(db, client_id, last_mid); if(!context) rc = 1; _mosquitto_free(client_id); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); if(db_fptr) fclose(db_fptr); if(client_id) _mosquitto_free(client_id); return 1; }
int _mosquitto_send_suback(struct mosquitto *context, uint16_t mid, uint32_t payloadlen, const void *payload) {//给当前客户端发送一个回包,内容在参数payload上面 struct _mosquitto_packet *packet = NULL; int rc; _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending SUBACK to %s", context->id); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->command = SUBACK; packet->remaining_length = 2+payloadlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } _mosquitto_write_uint16(packet, mid); if(payloadlen){ _mosquitto_write_bytes(packet, payload, payloadlen); } return _mosquitto_packet_queue(context, packet); }
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; int queue_status; if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(STREMPTY(topic)) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ return MOSQ_ERR_INVAL; } 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 = mosquitto_time(); 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; pthread_mutex_lock(&mosq->out_message_mutex); printf("================ mosquitto.c ================\n"); printf("#mosq->inflight_messages : %s\n", mosq->inflight_messages); queue_status = _mosquitto_message_queue(mosq, message, mosq_md_out); if(queue_status == 0){ if(qos == 1){ message->state = mosq_ms_wait_for_puback; }else if(qos == 2){ message->state = mosq_ms_wait_for_pubrec; } pthread_mutex_unlock(&mosq->out_message_mutex); 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); }else{ message->state = mosq_ms_invalid; pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } } }
int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_session, void *userdata) { int i; if(!mosq) return MOSQ_ERR_INVAL; if(clean_session == false && id == NULL){ return MOSQ_ERR_INVAL; } _mosquitto_destroy(mosq); memset(mosq, 0, sizeof(struct mosquitto)); if(userdata){ mosq->userdata = userdata; }else{ mosq->userdata = mosq; } mosq->protocol = mosq_p_mqtt31; mosq->sock = INVALID_SOCKET; mosq->sockpairR = INVALID_SOCKET; mosq->sockpairW = INVALID_SOCKET; mosq->keepalive = 60; mosq->message_retry = 20; mosq->last_retry_check = 0; mosq->clean_session = clean_session; if(id){ if(STREMPTY(id)){ return MOSQ_ERR_INVAL; } mosq->id = _mosquitto_strdup(id); }else{ mosq->id = (char *)_mosquitto_calloc(24, sizeof(char)); if(!mosq->id){ return MOSQ_ERR_NOMEM; } mosq->id[0] = 'm'; mosq->id[1] = 'o'; mosq->id[2] = 's'; mosq->id[3] = 'q'; mosq->id[4] = '/'; for(i=5; i<23; i++){ mosq->id[i] = (rand()%73)+48; } } mosq->in_packet.payload = NULL; _mosquitto_packet_cleanup(&mosq->in_packet); mosq->out_packet = NULL; mosq->current_out_packet = NULL; mosq->last_msg_in = mosquitto_time(); mosq->last_msg_out = mosquitto_time(); mosq->ping_t = 0; mosq->last_mid = 0; mosq->state = mosq_cs_new; mosq->in_messages = NULL; mosq->in_messages_last = NULL; mosq->out_messages = NULL; mosq->out_messages_last = NULL; mosq->max_inflight_messages = 20; mosq->will = NULL; mosq->on_connect = NULL; mosq->on_publish = NULL; mosq->on_message = NULL; mosq->on_subscribe = NULL; mosq->on_unsubscribe = NULL; mosq->host = NULL; mosq->port = 1883; mosq->in_callback = false; mosq->in_queue_len = 0; mosq->out_queue_len = 0; mosq->reconnect_delay = 1; mosq->reconnect_delay_max = 1; mosq->reconnect_exponential_backoff = false; mosq->threaded = false; #ifdef WITH_TLS mosq->ssl = NULL; mosq->tls_cert_reqs = SSL_VERIFY_PEER; mosq->tls_insecure = false; mosq->want_write = false; #endif #ifdef WITH_THREADING pthread_mutex_init(&mosq->exe_mutex, NULL); pthread_mutex_init(&mosq->callback_mutex, NULL); pthread_mutex_init(&mosq->log_callback_mutex, NULL); pthread_mutex_init(&mosq->state_mutex, NULL); pthread_mutex_init(&mosq->out_packet_mutex, NULL); pthread_mutex_init(&mosq->current_out_packet_mutex, NULL); pthread_mutex_init(&mosq->msgtime_mutex, NULL); pthread_mutex_init(&mosq->in_message_mutex, NULL); pthread_mutex_init(&mosq->out_message_mutex, NULL); pthread_mutex_init(&mosq->mid_mutex, NULL); mosq->thread_id = pthread_self(); #endif return MOSQ_ERR_SUCCESS; }
static int _db_msg_store_chunk_restore(mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; uint32_t i32temp, payloadlen; uint16_t i16temp, slen, source_mid, mid; uint8_t qos, retain, *payload = NULL; char *source_id = NULL; char *topic = NULL; int rc = 0; struct mosquitto_msg_store *stored = NULL; read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ source_id = _mosquitto_calloc(slen+1, sizeof(char)); if(!source_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(source_id, 1, slen, db_fptr) != slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); return 1; } } read_e(db_fptr, &i16temp, sizeof(uint16_t)); source_mid = ntohs(i16temp); read_e(db_fptr, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ topic = _mosquitto_calloc(slen+1, sizeof(char)); if(!topic){ fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(topic, 1, slen, db_fptr) != slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); return 1; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid msg_store chunk when restoring persistent database."); fclose(db_fptr); _mosquitto_free(source_id); return 1; } read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); read_e(db_fptr, &i32temp, sizeof(uint32_t)); payloadlen = ntohl(i32temp); if(payloadlen){ payload = _mosquitto_malloc(payloadlen); if(!payload){ fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(payload, 1, payloadlen, db_fptr) != payloadlen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_free(payload); return 1; } } rc = mqtt3_db_message_store(db, source_id, source_mid, topic, qos, payloadlen, payload, retain, &stored, store_id); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_free(payload); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); if(db_fptr) fclose(db_fptr); if(source_id) _mosquitto_free(source_id); if(topic) _mosquitto_free(topic); return 1; }
int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context) { char *protocol_name = NULL; uint8_t protocol_version; uint8_t connect_flags; char *client_id = NULL; char *will_payload = NULL, *will_topic = NULL; uint16_t will_payloadlen; struct mosquitto_message *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_session; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int i; int rc; struct _mosquitto_acl_user *acl_tail; int slen; #ifdef WITH_TLS X509 *client_cert; X509_NAME *name; X509_NAME_ENTRY *name_entry; #endif struct _clientid_index_hash *find_cih; struct _clientid_index_hash *new_cih; #ifdef WITH_SYS_TREE g_connection_count++; #endif /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){ mqtt3_context_disconnect(db, context); return MOSQ_ERR_PROTOCOL; } if(_mosquitto_read_string(&context->in_packet, &protocol_name)){ mqtt3_context_disconnect(db, context); return 1; } if(!protocol_name){ mqtt3_context_disconnect(db, context); return 3; } if(strcmp(protocol_name, PROTOCOL_NAME)){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol \"%s\" in CONNECT from %s.", protocol_name, context->address); } _mosquitto_free(protocol_name); mqtt3_context_disconnect(db, context); return MOSQ_ERR_PROTOCOL; } _mosquitto_free(protocol_name); if(_mosquitto_read_byte(&context->in_packet, &protocol_version)){ mqtt3_context_disconnect(db, context); return 1; } if((protocol_version&0x7F) != PROTOCOL_VERSION){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, CONNACK_REFUSED_PROTOCOL_VERSION); mqtt3_context_disconnect(db, context); return MOSQ_ERR_PROTOCOL; } if((protocol_version&0x80) == 0x80){ context->is_bridge = true; } if(_mosquitto_read_byte(&context->in_packet, &connect_flags)){ mqtt3_context_disconnect(db, context); return 1; } clean_session = connect_flags & 0x02; will = connect_flags & 0x04; will_qos = (connect_flags & 0x18) >> 3; will_retain = connect_flags & 0x20; password_flag = connect_flags & 0x40; username_flag = connect_flags & 0x80; if(_mosquitto_read_uint16(&context->in_packet, &(context->keepalive))){ mqtt3_context_disconnect(db, context); return 1; } if(_mosquitto_read_string(&context->in_packet, &client_id)){ mqtt3_context_disconnect(db, context); return 1; } slen = strlen(client_id); #ifdef WITH_STRICT_PROTOCOL if(slen > 23 || slen == 0){ #else if(slen == 0){ #endif _mosquitto_free(client_id); _mosquitto_send_connack(context, CONNACK_REFUSED_IDENTIFIER_REJECTED); mqtt3_context_disconnect(db, context); return 1; } /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ _mosquitto_free(client_id); _mosquitto_send_connack(context, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); return MOSQ_ERR_SUCCESS; } } if(will){ will_struct = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!will_struct){ mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &will_topic)){ mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } if(strlen(will_topic) == 0){ /* FIXME - CONNACK_REFUSED_IDENTIFIER_REJECTED not really appropriate here. */ _mosquitto_send_connack(context, CONNACK_REFUSED_IDENTIFIER_REJECTED); mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } if(_mosquitto_read_uint16(&context->in_packet, &will_payloadlen)){ mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } if(will_payloadlen > 0){ will_payload = _mosquitto_malloc(will_payloadlen); if(!will_payload){ mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } rc = _mosquitto_read_bytes(&context->in_packet, will_payload, will_payloadlen); if(rc){ mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } } } if(username_flag){ rc = _mosquitto_read_string(&context->in_packet, &username); if(rc == MOSQ_ERR_SUCCESS){ if(password_flag){ rc = _mosquitto_read_string(&context->in_packet, &password); if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else if(rc == MOSQ_ERR_PROTOCOL){ /* Password flag given, but no password. Ignore. */ password_flag = 0; } } }else if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else{ /* Username flag given, but no username. Ignore. */ username_flag = 0; } } #ifdef WITH_TLS if(context->listener->use_identity_as_username){ if(!context->ssl){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } #ifdef REAL_WITH_TLS_PSK if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } }else{ #endif /* REAL_WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } name_entry = X509_NAME_get_entry(name, i); context->username = _mosquitto_strdup((char *)ASN1_STRING_data(name_entry->value)); if(!context->username){ rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } #ifdef REAL_WITH_TLS_PSK } #endif /* REAL_WITH_TLS_PSK */ }else{ #endif /* WITH_TLS */ if(username_flag){ rc = mosquitto_unpwd_check(db, username, password); if(rc == MOSQ_ERR_AUTH){ _mosquitto_send_connack(context, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; }else if(rc == MOSQ_ERR_INVAL){ goto handle_connect_error; } context->username = username; context->password = password; username = NULL; /* Avoid free() in error: below. */ password = NULL; } if(!username_flag && db->config->allow_anonymous == false){ _mosquitto_send_connack(context, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } #ifdef WITH_TLS } #endif /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND_STR(db->clientid_index_hash, client_id, find_cih); if(find_cih){ i = find_cih->db_context_index; /* Found a matching client */ if(db->contexts[i]->sock == -1){ /* Client is reconnecting after a disconnect */ /* FIXME - does anything else need to be done here? */ }else{ /* Client is already connected, disconnect old version */ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Client %s already connected, closing old connection.", client_id); } } db->contexts[i]->clean_session = clean_session; mqtt3_context_cleanup(db, db->contexts[i], false); db->contexts[i]->state = mosq_cs_connected; db->contexts[i]->address = _mosquitto_strdup(context->address); db->contexts[i]->sock = context->sock; db->contexts[i]->listener = context->listener; db->contexts[i]->last_msg_in = mosquitto_time(); db->contexts[i]->last_msg_out = mosquitto_time(); db->contexts[i]->keepalive = context->keepalive; db->contexts[i]->pollfd_index = context->pollfd_index; #ifdef WITH_TLS db->contexts[i]->ssl = context->ssl; #endif if(context->username){ db->contexts[i]->username = _mosquitto_strdup(context->username); } context->sock = -1; #ifdef WITH_TLS context->ssl = NULL; #endif context->state = mosq_cs_disconnecting; context = db->contexts[i]; if(context->msgs){ mqtt3_db_message_reconnect_reset(context); } } context->id = client_id; client_id = NULL; context->clean_session = clean_session; context->ping_t = 0; // Add the client ID to the DB hash table here new_cih = _mosquitto_malloc(sizeof(struct _clientid_index_hash)); if(!new_cih){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } new_cih->id = context->id; new_cih->db_context_index = context->db_index; HASH_ADD_KEYPTR(hh, db->clientid_index_hash, context->id, strlen(context->id), new_cih); #ifdef WITH_PERSISTENCE if(!clean_session){ db->persistence_changes++; } #endif /* Associate user with its ACL, assuming we have ACLs loaded. */ if(db->acl_list){ acl_tail = db->acl_list; while(acl_tail){ if(context->username){ if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ context->acl_list = acl_tail; break; } }else{ if(acl_tail->username == NULL){ context->acl_list = acl_tail; break; } } acl_tail = acl_tail->next; } }else{ context->acl_list = NULL; } if(will_struct){ if(mosquitto_acl_check(db, context, will_topic, MOSQ_ACL_WRITE) != MOSQ_ERR_SUCCESS){ _mosquitto_send_connack(context, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } context->will = will_struct; context->will->topic = will_topic; if(will_payload){ context->will->payload = will_payload; context->will->payloadlen = will_payloadlen; }else{ context->will->payload = NULL; context->will->payloadlen = 0; } context->will->qos = will_qos; context->will->retain = will_retain; } if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d).", context->address, context->id, context->clean_session, context->keepalive); } context->state = mosq_cs_connected; return _mosquitto_send_connack(context, CONNACK_ACCEPTED); handle_connect_error: if(client_id) _mosquitto_free(client_id); if(username) _mosquitto_free(username); if(password) _mosquitto_free(password); if(will_payload) _mosquitto_free(will_payload); if(will_topic) _mosquitto_free(will_topic); if(will_struct) _mosquitto_free(will_struct); return rc; } int mqtt3_handle_disconnect(struct mosquitto_db *db, struct mosquitto *context) { if(!context){ return MOSQ_ERR_INVAL; } if(context->in_packet.remaining_length != 0){ return MOSQ_ERR_PROTOCOL; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received DISCONNECT from %s", context->id); context->state = mosq_cs_disconnecting; mqtt3_context_disconnect(db, context); return MOSQ_ERR_SUCCESS; } int mqtt3_handle_subscribe(struct mosquitto_db *db, struct mosquitto *context) { int rc = 0; int rc2; uint16_t mid; char *sub; uint8_t qos; uint8_t *payload = NULL, *tmp_payload; uint32_t payloadlen = 0; int len; char *sub_mount; if(!context) return MOSQ_ERR_INVAL; _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->id); /* FIXME - plenty of potential for memory leaks here */ if(_mosquitto_read_uint16(&context->in_packet, &mid)) return 1; while(context->in_packet.pos < context->in_packet.remaining_length){ sub = NULL; if(_mosquitto_read_string(&context->in_packet, &sub)){ if(payload) _mosquitto_free(payload); return 1; } if(sub){ if(_mosquitto_read_byte(&context->in_packet, &qos)){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(qos > 2){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in subscription command from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(_mosquitto_fix_sub_topic(&sub)){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(!strlen(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Empty subscription string from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(sub) + 1; sub_mount = _mosquitto_calloc(len, sizeof(char)); if(!sub_mount){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return MOSQ_ERR_NOMEM; } snprintf(sub_mount, len, "%s%s", context->listener->mount_point, sub); _mosquitto_free(sub); sub = sub_mount; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); rc2 = mqtt3_sub_add(db, context, sub, qos, &db->subs); if(rc2 == MOSQ_ERR_SUCCESS){ if(mqtt3_retain_queue(db, context, sub, qos)) rc = 1; }else if(rc2 != -1){ rc = rc2; } _mosquitto_log_printf(NULL, MOSQ_LOG_SUBSCRIBE, "%s %d %s", context->id, qos, sub); _mosquitto_free(sub); tmp_payload = _mosquitto_realloc(payload, payloadlen + 1); if(tmp_payload){ payload = tmp_payload; payload[payloadlen] = qos; payloadlen++; }else{ if(payload) _mosquitto_free(payload); return MOSQ_ERR_NOMEM; } } } if(_mosquitto_send_suback(context, mid, payloadlen, payload)) rc = 1; _mosquitto_free(payload); #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif return rc; }
int _mosquitto_send_connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session) { struct _mosquitto_packet *packet = NULL; int payloadlen; uint8_t will = 0; uint8_t byte; int rc; uint8_t version = PROTOCOL_VERSION; assert(mosq); assert(mosq->id); packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; payloadlen = 2+strlen(mosq->id); if(mosq->will){ will = 1; assert(mosq->will->topic); payloadlen += 2+strlen(mosq->will->topic) + 2+mosq->will->payloadlen; } if(mosq->username){ payloadlen += 2+strlen(mosq->username); if(mosq->password){ payloadlen += 2+strlen(mosq->password); } } packet->command = CONNECT; packet->remaining_length = 12+payloadlen; rc = _mosquitto_packet_alloc(packet); if(rc){ _mosquitto_free(packet); return rc; } /* Variable header */ _mosquitto_write_string(packet, PROTOCOL_NAME, strlen(PROTOCOL_NAME)); _mosquitto_write_byte(packet, version); byte = (clean_session&0x1)<<1; if(will){ byte = byte | ((mosq->will->retain&0x1)<<5) | ((mosq->will->qos&0x3)<<3) | ((will&0x1)<<2); } if(mosq->username){ byte = byte | 0x1<<7; if(mosq->password){ byte = byte | 0x1<<6; } } _mosquitto_write_byte(packet, byte); _mosquitto_write_uint16(packet, keepalive); /* Payload */ _mosquitto_write_string(packet, mosq->id, strlen(mosq->id)); if(will){ _mosquitto_write_string(packet, mosq->will->topic, strlen(mosq->will->topic)); _mosquitto_write_string(packet, (const char *)mosq->will->payload, mosq->will->payloadlen); } if(mosq->username){ _mosquitto_write_string(packet, mosq->username, strlen(mosq->username)); if(mosq->password){ _mosquitto_write_string(packet, mosq->password, strlen(mosq->password)); } } mosq->keepalive = keepalive; #ifdef WITH_BROKER #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending CONNECT", mosq->id); #endif return _mosquitto_packet_queue(mosq, packet); }
int mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context) { char *protocol_name = NULL; uint8_t protocol_version; uint8_t connect_flags; uint8_t connect_ack = 0; char *client_id = NULL; char *will_payload = NULL, *will_topic = NULL; char *will_topic_mount; uint16_t will_payloadlen; struct mosquitto_message *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_session; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int rc; struct _mosquitto_acl_user *acl_tail; struct mosquitto_client_msg *msg_tail, *msg_prev; struct mosquitto *found_context; int slen; struct _mosquitto_subleaf *leaf; int i; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; X509_NAME_ENTRY *name_entry; #endif #ifdef WITH_SYS_TREE g_connection_count++; #endif g_epoll_mqtt_connections++; /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &protocol_name)){ rc = 1; goto handle_connect_error; return 1; } if(!protocol_name){ rc = 3; goto handle_connect_error; return 3; } if(_mosquitto_read_byte(&context->in_packet, &protocol_version)){ rc = 1; goto handle_connect_error; return 1; } if(!strcmp(protocol_name, PROTOCOL_NAME_v31)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v31){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt31; }else if(!strcmp(protocol_name, PROTOCOL_NAME_v311)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v311){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if((context->in_packet.command&0x0F) != 0x00){ /* Reserved flags not set to 0, must disconnect. */ _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt311; }else{ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol \"%s\" in CONNECT from %s.", protocol_name, context->address); } _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } _mosquitto_free(protocol_name); if(_mosquitto_read_byte(&context->in_packet, &connect_flags)){ rc = 1; goto handle_connect_error; } clean_session = (connect_flags & 0x02) >> 1; will = connect_flags & 0x04; will_qos = (connect_flags & 0x18) >> 3; if(will_qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid Will QoS in CONNECT from %s.", context->address); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } will_retain = connect_flags & 0x20; password_flag = connect_flags & 0x40; username_flag = connect_flags & 0x80; if(_mosquitto_read_uint16(&context->in_packet, &(context->keepalive))){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &client_id)){ rc = 1; goto handle_connect_error; } slen = strlen(client_id); if(slen == 0){ if(context->protocol == mosq_p_mqtt31){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ /* mqtt311 */ _mosquitto_free(client_id); client_id = NULL; if(clean_session == 0 || db->config->allow_zero_length_clientid == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ client_id = client_id_gen(db); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } } } } /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } if(will){ will_struct = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!will_struct){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &will_topic)){ rc = 1; goto handle_connect_error; } if(STREMPTY(will_topic)){ rc = 1; goto handle_connect_error; } if(context->listener && context->listener->mount_point){ slen = strlen(context->listener->mount_point) + strlen(will_topic); will_topic_mount = _mosquitto_malloc(slen+1); if(!will_topic_mount){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } snprintf(will_topic_mount, slen, "%s%s", context->listener->mount_point, will_topic); will_topic_mount[slen] = '\0'; _mosquitto_free(will_topic); will_topic = will_topic_mount; } if(mosquitto_pub_topic_check(will_topic)){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_uint16(&context->in_packet, &will_payloadlen)){ rc = 1; goto handle_connect_error; } if(will_payloadlen > 0){ will_payload = _mosquitto_malloc(will_payloadlen); if(!will_payload){ rc = 1; goto handle_connect_error; } rc = _mosquitto_read_bytes(&context->in_packet, will_payload, will_payloadlen); if(rc){ rc = 1; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(will_qos != 0 || will_retain != 0){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } if(username_flag){ rc = _mosquitto_read_string(&context->in_packet, &username); if(rc == MOSQ_ERR_SUCCESS){ if(password_flag){ rc = _mosquitto_read_string(&context->in_packet, &password); if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else if(rc == MOSQ_ERR_PROTOCOL){ if(context->protocol == mosq_p_mqtt31){ /* Password flag given, but no password. Ignore. */ password_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } }else if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else{ if(context->protocol == mosq_p_mqtt31){ /* Username flag given, but no username. Ignore. */ username_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(password_flag){ /* username_flag == 0 && password_flag == 1 is forbidden */ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } #ifdef WITH_TLS if(context->listener && context->listener->ssl_ctx && context->listener->use_identity_as_username){ if(!context->ssl){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } #ifdef REAL_WITH_TLS_PSK if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } }else{ #endif /* REAL_WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name_entry = X509_NAME_get_entry(name, i); context->username = _mosquitto_strdup((char *)ASN1_STRING_data(name_entry->value)); if(!context->username){ rc = 1; goto handle_connect_error; } X509_free(client_cert); client_cert = NULL; #ifdef REAL_WITH_TLS_PSK } #endif /* REAL_WITH_TLS_PSK */ }else{ #endif /* WITH_TLS */ if(username_flag){ rc = mosquitto_unpwd_check(db, username, password); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; default: mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; } context->username = username; context->password = password; username = NULL; /* Avoid free() in error: below. */ password = NULL; } if(!username_flag && db->config->allow_anonymous == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } #ifdef WITH_TLS } #endif if(context->listener && context->listener->use_username_as_clientid){ if(context->username){ _mosquitto_free(client_id); client_id = _mosquitto_strdup(context->username); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } }else{ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND(hh_id, db->contexts_by_id, client_id, strlen(client_id), found_context); if(found_context){ /* Found a matching client */ if(found_context->sock == INVALID_SOCKET){ /* Client is reconnecting after a disconnect */ /* FIXME - does anything need to be done here? */ }else{ /* Client is already connected, disconnect old version. This is * done in mqtt3_context_cleanup() below. */ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Client %s already connected, closing old connection.", client_id); } } if(context->protocol == mosq_p_mqtt311){ if(clean_session == 0){ connect_ack |= 0x01; } } context->clean_session = clean_session; if(context->clean_session == false && found_context->clean_session == false){ if(found_context->msgs){ context->msgs = found_context->msgs; found_context->msgs = NULL; mqtt3_db_message_reconnect_reset(db, context); } context->subs = found_context->subs; found_context->subs = NULL; context->sub_count = found_context->sub_count; found_context->sub_count = 0; for(i=0; i<context->sub_count; i++){ if(context->subs[i]){ leaf = context->subs[i]->subs; while(leaf){ if(leaf->context == found_context){ leaf->context = context; } leaf = leaf->next; } } } } found_context->clean_session = true; found_context->state = mosq_cs_disconnecting; if(g_flag_epoll) { epoll_do_disconnect(db,found_context); } else { do_disconnect(db, found_context); } } /* Associate user with its ACL, assuming we have ACLs loaded. */ if(db->acl_list){ acl_tail = db->acl_list; while(acl_tail){ if(context->username){ if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ context->acl_list = acl_tail; break; } }else{ if(acl_tail->username == NULL){ context->acl_list = acl_tail; break; } } acl_tail = acl_tail->next; } }else{ context->acl_list = NULL; } if(will_struct){ context->will = will_struct; context->will->topic = will_topic; if(will_payload){ context->will->payload = will_payload; context->will->payloadlen = will_payloadlen; }else{ context->will->payload = NULL; context->will->payloadlen = 0; } context->will->qos = will_qos; context->will->retain = will_retain; } if(db->config->connection_messages == true){ if(context->is_bridge){ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } }else{ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } } } context->id = client_id; client_id = NULL; context->clean_session = clean_session; context->ping_t = 0; context->is_dropping = false; if((protocol_version&0x80) == 0x80){ context->is_bridge = true; } /* Remove any queued messages that are no longer allowed through ACL, * assuming a possible change of username. */ msg_tail = context->msgs; msg_prev = NULL; while(msg_tail){ if(msg_tail->direction == mosq_md_out){ if(mosquitto_acl_check(db, context, msg_tail->store->topic, MOSQ_ACL_READ) != MOSQ_ERR_SUCCESS){ mosquitto__db_msg_store_deref(db, &msg_tail->store); if(msg_prev){ msg_prev->next = msg_tail->next; _mosquitto_free(msg_tail); msg_tail = msg_prev->next; }else{ context->msgs = context->msgs->next; _mosquitto_free(msg_tail); msg_tail = context->msgs; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } } HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); #ifdef WITH_PERSISTENCE if(!clean_session){ db->persistence_changes++; } #endif context->state = mosq_cs_connected; return _mosquitto_send_connack(context, connect_ack, CONNACK_ACCEPTED); handle_connect_error: if(client_id) _mosquitto_free(client_id); if(username) _mosquitto_free(username); if(password) _mosquitto_free(password); if(will_payload) _mosquitto_free(will_payload); if(will_topic) _mosquitto_free(will_topic); if(will_struct) _mosquitto_free(will_struct); #ifdef WITH_TLS if(client_cert) X509_free(client_cert); #endif /* We return an error here which means the client is freed later on. */ return rc; }