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 _mosquitto_reconnect(struct mosquitto *mosq, bool blocking) { int rc; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_new; pthread_mutex_unlock(&mosq->state_mutex); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); mosq->last_msg_out = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); mosq->ping_t = 0; _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; } while(mosq->current_out_packet){ packet = mosq->current_out_packet; /* Free data and reset values */ mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; } _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); } pthread_mutex_unlock(&mosq->out_packet_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); _mosquitto_messages_reconnect_reset(mosq); rc = _mosquitto_socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking); if(rc){ return rc; } return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); }
void _mosquitto_message_retry_check_actual(struct mosquitto *mosq, struct mosquitto_message_all *messages, pthread_mutex_t mutex) { time_t now = mosquitto_time(); assert(mosq); pthread_mutex_lock(&mutex); while(messages) { if(messages->timestamp + mosq->message_retry < now) { switch(messages->state) { case mosq_ms_wait_for_puback: case mosq_ms_wait_for_pubrec: messages->timestamp = now; messages->dup = true; _mosquitto_send_publish(mosq, messages->msg.mid, messages->msg.topic, messages->msg.payloadlen, messages->msg.payload, messages->msg.qos, messages->msg.retain, messages->dup); break; case mosq_ms_wait_for_pubrel: messages->timestamp = now; messages->dup = true; _mosquitto_send_pubrec(mosq, messages->msg.mid); break; case mosq_ms_wait_for_pubcomp: messages->timestamp = now; messages->dup = true; _mosquitto_send_pubrel(mosq, messages->msg.mid, true); break; default: break; } } messages = messages->next; } pthread_mutex_unlock(&mutex); }
int mqtt3_db_message_timeout_check(struct mosquitto_db *db, unsigned int timeout) { int i; time_t threshold; enum mosquitto_msg_state new_state; struct mosquitto *context; struct mosquitto_client_msg *msg; threshold = mosquitto_time() - timeout; for(i=0; i<db->context_count; i++){ context = db->contexts[i]; if(!context) continue; msg = context->msgs; while(msg){ new_state = mosq_ms_invalid; if(msg->timestamp < threshold && msg->state != mosq_ms_queued){ switch(msg->state){ case mosq_ms_wait_for_puback: new_state = mosq_ms_publish_qos1; break; case mosq_ms_wait_for_pubrec: new_state = mosq_ms_publish_qos2; break; case mosq_ms_wait_for_pubrel: new_state = mosq_ms_send_pubrec; break; case mosq_ms_wait_for_pubcomp: new_state = mosq_ms_resend_pubrel; break; default: break; } if(new_state != mosq_ms_invalid){ msg->timestamp = mosquitto_time(); msg->state = new_state; msg->dup = true; } } msg = msg->next; } } return MOSQ_ERR_SUCCESS; }
//超过重发限,需要移除消息,返回失败信息,add by lanhuaiyu@20150508 void _mos_message_retry_check_timeout(struct mosquitto *mosq) { time_t now = mosquitto_time(); assert(mosq); struct mosquitto_message_all *cur, *prev = NULL; pthread_mutex_lock(&mosq->out_message_mutex); cur = mosq->out_messages; while(cur){ if (cur->timestamp > 0 && cur->state != mosq_ms_invalid && (now - cur->timestamp) > mosq->max_message_retry) { _mosquitto_log_printf(mosq, MOSQ_LOG_NOTICE, "Message timeout %d will give up;now:%ld timestamp:%ld ", cur->msg.mid,now, cur->timestamp, mosq->max_message_retry); if(prev){ prev->next = cur->next; }else{ mosq->out_messages = cur->next; } mosq->out_queue_len--; if(cur->next == NULL){ mosq->out_messages_last = prev; }else if(!mosq->out_messages){ mosq->out_messages_last = NULL; } if(cur->msg.qos > 0){ mosq->inflight_messages--; } if (mosq->on_publish != NULL) { mosq->on_publish(mosq, mosq->userdata,cur->msg.mid, MOSQ_ERR_MSG_FAILED); } struct mosquitto_message_all* temp_del = cur; cur = cur->next; //need release memory _mosquitto_message_cleanup(&temp_del); } else{ prev = cur; cur = cur->next; } } pthread_mutex_unlock(&mosq->out_message_mutex); }
int mqtt3_db_message_update(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, enum mosquitto_msg_state state) { struct mosquitto_client_msg *tail; tail = context->msgs; while(tail){ if(tail->mid == mid && tail->direction == dir){ tail->state = state; tail->timestamp = mosquitto_time(); return MOSQ_ERR_SUCCESS; } tail = tail->next; } return 1; }
int _mosquitto_send_pingreq(struct mosquitto *mosq) { int rc; assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PINGREQ to %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PINGREQ", mosq->id); #endif rc = _mosquitto_send_simple_command(mosq, PINGREQ); if(rc == MOSQ_ERR_SUCCESS){ mosq->ping_t = mosquitto_time(); } return rc; }
int mqtt3_db_message_delete(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir) { struct mosquitto_client_msg *tail, *last = NULL; 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){ tail->state = mosq_ms_wait_for_pubrel; } } } if(tail->mid == mid && tail->direction == dir){ msg_index--; _message_remove(context, &tail, last); deleted = true; }else{ last = tail; tail = tail->next; } if(msg_index > max_inflight && deleted){ return MOSQ_ERR_SUCCESS; } } return MOSQ_ERR_SUCCESS; }
int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state) { struct mosquitto_message_all *message; assert(mosq); pthread_mutex_lock(&mosq->out_message_mutex); message = mosq->out_messages; while(message){ if(message->msg.mid == mid){ message->state = state; message->timestamp = mosquitto_time(); pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } message = message->next; } pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_NOT_FOUND; }
void mqtt3_context_disconnect(struct mosquitto_db *db, struct mosquitto *ctxt) { if(ctxt->state != mosq_cs_disconnecting && ctxt->will){ /* Unexpected disconnect, queue the client will. */ mqtt3_db_messages_easy_queue(db, ctxt, ctxt->will->topic, ctxt->will->qos, ctxt->will->payloadlen, ctxt->will->payload, ctxt->will->retain); } if(ctxt->will){ if(ctxt->will->topic) _mosquitto_free(ctxt->will->topic); if(ctxt->will->payload) _mosquitto_free(ctxt->will->payload); _mosquitto_free(ctxt->will); ctxt->will = NULL; } if(ctxt->listener){ ctxt->listener->client_count--; assert(ctxt->listener->client_count >= 0); ctxt->listener = NULL; } ctxt->disconnect_t = mosquitto_time(); _mosquitto_socket_close(ctxt); }
int _mosquitto_message_out_update(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_state state) { struct mosquitto_message_all *message; assert(mosq); pthread_mutex_lock(&mosq->out_message_mutex); message = mosq->out_messages; while(message){ if(message->msg.mid == mid){ message->state = state; message->timestamp = mosquitto_time(); pthread_mutex_unlock(&mosq->out_message_mutex); return MOSQ_ERR_SUCCESS; } message = message->next; } pthread_mutex_unlock(&mosq->out_message_mutex); //modify by lanhuaiyu,重启后接收到上次未完成消息将导致重连;所以注释掉,始终返回MOSQ_ERR_SUCCESS return MOSQ_ERR_NOT_FOUND; // return MOSQ_ERR_SUCCESS; }
int bridge__connect_step3(struct mosquitto_db *db, struct mosquitto *context) { int rc; rc = net__socket_connect_step3(context, context->bridge->addresses[context->bridge->cur_address].address); 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; } if(context->bridge->round_robin == false && context->bridge->cur_address != 0){ context->bridge->primary_retry = mosquitto_time() + 5; } rc = send__connect(context, context->keepalive, context->clean_session); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ 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)); } net__socket_close(db, context); return rc; } }
int mosquitto_loop_misc(struct mosquitto *mosq) { time_t now; int rc; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; now = mosquitto_time(); _mosquitto_check_keepalive(mosq); if(mosq->last_retry_check+1 < now){ _mosquitto_message_retry_check(mosq); mosq->last_retry_check = now; } if(mosq->ping_t && now - mosq->ping_t >= mosq->keepalive){ /* mosq->ping_t != 0 means we are waiting for a pingresp. * This hasn't happened in the keepalive time so we should disconnect. */ _mosquitto_socket_close(mosq); pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ rc = MOSQ_ERR_SUCCESS; }else{ rc = 1; } pthread_mutex_unlock(&mosq->state_mutex); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_disconnect){ mosq->in_callback = true; mosq->on_disconnect(mosq, mosq->userdata, rc); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); return MOSQ_ERR_CONN_LOST; } return MOSQ_ERR_SUCCESS; }
int mqtt3_db_message_write(struct mosquitto *context) { int rc; struct mosquitto_client_msg *tail, *last = NULL; uint16_t mid; int retries; int retain; const char *topic; int qos; uint32_t payloadlen; const void *payload; int msg_count = 0; if(!context || context->sock == -1 || (context->state == mosq_cs_connected && !context->id)){ return MOSQ_ERR_INVAL; } tail = context->msgs; while(tail){ if(tail->direction == mosq_md_in){ msg_count++; } if(tail->state != mosq_ms_queued){ mid = tail->mid; retries = tail->dup; retain = tail->retain; topic = tail->store->msg.topic; qos = tail->qos; payloadlen = tail->store->msg.payloadlen; payload = tail->store->msg.payload; switch(tail->state){ case mosq_ms_publish_qos0: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ _message_remove(context, &tail, last); }else{ return rc; } break; case mosq_ms_publish_qos1: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_puback; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_publish_qos2: rc = _mosquitto_send_publish(context, mid, topic, payloadlen, payload, qos, retain, retries); if(!rc){ tail->timestamp = mosquitto_time(); tail->dup = 1; /* Any retry attempts are a duplicate. */ tail->state = mosq_ms_wait_for_pubrec; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_send_pubrec: rc = _mosquitto_send_pubrec(context, mid); if(!rc){ tail->state = mosq_ms_wait_for_pubrel; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_resend_pubrel: rc = _mosquitto_send_pubrel(context, mid, true); if(!rc){ tail->state = mosq_ms_wait_for_pubcomp; }else{ return rc; } last = tail; tail = tail->next; break; case mosq_ms_resend_pubcomp: rc = _mosquitto_send_pubcomp(context, mid); if(!rc){ tail->state = mosq_ms_wait_for_pubrel; }else{ return rc; } last = tail; tail = tail->next; break; default: last = tail; tail = tail->next; break; } }else{ /* state == mosq_ms_queued */ if(tail->direction == mosq_md_in && (max_inflight == 0 || msg_count < max_inflight)){ if(tail->qos == 2){ tail->state = mosq_ms_send_pubrec; } }else{ last = tail; tail = tail->next; } } } return MOSQ_ERR_SUCCESS; }
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; }
void _mosquitto_check_keepalive(struct mosquitto *mosq) { time_t last_msg_out; time_t last_msg_in; time_t now = mosquitto_time(); #ifndef WITH_BROKER int rc; #endif assert(mosq); #if defined(WITH_BROKER) && defined(WITH_BRIDGE) /* Check if a lazy bridge should be timed out due to idle. */ if(mosq->bridge && mosq->bridge->start_type == bst_lazy && mosq->sock != INVALID_SOCKET && now - mosq->last_msg_out >= mosq->bridge->idle_timeout){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id); _mosquitto_socket_close(mosq); return; } #endif pthread_mutex_lock(&mosq->msgtime_mutex); last_msg_out = mosq->last_msg_out; last_msg_in = mosq->last_msg_in; pthread_mutex_unlock(&mosq->msgtime_mutex); if(mosq->sock != INVALID_SOCKET && (now - last_msg_out >= mosq->keepalive || now - last_msg_in >= mosq->keepalive)){ if(mosq->state == mosq_cs_connected && mosq->ping_t == 0){ _mosquitto_send_pingreq(mosq); /* Reset last msg times to give the server time to send a pingresp */ pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = now; mosq->last_msg_out = now; pthread_mutex_unlock(&mosq->msgtime_mutex); }else{ #ifdef WITH_BROKER if(mosq->listener){ mosq->listener->client_count--; assert(mosq->listener->client_count >= 0); } mosq->listener = NULL; #endif _mosquitto_socket_close(mosq); #ifndef WITH_BROKER pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_disconnecting){ rc = MOSQ_ERR_SUCCESS; }else{ rc = 1; } pthread_mutex_unlock(&mosq->state_mutex); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_disconnect){ mosq->in_callback = true; mosq->on_disconnect(mosq, mosq->userdata, rc); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); #endif } } }
int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) { #ifdef HAVE_PSELECT struct timespec local_timeout; #else struct timeval local_timeout; #endif fd_set readfds, writefds; int fdcount; int rc; char pairbuf; int maxfd = 0; time_t now; if(!mosq || max_packets < 1) return MOSQ_ERR_INVAL; #ifndef WIN32 if(mosq->sock >= FD_SETSIZE || mosq->sockpairR >= FD_SETSIZE){ return MOSQ_ERR_INVAL; } #endif FD_ZERO(&readfds); FD_ZERO(&writefds); if(mosq->sock != INVALID_SOCKET){ maxfd = mosq->sock; FD_SET(mosq->sock, &readfds); pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet || mosq->current_out_packet){ FD_SET(mosq->sock, &writefds); } #ifdef WITH_TLS if(mosq->ssl){ if(mosq->want_write){ FD_SET(mosq->sock, &writefds); }else if(mosq->want_connect){ /* Remove possible FD_SET from above, we don't want to check * for writing if we are still connecting, unless want_write is * definitely set. The presence of outgoing packets does not * matter yet. */ FD_CLR(mosq->sock, &writefds); } } #endif pthread_mutex_unlock(&mosq->out_packet_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); }else{ #ifdef WITH_SRV if(mosq->achan){ pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_connect_srv){ rc = ares_fds(mosq->achan, &readfds, &writefds); if(rc > maxfd){ maxfd = rc; } }else{ pthread_mutex_unlock(&mosq->state_mutex); return MOSQ_ERR_NO_CONN; } pthread_mutex_unlock(&mosq->state_mutex); } #else return MOSQ_ERR_NO_CONN; #endif } if(mosq->sockpairR != INVALID_SOCKET){ /* sockpairR is used to break out of select() before the timeout, on a * call to publish() etc. */ FD_SET(mosq->sockpairR, &readfds); if(mosq->sockpairR > maxfd){ maxfd = mosq->sockpairR; } } if(timeout < 0){ timeout = 1000; } now = mosquitto_time(); if(mosq->next_msg_out && now + timeout/1000 > mosq->next_msg_out){ timeout = (mosq->next_msg_out - now)*1000; } if(timeout < 0){ /* There has been a delay somewhere which means we should have already * sent a message. */ timeout = 0; } local_timeout.tv_sec = timeout/1000; #ifdef HAVE_PSELECT local_timeout.tv_nsec = (timeout-local_timeout.tv_sec*1000)*1e6; #else local_timeout.tv_usec = (timeout-local_timeout.tv_sec*1000)*1000; #endif #ifdef HAVE_PSELECT fdcount = pselect(maxfd+1, &readfds, &writefds, NULL, &local_timeout, NULL); #else fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout); #endif if(fdcount == -1){ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EINTR){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_ERRNO; } }else{ if(mosq->sock != INVALID_SOCKET){ if(FD_ISSET(mosq->sock, &readfds)){ #ifdef WITH_TLS if(mosq->want_connect){ rc = mosquitto__socket_connect_tls(mosq); if(rc) return rc; }else #endif { do{ rc = mosquitto_loop_read(mosq, max_packets); if(rc || mosq->sock == INVALID_SOCKET){ return rc; } }while(SSL_DATA_PENDING(mosq)); } } if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){ #ifndef WIN32 if(read(mosq->sockpairR, &pairbuf, 1) == 0){ } #else recv(mosq->sockpairR, &pairbuf, 1, 0); #endif /* Fake write possible, to stimulate output write even though * we didn't ask for it, because at that point the publish or * other command wasn't present. */ FD_SET(mosq->sock, &writefds); } if(FD_ISSET(mosq->sock, &writefds)){ #ifdef WITH_TLS if(mosq->want_connect){ rc = mosquitto__socket_connect_tls(mosq); if(rc) return rc; }else #endif { rc = mosquitto_loop_write(mosq, max_packets); if(rc || mosq->sock == INVALID_SOCKET){ return rc; } } } } #ifdef WITH_SRV if(mosq->achan){ ares_process(mosq->achan, &readfds, &writefds); } #endif } return mosquitto_loop_misc(mosq); }
static int callback_mqtt(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct mosquitto_db *db; struct mosquitto *mosq = NULL; struct mosquitto__packet *packet; int count, i, j; const struct libwebsocket_protocols *p; struct libws_mqtt_data *u = (struct libws_mqtt_data *)user; size_t pos; uint8_t *buf; int rc; uint8_t byte; db = &int_db; switch (reason) { case LWS_CALLBACK_ESTABLISHED: mosq = context__init(db, WEBSOCKET_CLIENT); if(mosq){ p = libwebsockets_get_protocol(wsi); for (i=0; i<db->config->listener_count; i++){ if (db->config->listeners[i].protocol == mp_websockets) { for (j=0; db->config->listeners[i].ws_protocol[j].name; j++){ if (p == &db->config->listeners[i].ws_protocol[j]){ mosq->listener = &db->config->listeners[i]; mosq->listener->client_count++; } } } } if(!mosq->listener){ mosquitto__free(mosq); return -1; } #if !defined(LWS_LIBRARY_VERSION_NUMBER) mosq->ws_context = context; #endif mosq->wsi = wsi; #ifdef WITH_TLS if(in){ mosq->ssl = (SSL *)in; if(!mosq->listener->ssl_ctx){ mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl); } } #endif u->mosq = mosq; }else{ return -1; } easy_address(libwebsocket_get_socket_fd(wsi), mosq); if(!mosq->address){ /* getpeername and inet_ntop failed and not a bridge */ mosquitto__free(mosq); u->mosq = NULL; return -1; } if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){ if(db->config->connection_messages == true){ log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address); } mosquitto__free(mosq); u->mosq = NULL; return -1; } mosq->sock = libwebsocket_get_socket_fd(wsi); HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(mosq->sock), mosq); break; case LWS_CALLBACK_CLOSED: if(!u){ return -1; } mosq = u->mosq; if(mosq){ if(mosq->sock != INVALID_SOCKET){ HASH_DELETE(hh_sock, db->contexts_by_sock, mosq); mosq->sock = INVALID_SOCKET; mosq->pollfd_index = -1; } mosq->wsi = NULL; #ifdef WITH_TLS mosq->ssl = NULL; #endif do_disconnect(db, mosq); } break; case LWS_CALLBACK_SERVER_WRITEABLE: if(!u){ return -1; } mosq = u->mosq; if(!mosq){ return -1; } db__message_write(db, mosq); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } if(mosq->current_out_packet && !lws_send_pipe_choked(mosq->wsi)){ packet = mosq->current_out_packet; if(packet->pos == 0 && packet->to_process == packet->packet_length){ /* First time this packet has been dealt with. * libwebsockets requires that the payload has * LWS_SEND_BUFFER_PRE_PADDING space available before the * actual data and LWS_SEND_BUFFER_POST_PADDING afterwards. * We've already made the payload big enough to allow this, * but need to move it into position here. */ memmove(&packet->payload[LWS_SEND_BUFFER_PRE_PADDING], packet->payload, packet->packet_length); packet->pos += LWS_SEND_BUFFER_PRE_PADDING; } count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY); if(count < 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } return 0; } #ifdef WITH_SYS_TREE g_bytes_sent += count; #endif packet->to_process -= count; packet->pos += count; if(packet->to_process > 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } break; } #ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } #endif /* Free data and reset values */ mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } packet__cleanup(packet); mosquitto__free(packet); mosq->next_msg_out = mosquitto_time() + mosq->keepalive; } if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } if(mosq->current_out_packet){ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } break; case LWS_CALLBACK_RECEIVE: if(!u || !u->mosq){ return -1; } mosq = u->mosq; pos = 0; buf = (uint8_t *)in; G_BYTES_RECEIVED_INC(len); while(pos < len){ if(!mosq->in_packet.command){ mosq->in_packet.command = buf[pos]; pos++; /* Clients must send CONNECT as their first command. */ if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){ return -1; } } if(mosq->in_packet.remaining_count <= 0){ do{ if(pos == len){ return 0; } byte = buf[pos]; pos++; mosq->in_packet.remaining_count--; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count < -4){ return -1; } mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }while((byte & 128) != 0); mosq->in_packet.remaining_count *= -1; if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload){ return -1; } mosq->in_packet.to_process = mosq->in_packet.remaining_length; } } if(mosq->in_packet.to_process>0){ if(len - pos >= mosq->in_packet.to_process){ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], mosq->in_packet.to_process); mosq->in_packet.pos += mosq->in_packet.to_process; pos += mosq->in_packet.to_process; mosq->in_packet.to_process = 0; }else{ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], len-pos); mosq->in_packet.pos += len-pos; mosq->in_packet.to_process -= len-pos; return 0; } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_SYS_TREE G_MSGS_RECEIVED_INC(1); if(((mosq->in_packet.command)&0xF5) == PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } #endif rc = handle__packet(db, mosq); /* Free data and reset values */ packet__cleanup(&mosq->in_packet); mosq->last_msg_in = mosquitto_time(); if(rc && (mosq->out_packet || mosq->current_out_packet)) { if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_disconnect_ws; } libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } else if (rc) { do_disconnect(db, mosq); return -1; } } break; default: break; } return 0; }
int _mosquitto_packet_read(struct mosquitto *mosq) #endif { uint8_t byte; ssize_t read_length; int rc = 0; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; /* This gets called if pselect() indicates that there is network data * available - ie. at least one byte. What we do depends on what data we * already have. * If we've not got a command, attempt to read one and save it. This should * always work because it's only a single byte. * Then try to read the remaining length. This may fail because it is may * be more than one byte - will need to save data pending next read if it * does fail. * Then try to read the remaining payload, where 'payload' here means the * combined variable header and actual payload. This is the most likely to * fail due to longer length, so save current data and current position. * After all data is read, send to _mosquitto_handle_packet() to deal with. * Finally, free the memory and reset everything to starting conditions. */ if(!mosq->in_packet.command){ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.command = byte; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_bytes_received++; # endif /* Clients must send CONNECT as their first command. */ if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CONNECT) return MOSQ_ERR_PROTOCOL; #endif }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(!mosq->in_packet.have_remaining){ /* Read remaining * Algorithm for decoding taken from pseudo code at * http://publib.boulder.ibm.com/infocenter/wmbhelp/v6r0m0/topic/com.ibm.etools.mft.doc/ac10870_.htm */ do{ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.remaining_count++; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count > 4) return MOSQ_ERR_PROTOCOL; #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received++; #endif mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } }while((byte & 128) != 0); if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM; mosq->in_packet.to_process = mosq->in_packet.remaining_length; } mosq->in_packet.have_remaining = 1; } while(mosq->in_packet.to_process>0){ read_length = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(read_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received += read_length; #endif mosq->in_packet.to_process -= read_length; mosq->in_packet.pos += read_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_received++; if(((mosq->in_packet.command)&0xF5) == PUBLISH){ g_pub_msgs_received++; } # endif rc = mqtt3_packet_handle(db, mosq); #else rc = _mosquitto_packet_handle(mosq); #endif /* Free data and reset values */ _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); return rc; }
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; }
int mqtt3_bridge_connect(struct mosquitto_db *db, struct mosquitto *context) { int rc; 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; mqtt3_bridge_packet_cleanup(context); mqtt3_db_message_reconnect_reset(db, context); if(context->clean_session){ mqtt3_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. */ mqtt3_subs_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){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); if(mqtt3_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'; mqtt3_db_messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_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'; mqtt3_db_messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); context->bridge->initial_notification_done = true; } notification_payload = '0'; rc = _mosquitto_will_set(context, notification_topic, 1, ¬ification_payload, 1, true); _mosquitto_free(notification_topic); if(rc != MOSQ_ERR_SUCCESS){ return rc; } } } _mosquitto_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 = _mosquitto_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){ _mosquitto_socket_close(db, context); return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(context->sock), context); if(rc == MOSQ_ERR_CONN_PENDING){ context->state = mosq_cs_connect_pending; } rc = _mosquitto_send_connect(context, context->keepalive, context->clean_session); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } _mosquitto_socket_close(db, context); return rc; } }
int _mosquitto_packet_write(struct mosquitto *mosq) { ssize_t write_length; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } pthread_mutex_unlock(&mosq->out_packet_mutex); if(mosq->state == mosq_cs_connect_pending){ pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } while(mosq->current_out_packet){ packet = mosq->current_out_packet; while(packet->to_process > 0){ write_length = _mosquitto_net_write(mosq, &(packet->payload[packet->pos]), packet->to_process); if(write_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_sent += write_length; #endif packet->to_process -= write_length; packet->pos += write_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; }else{ pthread_mutex_unlock(&mosq->current_out_packet_mutex); switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } # endif #else if(((packet->command)&0xF6) == PUBLISH){ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_publish){ /* This is a QoS=0 message */ mosq->in_callback = true; mosq->on_publish(mosq, mosq->userdata, packet->mid); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); }else if(((packet->command)&0xF0) == DISCONNECT){ /* FIXME what cleanup needs doing here? * incoming/outgoing messages? */ _mosquitto_socket_close(mosq); /* Start of duplicate, possibly unnecessary code. * This does leave things in a consistent state at least. */ /* Free data and reset values */ pthread_mutex_lock(&mosq->out_packet_mutex); mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } pthread_mutex_unlock(&mosq->out_packet_mutex); _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_out = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); /* End of duplicate, possibly unnecessary code */ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_disconnect){ mosq->in_callback = true; mosq->on_disconnect(mosq, mosq->userdata, 0); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } #endif /* Free data and reset values */ pthread_mutex_lock(&mosq->out_packet_mutex); mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } pthread_mutex_unlock(&mosq->out_packet_mutex); _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_out = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); } pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; }
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_db_message_insert(struct mosquitto_db *db, struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, int qos, bool retain, struct mosquitto_msg_store *stored) { struct mosquitto_client_msg *msg; enum mosquitto_msg_state state = mosq_ms_invalid; int rc = 0; int i; char **dest_ids; assert(stored); if(!context) return MOSQ_ERR_INVAL; /* Check whether we've already sent this message to this client * for outgoing messages only. * If retain==true then this is a stale retained message and so should be * sent regardless. FIXME - this does mean retained messages will received * multiple times for overlapping subscriptions, although this is only the * case for SUBSCRIPTION with multiple subs in so is a minor concern. */ if(db->config->allow_duplicate_messages == false && dir == mosq_md_out && retain == false && stored->dest_ids){ for(i=0; i<stored->dest_id_count; i++){ if(!strcmp(stored->dest_ids[i], context->id)){ /* We have already sent this message to this client. */ return MOSQ_ERR_SUCCESS; } } } if(context->sock == INVALID_SOCKET){ /* Client is not connected only queue messages with QoS>0. */ if(qos == 0 && !db->config->queue_qos0_messages){ if(!context->bridge){ return 2; }else{ if(context->bridge->start_type != bst_lazy){ return 2; } } } } if(context->sock != INVALID_SOCKET){ if(qos == 0 || max_inflight == 0 || context->msg_count12 < max_inflight){ if(dir == mosq_md_out){ switch(qos){ case 0: state = mosq_ms_publish_qos0; break; case 1: state = mosq_ms_publish_qos1; break; case 2: state = mosq_ms_publish_qos2; break; } }else{ if(qos == 2){ state = mosq_ms_wait_for_pubrel; }else{ return 1; } } }else if(max_queued == 0 || context->msg_count12-max_inflight < max_queued){ state = mosq_ms_queued; rc = 2; }else{ /* Dropping message due to full queue. */ if(context->is_dropping == false){ context->is_dropping = true; _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Outgoing messages are being dropped for client %s.", context->id); } #ifdef WITH_SYS_TREE g_msgs_dropped++; #endif return 2; } }else{ if(max_queued > 0 && context->msg_count12 >= max_queued){ #ifdef WITH_SYS_TREE g_msgs_dropped++; #endif if(context->is_dropping == false){ context->is_dropping = true; _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Outgoing messages are being dropped for client %s.", context->id); } return 2; }else{ state = mosq_ms_queued; } } assert(state != mosq_ms_invalid); #ifdef WITH_PERSISTENCE if(state == mosq_ms_queued){ db->persistence_changes++; } #endif msg = _mosquitto_malloc(sizeof(struct mosquitto_client_msg)); if(!msg) return MOSQ_ERR_NOMEM; msg->next = NULL; msg->store = stored; msg->store->ref_count++; msg->mid = mid; msg->timestamp = mosquitto_time(); msg->direction = dir; msg->state = state; msg->dup = false; msg->qos = qos; msg->retain = retain; if(context->last_msg){ context->last_msg->next = msg; context->last_msg = msg; }else{ context->msgs = msg; context->last_msg = msg; } context->msg_count++; if(qos > 0){ context->msg_count12++; } if(db->config->allow_duplicate_messages == false && dir == mosq_md_out && retain == false){ /* Record which client ids this message has been sent to so we can avoid duplicates. * Outgoing messages only. * If retain==true then this is a stale retained message and so should be * sent regardless. FIXME - this does mean retained messages will received * multiple times for overlapping subscriptions, although this is only the * case for SUBSCRIPTION with multiple subs in so is a minor concern. */ dest_ids = _mosquitto_realloc(stored->dest_ids, sizeof(char *)*(stored->dest_id_count+1)); if(dest_ids){ stored->dest_ids = dest_ids; stored->dest_id_count++; stored->dest_ids[stored->dest_id_count-1] = _mosquitto_strdup(context->id); if(!stored->dest_ids[stored->dest_id_count-1]){ return MOSQ_ERR_NOMEM; } }else{ return MOSQ_ERR_NOMEM; } } #ifdef WITH_BRIDGE if(context->bridge && context->bridge->start_type == bst_lazy && context->sock == INVALID_SOCKET && context->msg_count >= context->bridge->threshold){ context->bridge->lazy_reconnect = true; } #endif return rc; }
int _mosquitto_packet_read(struct mosquitto *mosq) #endif { uint8_t byte; ssize_t read_length; int rc = 0; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; if(mosq->state == mosq_cs_connect_pending){ return MOSQ_ERR_SUCCESS; } /* This gets called if pselect() indicates that there is network data * available - ie. at least one byte. What we do depends on what data we * already have. * If we've not got a command, attempt to read one and save it. This should * always work because it's only a single byte. * Then try to read the remaining length. This may fail because it is may * be more than one byte - will need to save data pending next read if it * does fail. * Then try to read the remaining payload, where 'payload' here means the * combined variable header and actual payload. This is the most likely to * fail due to longer length, so save current data and current position. * After all data is read, send to _mosquitto_handle_packet() to deal with. * Finally, free the memory and reset everything to starting conditions. */ if(!mosq->in_packet.command){ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.command = byte; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_bytes_received++; # endif /* Clients must send CONNECT as their first command. */ if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CONNECT) return MOSQ_ERR_PROTOCOL; #endif }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } /* remaining_count is the number of bytes that the remaining_length * parameter occupied in this incoming packet. We don't use it here as such * (it is used when allocating an outgoing packet), but we must be able to * determine whether all of the remaining_length parameter has been read. * remaining_count has three states here: * 0 means that we haven't read any remaining_length bytes * <0 means we have read some remaining_length bytes but haven't finished * >0 means we have finished reading the remaining_length bytes. */ if(mosq->in_packet.remaining_count <= 0){ do{ read_length = _mosquitto_net_read(mosq, &byte, 1); if(read_length == 1){ mosq->in_packet.remaining_count--; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count < -4) return MOSQ_ERR_PROTOCOL; #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received++; #endif mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }else{ if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } }while((byte & 128) != 0); /* We have finished reading remaining_length, so make remaining_count * positive. */ mosq->in_packet.remaining_count *= -1; if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM; mosq->in_packet.to_process = mosq->in_packet.remaining_length; } } while(mosq->in_packet.to_process>0){ read_length = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(read_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_received += read_length; #endif mosq->in_packet.to_process -= read_length; mosq->in_packet.pos += read_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ if(mosq->in_packet.to_process > 1000){ /* Update last_msg_in time if more than 1000 bytes left to * receive. Helps when receiving large messages. * This is an arbitrary limit, but with some consideration. * If a client can't send 1000 bytes in a second it * probably shouldn't be using a 1 second keep alive. */ pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); } return MOSQ_ERR_SUCCESS; }else{ switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_received++; if(((mosq->in_packet.command)&0xF5) == PUBLISH){ g_pub_msgs_received++; } # endif rc = mqtt3_packet_handle(db, mosq); #else rc = _mosquitto_packet_handle(mosq); #endif /* Free data and reset values */ _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); return rc; }
int _mosquitto_handle_publish(struct mosquitto *mosq) { uint8_t header; struct mosquitto_message_all *message; int rc = 0; uint16_t mid; assert(mosq); message = _mosquitto_calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; header = mosq->in_packet.command; message->direction = mosq_md_in; message->dup = (header & 0x08)>>3; message->msg.qos = (header & 0x06)>>1; message->msg.retain = (header & 0x01); rc = _mosquitto_read_string(&mosq->in_packet, &message->msg.topic); if(rc){ _mosquitto_message_cleanup(&message); return rc; } rc = _mosquitto_fix_sub_topic(&message->msg.topic); if(rc){ _mosquitto_message_cleanup(&message); return rc; } if(!strlen(message->msg.topic)){ _mosquitto_message_cleanup(&message); return MOSQ_ERR_PROTOCOL; } if(message->msg.qos > 0){ rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc){ _mosquitto_message_cleanup(&message); return rc; } message->msg.mid = (int)mid; } message->msg.payloadlen = mosq->in_packet.remaining_length - mosq->in_packet.pos; if(message->msg.payloadlen){ message->msg.payload = _mosquitto_calloc(message->msg.payloadlen+1, sizeof(uint8_t)); rc = _mosquitto_read_bytes(&mosq->in_packet, message->msg.payload, message->msg.payloadlen); if(rc){ _mosquitto_message_cleanup(&message); return rc; } } _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, message->dup, message->msg.qos, message->msg.retain, message->msg.mid, message->msg.topic, (long)message->msg.payloadlen); message->timestamp = mosquitto_time(); switch(message->msg.qos){ case 0: pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_message){ mosq->in_callback = true; mosq->on_message(mosq, mosq->userdata, &message->msg); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); _mosquitto_message_cleanup(&message); return MOSQ_ERR_SUCCESS; case 1: rc = _mosquitto_send_puback(mosq, message->msg.mid); pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_message){ mosq->in_callback = true; mosq->on_message(mosq, mosq->userdata, &message->msg); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); _mosquitto_message_cleanup(&message); return rc; case 2: rc = _mosquitto_send_pubrec(mosq, message->msg.mid); message->state = mosq_ms_wait_for_pubrel; pthread_mutex_lock(&mosq->message_mutex); _mosquitto_message_queue(mosq, message, true); pthread_mutex_unlock(&mosq->message_mutex); return rc; default: return MOSQ_ERR_PROTOCOL; } }
/* Send messages for the $SYS hierarchy if the last update is longer than * 'interval' seconds ago. * 'interval' is the amount of seconds between updates. If 0, then no periodic * messages are sent for the $SYS hierarchy. * 'start_time' is the result of time() that the broker was started at. */ void mqtt3_db_sys_update(struct mosquitto_db *db, int interval, time_t start_time) { static time_t last_update = 0; time_t now; time_t uptime; char buf[BUFLEN]; static int msg_store_count = -1; static unsigned long msgs_received = -1; static unsigned long msgs_sent = -1; static unsigned long publish_dropped = -1; static unsigned long pub_msgs_received = -1; static unsigned long pub_msgs_sent = -1; static unsigned long long bytes_received = -1; static unsigned long long bytes_sent = -1; static unsigned long long pub_bytes_received = -1; static unsigned long long pub_bytes_sent = -1; static int subscription_count = -1; static int retained_count = -1; static double msgs_received_load1 = 0; static double msgs_received_load5 = 0; static double msgs_received_load15 = 0; static double msgs_sent_load1 = 0; static double msgs_sent_load5 = 0; static double msgs_sent_load15 = 0; static double publish_dropped_load1 = 0; static double publish_dropped_load5 = 0; static double publish_dropped_load15 = 0; double msgs_received_interval, msgs_sent_interval, publish_dropped_interval; static double publish_received_load1 = 0; static double publish_received_load5 = 0; static double publish_received_load15 = 0; static double publish_sent_load1 = 0; static double publish_sent_load5 = 0; static double publish_sent_load15 = 0; double publish_received_interval, publish_sent_interval; static double bytes_received_load1 = 0; static double bytes_received_load5 = 0; static double bytes_received_load15 = 0; static double bytes_sent_load1 = 0; static double bytes_sent_load5 = 0; static double bytes_sent_load15 = 0; double bytes_received_interval, bytes_sent_interval; static double socket_load1 = 0; static double socket_load5 = 0; static double socket_load15 = 0; double socket_interval; static double connection_load1 = 0; static double connection_load5 = 0; static double connection_load15 = 0; double connection_interval; double exponent; double i_mult; now = mosquitto_time(); if(interval && now - interval > last_update){ uptime = now - start_time; snprintf(buf, BUFLEN, "%d seconds", (int)uptime); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/uptime", 2, strlen(buf), buf, 1); _sys_update_clients(db, buf); if(last_update > 0){ i_mult = 60.0/(double)(now-last_update); msgs_received_interval = (g_msgs_received - msgs_received)*i_mult; msgs_sent_interval = (g_msgs_sent - msgs_sent)*i_mult; publish_dropped_interval = (g_msgs_dropped - publish_dropped)*i_mult; publish_received_interval = (g_pub_msgs_received - pub_msgs_received)*i_mult; publish_sent_interval = (g_pub_msgs_sent - pub_msgs_sent)*i_mult; bytes_received_interval = (g_bytes_received - bytes_received)*i_mult; bytes_sent_interval = (g_bytes_sent - bytes_sent)*i_mult; socket_interval = g_socket_connections*i_mult; g_socket_connections = 0; connection_interval = g_connection_count*i_mult; g_connection_count = 0; /* 1 minute load */ exponent = exp(-1.0*(now-last_update)/60.0); calc_load(db, buf, "$SYS/broker/load/messages/received/1min", exponent, msgs_received_interval, &msgs_received_load1); calc_load(db, buf, "$SYS/broker/load/messages/sent/1min", exponent, msgs_sent_interval, &msgs_sent_load1); calc_load(db, buf, "$SYS/broker/load/publish/dropped/1min", exponent, publish_dropped_interval, &publish_dropped_load1); calc_load(db, buf, "$SYS/broker/load/publish/received/1min", exponent, publish_received_interval, &publish_received_load1); calc_load(db, buf, "$SYS/broker/load/publish/sent/1min", exponent, publish_sent_interval, &publish_sent_load1); calc_load(db, buf, "$SYS/broker/load/bytes/received/1min", exponent, bytes_received_interval, &bytes_received_load1); calc_load(db, buf, "$SYS/broker/load/bytes/sent/1min", exponent, bytes_sent_interval, &bytes_sent_load1); calc_load(db, buf, "$SYS/broker/load/sockets/1min", exponent, socket_interval, &socket_load1); calc_load(db, buf, "$SYS/broker/load/connections/1min", exponent, connection_interval, &connection_load1); /* 5 minute load */ exponent = exp(-1.0*(now-last_update)/300.0); calc_load(db, buf, "$SYS/broker/load/messages/received/5min", exponent, msgs_received_interval, &msgs_received_load5); calc_load(db, buf, "$SYS/broker/load/messages/sent/5min", exponent, msgs_sent_interval, &msgs_sent_load5); calc_load(db, buf, "$SYS/broker/load/publish/dropped/5min", exponent, publish_dropped_interval, &publish_dropped_load5); calc_load(db, buf, "$SYS/broker/load/publish/received/5min", exponent, publish_received_interval, &publish_received_load5); calc_load(db, buf, "$SYS/broker/load/publish/sent/5min", exponent, publish_sent_interval, &publish_sent_load5); calc_load(db, buf, "$SYS/broker/load/bytes/received/5min", exponent, bytes_received_interval, &bytes_received_load5); calc_load(db, buf, "$SYS/broker/load/bytes/sent/5min", exponent, bytes_sent_interval, &bytes_sent_load5); calc_load(db, buf, "$SYS/broker/load/sockets/5min", exponent, socket_interval, &socket_load5); calc_load(db, buf, "$SYS/broker/load/connections/5min", exponent, connection_interval, &connection_load5); /* 15 minute load */ exponent = exp(-1.0*(now-last_update)/900.0); calc_load(db, buf, "$SYS/broker/load/messages/received/15min", exponent, msgs_received_interval, &msgs_received_load15); calc_load(db, buf, "$SYS/broker/load/messages/sent/15min", exponent, msgs_sent_interval, &msgs_sent_load15); calc_load(db, buf, "$SYS/broker/load/publish/dropped/15min", exponent, publish_dropped_interval, &publish_dropped_load15); calc_load(db, buf, "$SYS/broker/load/publish/received/15min", exponent, publish_received_interval, &publish_received_load15); calc_load(db, buf, "$SYS/broker/load/publish/sent/15min", exponent, publish_sent_interval, &publish_sent_load15); calc_load(db, buf, "$SYS/broker/load/bytes/received/15min", exponent, bytes_received_interval, &bytes_received_load15); calc_load(db, buf, "$SYS/broker/load/bytes/sent/15min", exponent, bytes_sent_interval, &bytes_sent_load15); calc_load(db, buf, "$SYS/broker/load/sockets/15min", exponent, socket_interval, &socket_load15); calc_load(db, buf, "$SYS/broker/load/connections/15min", exponent, connection_interval, &connection_load15); } if(db->msg_store_count != msg_store_count){ msg_store_count = db->msg_store_count; snprintf(buf, BUFLEN, "%d", msg_store_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/stored", 2, strlen(buf), buf, 1); } if(db->subscription_count != subscription_count){ subscription_count = db->subscription_count; snprintf(buf, BUFLEN, "%d", subscription_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/subscriptions/count", 2, strlen(buf), buf, 1); } if(db->retained_count != retained_count){ retained_count = db->retained_count; snprintf(buf, BUFLEN, "%d", retained_count); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/retained messages/count", 2, strlen(buf), buf, 1); } #ifdef REAL_WITH_MEMORY_TRACKING _sys_update_memory(db, buf); #endif if(msgs_received != g_msgs_received){ msgs_received = g_msgs_received; snprintf(buf, BUFLEN, "%lu", msgs_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/received", 2, strlen(buf), buf, 1); } if(msgs_sent != g_msgs_sent){ msgs_sent = g_msgs_sent; snprintf(buf, BUFLEN, "%lu", msgs_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/messages/sent", 2, strlen(buf), buf, 1); } if(publish_dropped != g_msgs_dropped){ publish_dropped = g_msgs_dropped; snprintf(buf, BUFLEN, "%lu", publish_dropped); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/dropped", 2, strlen(buf), buf, 1); } if(pub_msgs_received != g_pub_msgs_received){ pub_msgs_received = g_pub_msgs_received; snprintf(buf, BUFLEN, "%lu", pub_msgs_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/received", 2, strlen(buf), buf, 1); } if(pub_msgs_sent != g_pub_msgs_sent){ pub_msgs_sent = g_pub_msgs_sent; snprintf(buf, BUFLEN, "%lu", pub_msgs_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/messages/sent", 2, strlen(buf), buf, 1); } if(bytes_received != g_bytes_received){ bytes_received = g_bytes_received; snprintf(buf, BUFLEN, "%llu", bytes_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/bytes/received", 2, strlen(buf), buf, 1); } if(bytes_sent != g_bytes_sent){ bytes_sent = g_bytes_sent; snprintf(buf, BUFLEN, "%llu", bytes_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/bytes/sent", 2, strlen(buf), buf, 1); } if(pub_bytes_received != g_pub_bytes_received){ pub_bytes_received = g_pub_bytes_received; snprintf(buf, BUFLEN, "%llu", pub_bytes_received); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/received", 2, strlen(buf), buf, 1); } if(pub_bytes_sent != g_pub_bytes_sent){ pub_bytes_sent = g_pub_bytes_sent; snprintf(buf, BUFLEN, "%llu", pub_bytes_sent); mqtt3_db_messages_easy_queue(db, NULL, "$SYS/broker/publish/bytes/sent", 2, strlen(buf), buf, 1); } last_update = mosquitto_time(); } // 大于interval了,就更新订阅信息 }
int mqtt3_bridge_connect(struct mosquitto_db *db, struct mosquitto *context) { int rc; 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 = -1; context->last_msg_in = mosquitto_time(); context->last_msg_out = mosquitto_time(); 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; mqtt3_bridge_packet_cleanup(context); mqtt3_db_message_reconnect_reset(context); if(context->clean_session){ mqtt3_db_messages_delete(context); } rc = mosquitto_unpwd_check(db, context->bridge->local_username, context->bridge->local_password); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Bridge %s failed authentication on local broker.", context->id); return rc; case MOSQ_ERR_UNKNOWN: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Bridge %s returned application error in authorisation.", context->id); return rc; default: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Unknown error in authentication for bridge %s.", context->id); return rc; } /* 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. */ mqtt3_subs_clean_session(db, context, &db->subs); for(i=0; i<context->bridge->topic_count; i++){ if(context->bridge->topics[i].direction == bd_out || context->bridge->topics[i].direction == bd_both){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Bridge %s doing local SUBSCRIBE on topic %s", context->id, context->bridge->topics[i].local_topic); if(mqtt3_sub_add(db, context, context->bridge->topics[i].local_topic, context->bridge->topics[i].qos, &db->subs)) return 1; } } if(context->bridge->notifications){ notification_payload = '0'; if(context->bridge->notification_topic){ mqtt3_db_messages_easy_queue(db, context, context->bridge->notification_topic, 1, 1, ¬ification_payload, 1); rc = _mosquitto_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->id)+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->id); mqtt3_db_messages_easy_queue(db, context, notification_topic, 1, 1, ¬ification_payload, 1); rc = _mosquitto_will_set(context, notification_topic, 1, ¬ification_payload, 1, true); if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_free(notification_topic); return rc; } _mosquitto_free(notification_topic); } } _mosquitto_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 = _mosquitto_socket_connect(context, context->bridge->addresses[context->bridge->cur_address].address, context->bridge->addresses[context->bridge->cur_address].port, NULL, true); if(rc != MOSQ_ERR_SUCCESS){ if(rc == MOSQ_ERR_TLS){ return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } return rc; } rc = _mosquitto_send_connect(context, context->keepalive, context->clean_session); if(rc == MOSQ_ERR_SUCCESS){ return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ return rc; /* Error already printed */ }else if(rc == MOSQ_ERR_ERRNO){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", strerror(errno)); }else if(rc == MOSQ_ERR_EAI){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error creating bridge: %s.", gai_strerror(errno)); } _mosquitto_socket_close(context); 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; 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_packet_write(struct mosquitto *mosq) { ssize_t write_length; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } pthread_mutex_unlock(&mosq->out_packet_mutex); while(mosq->current_out_packet){ packet = mosq->current_out_packet; while(packet->to_process > 0){ write_length = _mosquitto_net_write(mosq, &(packet->payload[packet->pos]), packet->to_process); if(write_length > 0){ #if defined(WITH_BROKER) && defined(WITH_SYS_TREE) g_bytes_sent += write_length; #endif packet->to_process -= write_length; packet->pos += write_length; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; }else{ pthread_mutex_unlock(&mosq->current_out_packet_mutex); switch(errno){ case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } #ifdef WITH_BROKER # ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } # endif #else if(((packet->command)&0xF6) == PUBLISH){ pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_publish){ /* This is a QoS=0 message */ mosq->in_callback = true; mosq->on_publish(mosq, mosq->userdata, packet->mid); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); } #endif /* Free data and reset values */ pthread_mutex_lock(&mosq->out_packet_mutex); mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } pthread_mutex_unlock(&mosq->out_packet_mutex); _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_out = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); } pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; }