int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char **argv; int argc = 1; char *token; char *saveptr = NULL; int rc; argv = _mosquitto_malloc(sizeof(char *)*1); argv[0] = "mosquitto"; token = strtok_r(lpCmdLine, " ", &saveptr); while(token){ argc++; argv = _mosquitto_realloc(argv, sizeof(char *)*argc); if(!argv){ fprintf(stderr, "Error: Out of memory.\n"); return MOSQ_ERR_NOMEM; } argv[argc-1] = token; token = strtok_r(NULL, " ", &saveptr); } rc = main(argc, argv); _mosquitto_free(argv); return rc; }
struct epoll_event* init_events( struct epoll_event* events, int listensock_count, int db_context_count, int* epollfd_count) { if (listensock_count + db_context_count > *epollfd_count){ *epollfd_count = listensock_count + db_context_count; return _mosquitto_realloc ( events, sizeof (struct epoll_event) * *epollfd_count); } else { return events; } }
int mqtt3_bridge_new(mosquitto_db *db, struct _mqtt3_bridge *bridge) { int i; mqtt3_context *new_context = NULL; mqtt3_context **tmp_contexts; assert(db); assert(bridge); new_context = mqtt3_context_init(-1); if(!new_context){ return MOSQ_ERR_NOMEM; } new_context->bridge = bridge; for(i=0; i<db->context_count; i++){ if(db->contexts[i] == NULL){ db->contexts[i] = new_context; break; } } if(i==db->context_count){ db->context_count++; tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(mqtt3_context*)*db->context_count); if(tmp_contexts){ db->contexts = tmp_contexts; db->contexts[db->context_count-1] = new_context; }else{ return MOSQ_ERR_NOMEM; } } /* FIXME - need to check that this name isn't already in use. */ new_context->core.id = _mosquitto_strdup(bridge->name); if(!new_context->core.id){ return MOSQ_ERR_NOMEM; } new_context->core.username = new_context->bridge->username; new_context->core.password = new_context->bridge->password; return mqtt3_bridge_connect(db, new_context); }
static struct mosquitto *_db_find_or_add_context(mosquitto_db *db, const char *client_id, uint16_t last_mid) { struct mosquitto *context; struct mosquitto **tmp_contexts; int i; context = NULL; for(i=0; i<db->context_count; i++){ if(db->contexts[i] && !strcmp(db->contexts[i]->id, client_id)){ context = db->contexts[i]; break; } } if(!context){ context = mqtt3_context_init(-1); context->clean_session = false; for(i=0; i<db->context_count; i++){ if(!db->contexts[i]){ db->contexts[i] = context; break; } } if(i==db->context_count){ db->context_count++; tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*db->context_count); if(tmp_contexts){ db->contexts = tmp_contexts; db->contexts[db->context_count-1] = context; }else{ return NULL; } } context->id = _mosquitto_strdup(client_id); } if(last_mid){ context->last_mid = last_mid; } return context; }
int mqtt3_bridge_new(struct mosquitto_db *db, struct _mqtt3_bridge *bridge) { struct mosquitto *new_context = NULL; struct mosquitto **bridges; char hostname[256]; int len; char *id, *local_id; assert(db); assert(bridge); if(!bridge->remote_clientid){ if(!gethostname(hostname, 256)){ len = strlen(hostname) + strlen(bridge->name) + 2; id = _mosquitto_malloc(len); if(!id){ return MOSQ_ERR_NOMEM; } snprintf(id, len, "%s.%s", hostname, bridge->name); }else{ return 1; } bridge->remote_clientid = id; } if(bridge->local_clientid){ local_id = _mosquitto_strdup(bridge->local_clientid); if(!local_id){ return MOSQ_ERR_NOMEM; } }else{ len = strlen(bridge->remote_clientid) + strlen("local.") + 2; local_id = _mosquitto_malloc(len); if(!local_id){ return MOSQ_ERR_NOMEM; } snprintf(local_id, len, "local.%s", bridge->remote_clientid); bridge->local_clientid = _mosquitto_strdup(local_id); if(!bridge->local_clientid){ _mosquitto_free(local_id); return MOSQ_ERR_NOMEM; } } HASH_FIND(hh_id, db->contexts_by_id, local_id, strlen(local_id), new_context); if(new_context){ /* (possible from persistent db) */ _mosquitto_free(local_id); }else{ /* id wasn't found, so generate a new context */ new_context = mqtt3_context_init(db, -1); if(!new_context){ _mosquitto_free(local_id); return MOSQ_ERR_NOMEM; } new_context->id = local_id; HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, new_context->id, strlen(new_context->id), new_context); } new_context->bridge = bridge; new_context->is_bridge = true; new_context->username = new_context->bridge->remote_username; new_context->password = new_context->bridge->remote_password; #ifdef WITH_TLS new_context->tls_cafile = new_context->bridge->tls_cafile; new_context->tls_capath = new_context->bridge->tls_capath; new_context->tls_certfile = new_context->bridge->tls_certfile; new_context->tls_keyfile = new_context->bridge->tls_keyfile; new_context->tls_cert_reqs = SSL_VERIFY_PEER; new_context->tls_version = new_context->bridge->tls_version; new_context->tls_insecure = new_context->bridge->tls_insecure; #ifdef REAL_WITH_TLS_PSK new_context->tls_psk_identity = new_context->bridge->tls_psk_identity; new_context->tls_psk = new_context->bridge->tls_psk; #endif #endif bridge->try_private_accepted = true; new_context->protocol = bridge->protocol_version; bridges = _mosquitto_realloc(db->bridges, (db->bridge_count+1)*sizeof(struct mosquitto *)); if(bridges){ db->bridges = bridges; db->bridge_count++; db->bridges[db->bridge_count-1] = new_context; }else{ return MOSQ_ERR_NOMEM; } return mqtt3_bridge_connect(db, new_context); }
int mqtt3_socket_accept(struct _mosquitto_db *db, int listensock) { int i; int j; int new_sock = -1; struct mosquitto **tmp_contexts = NULL; struct mosquitto *new_context; int opt = 1; #ifdef WITH_TLS BIO *bio; int rc; #endif #ifdef WITH_WRAP struct request_info wrap_req; #endif new_sock = accept(listensock, NULL, 0); if(new_sock == INVALID_SOCKET) return -1; #ifndef WIN32 /* Set non-blocking */ opt = fcntl(new_sock, F_GETFL, 0); if(opt == -1 || fcntl(new_sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ close(new_sock); return -1; } #else if(ioctlsocket(new_sock, FIONBIO, &opt)){ closesocket(new_sock); return INVALID_SOCKET; } #endif #ifdef WITH_WRAP /* Use tcpd / libwrap to determine whether a connection is allowed. */ request_init(&wrap_req, RQ_FILE, new_sock, RQ_DAEMON, "mosquitto", 0); fromhost(&wrap_req); if(!hosts_access(&wrap_req)){ /* Access is denied */ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection denied access by tcpd."); COMPAT_CLOSE(new_sock); return -1; }else{ #endif new_context = mqtt3_context_init(new_sock); if(!new_context){ COMPAT_CLOSE(new_sock); return -1; } for(i=0; i<db->config->listener_count; i++){ for(j=0; j<db->config->listeners[i].sock_count; j++){ if(db->config->listeners[i].socks[j] == listensock){ new_context->listener = &db->config->listeners[i]; break; } } } if(!new_context->listener){ COMPAT_CLOSE(new_sock); return -1; } if(new_context->listener->max_connections > 0 && new_context->listener->client_count >= new_context->listener->max_connections){ COMPAT_CLOSE(new_sock); return -1; } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s.", new_context->address); for(i=0; i<db->context_count; i++){ if(db->contexts[i] == NULL){ db->contexts[i] = new_context; break; } } if(i==db->context_count){ tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*(db->context_count+1)); if(tmp_contexts){ db->context_count++; db->contexts = tmp_contexts; db->contexts[db->context_count-1] = new_context; }else{ mqtt3_context_cleanup(NULL, new_context, true); } } new_context->listener->client_count++; #ifdef WITH_TLS /* TLS init */ for(i=0; i<db->config->listener_count; i++){ for(j=0; j<db->config->listeners[i].sock_count; j++){ if(db->config->listeners[i].socks[j] == listensock){ if(db->config->listeners[i].ssl_ctx){ new_context->ssl = SSL_new(db->config->listeners[i].ssl_ctx); if(!new_context->ssl){ COMPAT_CLOSE(new_sock); return -1; } SSL_set_ex_data(new_context->ssl, tls_ex_index_context, new_context); SSL_set_ex_data(new_context->ssl, tls_ex_index_listener, &db->config->listeners[i]); new_context->want_read = true; new_context->want_write = true; bio = BIO_new_socket(new_sock, BIO_NOCLOSE); SSL_set_bio(new_context->ssl, bio, bio); rc = SSL_accept(new_context->ssl); if(rc != 1){ rc = SSL_get_error(new_context->ssl, rc); if(rc == SSL_ERROR_WANT_READ){ new_context->want_read = true; }else if(rc == SSL_ERROR_WANT_WRITE){ new_context->want_write = true; } } } } } } #endif #ifdef WITH_WRAP } #endif return new_sock; }
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 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(context->protocol == mosq_p_mqtt311){ if((context->in_packet.command&0x0F) != 0x02){ return MOSQ_ERR_PROTOCOL; } } if(_mosquitto_read_uint16(&context->in_packet, &mid)) return 1; g_epoll_subscribe_num++; 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(!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(mosquitto_sub_topic_check(sub)){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid subscription string from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } 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(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(sub) + 1; sub_mount = _mosquitto_malloc(len+1); 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); sub_mount[len] = '\0'; _mosquitto_free(sub); sub = sub_mount; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); #if 0 /* FIXME * This section has been disabled temporarily. mosquitto_acl_check * calls mosquitto_topic_matches_sub, which can't cope with * checking subscriptions that have wildcards against ACLs that * have wildcards. Bug #1374291 is related. * * It's a very difficult problem when an ACL looks like foo/+/bar * and a subscription request to foo/# is made. * * This should be changed to using MOSQ_ACL_SUBSCRIPTION in the * future anyway. */ if(context->protocol == mosq_p_mqtt311){ rc = mosquitto_acl_check(db, context, sub, MOSQ_ACL_READ); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_ACL_DENIED: qos = 0x80; break; default: _mosquitto_free(sub); return rc; } } #endif if(qos != 0x80){ 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(context->protocol == mosq_p_mqtt311){ if(payloadlen == 0){ /* No subscriptions specified, protocol error. */ return MOSQ_ERR_PROTOCOL; } } if(_mosquitto_send_suback(context, mid, payloadlen, payload)) rc = 1; _mosquitto_free(payload); #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif return rc; }
int mqtt3_bridge_new(struct mosquitto_db *db, struct _mqtt3_bridge *bridge) { int i; struct mosquitto *new_context = NULL; int null_index = -1; struct mosquitto **tmp_contexts; char hostname[256]; int len; char *id; assert(db); assert(bridge); if(bridge->clientid){ id = _mosquitto_strdup(bridge->clientid); }else{ if(!gethostname(hostname, 256)){ len = strlen(hostname) + strlen(bridge->name) + 2; id = _mosquitto_malloc(len); if(!id){ return MOSQ_ERR_NOMEM; } snprintf(id, len, "%s.%s", hostname, bridge->name); }else{ return 1; } } if(!id){ return MOSQ_ERR_NOMEM; } /* Search for existing id (possible from persistent db) and also look for a * gap in the db->contexts[] array in case the id isn't found. */ for(i=0; i<db->context_count; i++){ if(db->contexts[i]){ if(!strcmp(db->contexts[i]->id, id)){ new_context = db->contexts[i]; break; } }else if(db->contexts[i] == NULL && null_index == -1){ null_index = i; break; } } if(!new_context){ /* id wasn't found, so generate a new context */ new_context = mqtt3_context_init(-1); if(!new_context){ return MOSQ_ERR_NOMEM; } if(null_index == -1){ /* There were no gaps in the db->contexts[] array, so need to append. */ db->context_count++; tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*db->context_count); if(tmp_contexts){ db->contexts = tmp_contexts; db->contexts[db->context_count-1] = new_context; }else{ _mosquitto_free(new_context); return MOSQ_ERR_NOMEM; } }else{ db->contexts[null_index] = new_context; } new_context->id = id; }else{ /* id was found, so context->id already in memory. */ _mosquitto_free(id); } new_context->bridge = bridge; new_context->is_bridge = true; new_context->username = new_context->bridge->username; new_context->password = new_context->bridge->password; #ifdef WITH_TLS new_context->tls_cafile = new_context->bridge->tls_cafile; new_context->tls_capath = new_context->bridge->tls_capath; new_context->tls_certfile = new_context->bridge->tls_certfile; new_context->tls_keyfile = new_context->bridge->tls_keyfile; new_context->tls_cert_reqs = SSL_VERIFY_PEER; new_context->tls_version = new_context->bridge->tls_version; new_context->tls_insecure = new_context->bridge->tls_insecure; #ifdef REAL_WITH_TLS_PSK new_context->tls_psk_identity = new_context->bridge->tls_psk_identity; new_context->tls_psk = new_context->bridge->tls_psk; #endif #endif bridge->try_private_accepted = true; return mqtt3_bridge_connect(db, new_context); }
int mosquitto__socks5_read(struct mosquitto *mosq) { ssize_t len; uint8_t *payload; uint8_t i; if(mosq->state == mosq_cs_socks5_start){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } switch(mosq->in_packet.payload[1]){ case SOCKS_AUTH_NONE: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); case SOCKS_AUTH_USERPASS: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_send_userpass; return mosquitto__socks5_send(mosq); default: _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_AUTH; } }else if(mosq->state == mosq_cs_socks5_userpass_reply){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 1){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } return MOSQ_ERR_PROXY; } }else if(mosq->state == mosq_cs_socks5_request){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.packet_length == 5){ /* First part of the packet has been received, we now know what else to expect. */ if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V4){ mosq->in_packet.to_process += 4+2-1; /* 4 bytes IPv4, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 4+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V6){ mosq->in_packet.to_process += 16+2-1; /* 16 bytes IPv6, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 16+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_DOMAINNAME){ if(mosq->in_packet.payload[4] > 0 && mosq->in_packet.payload[4] <= 255){ mosq->in_packet.to_process += mosq->in_packet.payload[4]; mosq->in_packet.packet_length += mosq->in_packet.payload[4]; } }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROTOCOL; } payload = _mosquitto_realloc(mosq->in_packet.payload, mosq->in_packet.packet_length); if(payload){ mosq->in_packet.payload = payload; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_NOMEM; } payload = _mosquitto_realloc(mosq->in_packet.payload, mosq->in_packet.packet_length); if(payload){ mosq->in_packet.payload = payload; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; } /* Entire packet is now read. */ if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ /* Auth passed */ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_new; switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } } }else{ return _mosquitto_packet_read(mosq); } return MOSQ_ERR_SUCCESS; }
int mqtt3_socket_accept(struct mosquitto_db *db, int listensock) { int i; int j; int new_sock = -1; struct mosquitto **tmp_contexts = NULL; struct mosquitto *new_context; int opt = 1; new_sock = accept(listensock, NULL, 0); if(new_sock == INVALID_SOCKET) return -1; #ifdef WITH_SYS_TREE g_socket_connections++; #endif /* Set non-blocking */ opt = fcntl(new_sock, F_GETFL, 0); if(opt == -1 || fcntl(new_sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ close(new_sock); return -1; } //初始化个跟客户端连接的context,里面会设置客户端的IP地址,这里可以考虑不在里面做,accept的时候参数中完成即可 new_context = mqtt3_context_init(new_sock); if(!new_context){ COMPAT_CLOSE(new_sock); return -1; } for(i=0; i<db->config->listener_count; i++){//循环找每一个listeners,找到我是属于哪个listeners.实际上epoll后就不需要这些东西了 for(j=0; j<db->config->listeners[i].sock_count; j++){ if(db->config->listeners[i].socks[j] == listensock){ new_context->listener = &db->config->listeners[i];//指向我所属的listener break; } } } if(!new_context->listener){ COMPAT_CLOSE(new_sock); return -1; } if(new_context->listener->max_connections > 0 && new_context->listener->client_count >= new_context->listener->max_connections){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address); COMPAT_CLOSE(new_sock); return -1; } _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port); for(i=0; i<db->context_count; i++){//找一个空的contexts结构,指向这一个空连接 if(db->contexts[i] == NULL){ db->contexts[i] = new_context; break; } } if(i==db->context_count){//没有了,重新realloc一个,这个代价很大的。所以建议申请2倍,保留一些空余的,到一定程度的时候每次增加32个也行 tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*(db->context_count+1)); if(tmp_contexts){ db->context_count += 1;//暂时改为一次增长32个,不然每次都realloc很恐怖 db->contexts = tmp_contexts;//这样的话,所有人都不能用指向contexts数组某个位置的指针来标识这个连接,比如放到epoll里面去世不行的 db->contexts[i] = new_context; }else{ //到这里,说明contexts[]数组不够了,而且relloac也失败,怎么办,只能丢掉这个连接了。但是下面并没有return -1,而且还去访问了。是个bug // Out of memory mqtt3_context_cleanup(NULL, new_context, true); return -1 ;//必须return,否则下面会core } } // If we got here then the context's DB index is "i" regardless of how we got here new_context->db_index = i; new_context->listener->client_count++; return new_sock; }
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; }
/* Creates a socket and listens on port 'port'. * Returns 1 on failure * Returns 0 on success. */ int mqtt3_socket_listen(struct _mqtt3_listener *listener) { int sock = -1; struct addrinfo hints; struct addrinfo *ainfo, *rp; char service[10]; int opt = 1; int ss_opt = 1; char err[256]; if(!listener) return MOSQ_ERR_INVAL; snprintf(service, 10, "%d", listener->port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; //导致下面返回多个链表节的的因素可能有: //hostname参数关联的地址有多个,那么每个返回一个节点;比如host为域名的时候,nslookup返回几个ip就有几个 //service参数指定的服务会吃多个套接字接口类型,那么也返回多个 if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET; listener->sock_count = 0; listener->socks = NULL; for(rp = ainfo; rp; rp = rp->ai_next){ if(rp->ai_family == AF_INET){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port)); }else if(rp->ai_family == AF_INET6){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port)); }else{ continue; } sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(sock == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: %s", err); continue; } listener->sock_count++; listener->socks = _mosquitto_realloc(listener->socks, sizeof(int)*listener->sock_count); if(!listener->socks){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } listener->socks[listener->sock_count-1] = sock; ss_opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt)); ss_opt = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt)); /* Set non-blocking */ opt = fcntl(sock, F_GETFL, 0); if(opt == -1 || fcntl(sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ COMPAT_CLOSE(sock); return 1; } if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err); COMPAT_CLOSE(sock); return 1; } if(listen(sock, 100) == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err); COMPAT_CLOSE(sock); return 1; } } freeaddrinfo(ainfo); /* We need to have at least one working socket. */ if(listener->sock_count > 0){ return 0; }else{ return 1; } }
int mosquitto_main_loop(struct mosquitto_db *db, int *listensock, int listensock_count, int listener_max) { time_t start_time = time(NULL); time_t last_backup = time(NULL); time_t last_store_clean = time(NULL); time_t now; int fdcount; #ifndef WIN32 sigset_t sigblock, origsig; #endif int i; struct pollfd *pollfds = NULL; int pollfd_count = 0; int pollfd_index; #ifndef WIN32 sigemptyset(&sigblock); sigaddset(&sigblock, SIGINT); #endif while(run){ mqtt3_db_sys_update(db, db->config->sys_interval, start_time); if(listensock_count + db->context_count > pollfd_count){ pollfd_count = listensock_count + db->context_count; pollfds = _mosquitto_realloc(pollfds, sizeof(struct pollfd)*pollfd_count); if(!pollfds){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } } memset(pollfds, -1, sizeof(struct pollfd)*pollfd_count); pollfd_index = 0; for(i=0; i<listensock_count; i++){ pollfds[pollfd_index].fd = listensock[i]; pollfds[pollfd_index].events = POLLIN; pollfds[pollfd_index].revents = 0; pollfd_index++; } now = time(NULL); for(i=0; i<db->context_count; i++){ if(db->contexts[i]){ db->contexts[i]->pollfd_index = -1; if(db->contexts[i]->sock != INVALID_SOCKET){ #ifdef WITH_BRIDGE if(db->contexts[i]->bridge){ _mosquitto_check_keepalive(db->contexts[i]); } #endif /* Local bridges never time out in this fashion. */ if(!(db->contexts[i]->keepalive) || db->contexts[i]->bridge || now - db->contexts[i]->last_msg_in < (time_t)(db->contexts[i]->keepalive)*3/2){ if(mqtt3_db_message_write(db->contexts[i]) == MOSQ_ERR_SUCCESS){ pollfds[pollfd_index].fd = db->contexts[i]->sock; pollfds[pollfd_index].events = POLLIN | POLLRDHUP; pollfds[pollfd_index].revents = 0; if(db->contexts[i]->out_packet){ pollfds[pollfd_index].events |= POLLOUT; } db->contexts[i]->pollfd_index = pollfd_index; pollfd_index++; }else{ mqtt3_context_disconnect(db, db->contexts[i]); } }else{ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Client %s has exceeded timeout, disconnecting.", db->contexts[i]->id); } /* Client has exceeded keepalive*1.5 */ mqtt3_context_disconnect(db, db->contexts[i]); } }else{ #ifdef WITH_BRIDGE if(db->contexts[i]->bridge){ /* Want to try to restart the bridge connection */ if(!db->contexts[i]->bridge->restart_t){ db->contexts[i]->bridge->restart_t = time(NULL)+db->contexts[i]->bridge->restart_timeout; }else{ if(db->contexts[i]->bridge->start_type == bst_automatic && time(NULL) > db->contexts[i]->bridge->restart_t){ db->contexts[i]->bridge->restart_t = 0; if(mqtt3_bridge_connect(db, db->contexts[i]) == MOSQ_ERR_SUCCESS){ pollfds[pollfd_index].fd = db->contexts[i]->sock; pollfds[pollfd_index].events = POLLIN | POLLRDHUP; pollfds[pollfd_index].revents = 0; if(db->contexts[i]->out_packet){ pollfds[pollfd_index].events |= POLLOUT; } db->contexts[i]->pollfd_index = pollfd_index; pollfd_index++; }else{ /* Retry later. */ db->contexts[i]->bridge->restart_t = time(NULL)+db->contexts[i]->bridge->restart_timeout; } } } }else{ #endif if(db->contexts[i]->clean_session == true){ mqtt3_context_cleanup(db, db->contexts[i], true); db->contexts[i] = NULL; }else if(db->config->persistent_client_expiration > 0){ /* This is a persistent client, check to see if the * last time it connected was longer than * persistent_client_expiration seconds ago. If so, * expire it and clean up. */ if(time(NULL) > db->contexts[i]->disconnect_t+db->config->persistent_client_expiration){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "Expiring persistent client %s due to timeout.", db->contexts[i]->id); g_clients_expired++; db->contexts[i]->clean_session = true; mqtt3_context_cleanup(db, db->contexts[i], true); db->contexts[i] = NULL; } } #ifdef WITH_BRIDGE } #endif } } } mqtt3_db_message_timeout_check(db, db->config->retry_interval); #ifndef WIN32 sigprocmask(SIG_SETMASK, &sigblock, &origsig); fdcount = poll(pollfds, pollfd_index, 100); sigprocmask(SIG_SETMASK, &origsig, NULL); #else fdcount = WSAPoll(pollfds, pollfd_index, 100); #endif if(fdcount == -1){ loop_handle_errors(db, pollfds); }else{ loop_handle_reads_writes(db, pollfds); for(i=0; i<listensock_count; i++){ if(pollfds[i].revents & (POLLIN | POLLPRI)){ while(mqtt3_socket_accept(db, listensock[i]) != -1){ } } } } #ifdef WITH_PERSISTENCE if(db->config->persistence && db->config->autosave_interval){ if(db->config->autosave_on_changes){ if(db->persistence_changes > db->config->autosave_interval){ mqtt3_db_backup(db, false, false); db->persistence_changes = 0; } }else{ if(last_backup + db->config->autosave_interval < now){ mqtt3_db_backup(db, false, false); last_backup = time(NULL); } } } #endif if(!db->config->store_clean_interval || last_store_clean + db->config->store_clean_interval < now){ mqtt3_db_store_clean(db); last_store_clean = time(NULL); } #ifdef WITH_PERSISTENCE if(flag_db_backup){ mqtt3_db_backup(db, false, false); flag_db_backup = false; } #endif if(flag_reload){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Reloading config."); mqtt3_config_read(db->config, true); mosquitto_security_cleanup(db, true); mosquitto_security_init(db, true); mosquitto_security_apply(db); mqtt3_log_init(db->config->log_type, db->config->log_dest); flag_reload = false; } if(flag_tree_print){ mqtt3_sub_tree_print(&db->subs, 0); flag_tree_print = false; } } if(pollfds) _mosquitto_free(pollfds); return MOSQ_ERR_SUCCESS; }
/* Creates a socket and listens on port 'port'. * Returns 1 on failure * Returns 0 on success. */ int mqtt3_socket_listen(struct _mqtt3_listener *listener) { int sock = -1; struct addrinfo hints; struct addrinfo *ainfo, *rp; char service[10]; int opt = 1; #ifndef WIN32 int ss_opt = 1; #else char ss_opt = 1; #endif #ifdef WITH_TLS int rc; X509_STORE *store; X509_LOOKUP *lookup; #endif char err[256]; if(!listener) return MOSQ_ERR_INVAL; snprintf(service, 10, "%d", listener->port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET; listener->sock_count = 0; listener->socks = NULL; for(rp = ainfo; rp; rp = rp->ai_next){ if(rp->ai_family == AF_INET){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port)); }else if(rp->ai_family == AF_INET6){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port)); }else{ continue; } sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(sock == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: %s", err); continue; } listener->sock_count++; listener->socks = _mosquitto_realloc(listener->socks, sizeof(int)*listener->sock_count); if(!listener->socks){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } listener->socks[listener->sock_count-1] = sock; #ifndef WIN32 ss_opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt)); #endif ss_opt = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt)); #ifndef WIN32 /* Set non-blocking */ opt = fcntl(sock, F_GETFL, 0); if(opt == -1 || fcntl(sock, F_SETFL, opt | O_NONBLOCK) == -1){ /* If either fcntl fails, don't want to allow this client to connect. */ COMPAT_CLOSE(sock); return 1; } #else if(ioctlsocket(sock, FIONBIO, &opt)){ COMPAT_CLOSE(sock); return 1; } #endif if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err); COMPAT_CLOSE(sock); return 1; } if(listen(sock, 100) == -1){ strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s", err); COMPAT_CLOSE(sock); return 1; } } freeaddrinfo(ainfo); /* We need to have at least one working socket. */ if(listener->sock_count > 0){ #ifdef WITH_TLS if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){ listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); if(!listener->ssl_ctx){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context."); COMPAT_CLOSE(sock); return 1; } if(listener->ciphers){ rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers); COMPAT_CLOSE(sock); return 1; } } rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath); if(rc == 0){ if(listener->cafile && listener->capath){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath); }else if(listener->cafile){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath); } COMPAT_CLOSE(sock); return 1; } /* FIXME user data? */ if(listener->require_certificate){ SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, client_certificate_verify); }else{ SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER, client_certificate_verify); } rc = SSL_CTX_use_certificate_file(listener->ssl_ctx, listener->certfile, SSL_FILETYPE_PEM); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile); COMPAT_CLOSE(sock); return 1; } rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile); COMPAT_CLOSE(sock); return 1; } rc = SSL_CTX_check_private_key(listener->ssl_ctx); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent."); COMPAT_CLOSE(sock); return 1; } /* Load CRLs if they exist. */ if(listener->crlfile){ store = SSL_CTX_get_cert_store(listener->ssl_ctx); if(!store){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store."); COMPAT_CLOSE(sock); return 1; } lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM); if(rc != 1){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile); COMPAT_CLOSE(sock); return 1; } X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); } # ifdef WITH_TLS_PSK }else if(listener->psk_hint){ if(tls_ex_index_context == -1){ tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL); } if(tls_ex_index_listener == -1){ tls_ex_index_listener = SSL_get_ex_new_index(0, "listener", NULL, NULL, NULL); } listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); if(!listener->ssl_ctx){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context."); COMPAT_CLOSE(sock); return 1; } SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback); if(listener->psk_hint){ rc = SSL_CTX_use_psk_identity_hint(listener->ssl_ctx, listener->psk_hint); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint."); COMPAT_CLOSE(sock); return 1; } } if(listener->ciphers){ rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers); if(rc == 0){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers); COMPAT_CLOSE(sock); return 1; } } # endif /* WITH_TLS_PSK */ } #endif /* WITH_TLS */ return 0; }else{ return 1; } }
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;//SUB的返回包为SUBACK,结构为每一行代表对应的一个topic的QOS 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){ //SUBSCRIBE消息包括msgid,后面就是topic的列表,一个个取就行 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)){//1个byte的QOS,高位6为空 _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)){//把重复的斜杠去掉://////some//aa// -> some/aa/ _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); //将当前的这个topic挂到订阅树里面,树的每一层为路径的一段,树的subs代表订阅的客户端链表,children代表子分支链表 rc2 = mqtt3_sub_add(db, context, sub, qos, &db->subs); if(rc2 == MOSQ_ERR_SUCCESS){//订阅成功了 //下面需要检查一下这个topic上面是不是有retain保留消息需要发送给这个客户端,里面又会处理一遍订阅树,其实可以合并一起处理嘛 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);//释放这个原始的字符串a/b/c tmp_payload = _mosquitto_realloc(payload, payloadlen + 1); if(tmp_payload){//这是要返回给客户端的QOS列表,一一对应 payload = tmp_payload; payload[payloadlen] = qos;//QOS级别不变?如果本身的topic的级别不够的话怎么办 payloadlen++; }else{ if(payload) _mosquitto_free(payload); return MOSQ_ERR_NOMEM; } //搞定一条订阅消息,在订阅的topic上已经记录了这个连接,并且payload[]上面也增加了对应连接的qos准备返回 } } //发送SUBACK回包 if(_mosquitto_send_suback(context, mid, payloadlen, payload)) rc = 1; _mosquitto_free(payload); #ifdef WITH_PERSISTENCE db->persistence_changes++; #endif return rc; }
int main(int argc, char *argv[]) { int *listensock = NULL; int listensock_count = 0; int listensock_index = 0; struct mqtt3_config config; char buf[1024]; int i, j; FILE *pid; int listener_max; int rc; char err[256]; #ifdef WIN32 SYSTEMTIME st; #else struct timeval tv; #endif #if defined(WIN32) || defined(__CYGWIN__) if(argc == 2){ if(!strcmp(argv[1], "run")){ service_run(); return 0; }else if(!strcmp(argv[1], "install")){ service_install(); return 0; }else if(!strcmp(argv[1], "uninstall")){ service_uninstall(); return 0; } } #endif #ifdef WIN32 GetSystemTime(&st); srand(st.wSecond + st.wMilliseconds); #else gettimeofday(&tv, NULL); srand(tv.tv_sec + tv.tv_usec); #endif memset(&int_db, 0, sizeof(struct mosquitto_db)); _mosquitto_net_init(); mqtt3_config_init(&config); rc = mqtt3_config_parse_args(&config, argc, argv); if(rc != MOSQ_ERR_SUCCESS) return rc; int_db.config = &config; if(config.daemon){ #ifndef WIN32 switch(fork()){ case 0: break; case -1: strerror_r(errno, err, 256); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error in fork: %s", err); return 1; default: return MOSQ_ERR_SUCCESS; } #else _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Can't start in daemon mode in Windows."); #endif } if(config.daemon && config.pid_file){ pid = _mosquitto_fopen(config.pid_file, "wt"); if(pid){ fprintf(pid, "%d", getpid()); fclose(pid); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Unable to write pid file."); return 1; } } rc = drop_privileges(&config); if(rc != MOSQ_ERR_SUCCESS) return rc; rc = mqtt3_db_open(&config, &int_db); if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Couldn't open database."); return rc; } /* Initialise logging only after initialising the database in case we're * logging to topics */ mqtt3_log_init(config.log_type, config.log_dest); _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s (build date %s) starting", VERSION, TIMESTAMP); if(config.config_file){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Config loaded from %s.", config.config_file); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Using default config."); } rc = mosquitto_security_module_init(&int_db); if(rc) return rc; rc = mosquitto_security_init(&int_db, false); if(rc) return rc; #ifdef WITH_SYS_TREE if(config.sys_interval > 0){ /* Set static $SYS messages */ snprintf(buf, 1024, "mosquitto version %s", VERSION); mqtt3_db_messages_easy_queue(&int_db, NULL, "$SYS/broker/version", 2, strlen(buf), buf, 1); snprintf(buf, 1024, "%s", TIMESTAMP); mqtt3_db_messages_easy_queue(&int_db, NULL, "$SYS/broker/timestamp", 2, strlen(buf), buf, 1); #ifdef CHANGESET snprintf(buf, 1024, "%s", CHANGESET); mqtt3_db_messages_easy_queue(&int_db, NULL, "$SYS/broker/changeset", 2, strlen(buf), buf, 1); #endif } #endif listener_max = -1; listensock_index = 0; for(i=0; i<config.listener_count; i++){ if(mqtt3_socket_listen(&config.listeners[i])){ _mosquitto_free(int_db.contexts); mqtt3_db_close(&int_db); if(config.pid_file){ remove(config.pid_file); } return 1; } listensock_count += config.listeners[i].sock_count; listensock = _mosquitto_realloc(listensock, sizeof(int)*listensock_count); if(!listensock){ _mosquitto_free(int_db.contexts); mqtt3_db_close(&int_db); if(config.pid_file){ remove(config.pid_file); } return 1; } for(j=0; j<config.listeners[i].sock_count; j++){ if(config.listeners[i].socks[j] == INVALID_SOCKET){ _mosquitto_free(int_db.contexts); mqtt3_db_close(&int_db); if(config.pid_file){ remove(config.pid_file); } return 1; } listensock[listensock_index] = config.listeners[i].socks[j]; if(listensock[listensock_index] > listener_max){ listener_max = listensock[listensock_index]; } listensock_index++; } } signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); #ifdef SIGHUP signal(SIGHUP, handle_sighup); #endif #ifndef WIN32 signal(SIGUSR1, handle_sigusr1); signal(SIGUSR2, handle_sigusr2); signal(SIGPIPE, SIG_IGN); #endif #ifdef WITH_BRIDGE for(i=0; i<config.bridge_count; i++){ if(mqtt3_bridge_new(&int_db, &(config.bridges[i]))){ _mosquitto_log_printf(NULL, MOSQ_LOG_WARNING, "Warning: Unable to connect to bridge %s.", config.bridges[i].name); } } #endif run = 1; rc = mosquitto_main_loop(&int_db, listensock, listensock_count, listener_max); _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s terminating", VERSION); mqtt3_log_close(); #ifdef WITH_PERSISTENCE if(config.persistence){ mqtt3_db_backup(&int_db, true, true); } #endif for(i=0; i<int_db.context_count; i++){ if(int_db.contexts[i]){ mqtt3_context_cleanup(&int_db, int_db.contexts[i], true); } } _mosquitto_free(int_db.contexts); int_db.contexts = NULL; mqtt3_db_close(&int_db); if(listensock){ for(i=0; i<listensock_count; i++){ if(listensock[i] != INVALID_SOCKET){ #ifndef WIN32 close(listensock[i]); #else closesocket(listensock[i]); #endif } } _mosquitto_free(listensock); } mosquitto_security_module_cleanup(&int_db); if(config.pid_file){ remove(config.pid_file); } _mosquitto_net_cleanup(); mqtt3_config_cleanup(int_db.config); return rc; }
int mqtt3_handle_subscribe(mosquitto_db *db, mqtt3_context *context) { int rc = 0; uint16_t mid; char *sub; uint8_t qos; uint8_t *payload = NULL; uint32_t payloadlen = 0; if(!context) return 1; mqtt3_log_printf(MOSQ_LOG_DEBUG, "Received SUBSCRIBE from %s", context->core.id); /* FIXME - plenty of potential for memory leaks here */ if(_mosquitto_read_uint16(&context->core.in_packet, &mid)) return 1; while(context->core.in_packet.pos < context->core.in_packet.remaining_length){ sub = NULL; if(_mosquitto_read_string(&context->core.in_packet, &sub)){ if(sub) _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(sub){ if(_mosquitto_read_byte(&context->core.in_packet, &qos)){ _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } if(qos > 2){ mqtt3_log_printf(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)){ mqtt3_log_printf(MOSQ_LOG_INFO, "Empty subscription string from %s, disconnecting.", context->address); _mosquitto_free(sub); if(payload) _mosquitto_free(payload); return 1; } mqtt3_log_printf(MOSQ_LOG_DEBUG, "\t%s (QoS %d)", sub, qos); mqtt3_sub_add(context, sub, qos, &db->subs); if(mqtt3_retain_queue(db, context, sub, qos)) rc = 1; _mosquitto_free(sub); } payload = _mosquitto_realloc(payload, payloadlen + 1); payload[payloadlen] = qos; payloadlen++; } if(mqtt3_raw_suback(context, mid, payloadlen, payload)) rc = 1; _mosquitto_free(payload); return rc; }
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 rc; int slen; #ifdef WITH_SYS_TREE g_connection_count++; #endif /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){//已经connect过了 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)){//协议名必须为"MQIsdp" 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; }//协议名只是为了检验是否为"MQIsdp"的,只后就没用啦 _mosquitto_free(protocol_name); if(_mosquitto_read_byte(&context->in_packet, &protocol_version)){//8 个字节的协议号 mqtt3_context_disconnect(db, context); return 1; } if((protocol_version&0x7F) != PROTOCOL_VERSION){//协议名必须是3版本 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){//发送这种协议来的,就认为是bridge 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; context->clean_session = clean_session; context->ping_t = 0; if(_mosquitto_read_uint16(&context->in_packet, &(context->keepalive))){ mqtt3_context_disconnect(db, context); return 1; } //客户端ID是必须有的,flags无法控制 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; } context->id = client_id; client_id = NULL; /* clientid_prefixes check */ if(db->config->clientid_prefixes){//如果配置文件配置了客户端统一前缀clientid_prefixes,那么所有客户端昵称必须一致 if(strncmp(db->config->clientid_prefixes, context->id, strlen(db->config->clientid_prefixes))){ _mosquitto_send_connack(context, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); return MOSQ_ERR_SUCCESS; } } if(will){//will指的是如果客户端意外断开连接,那么will Message内容的字符串消息会发布到Will Topic指代的地方 //申请一个message结构,待会填充到context->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; } //由于需要记录长度,所以不能一次读取_mosquitto_read_string if(_mosquitto_read_uint16(&context->in_packet, &will_payloadlen)){ mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; } 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; } //设置will-topic的相关信息,mqtt3_context_disconnect会用,判断连接不是主动断开的话会Publis一条消息 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; will_struct = NULL ;//设置为空,避免handle_connect_error释放。放到context上面后续释放即可 context->will->topic = will_topic; will_topic = NULL ; if(will_payload){ context->will->payload = will_payload; context->will->payloadlen = will_payloadlen; will_payload = NULL ; }else{ context->will->payload = NULL; context->will->payloadlen = 0; } context->will->qos = will_qos; context->will->retain = will_retain; } 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; } } context->username = username; context->password = password; username = NULL; /* Avoid free() in error: below. */ password = NULL; if(username_flag && password_flag){//如果发送了用户名密码,那么进行用户名密码校验 //放入待验证的客户端链表头部 struct _mosquitto_auth_list * tmpauth = _mosquitto_calloc(1, sizeof(struct _mosquitto_auth_list)); if(tmpauth == NULL){ _mosquitto_send_connack(context, CONNACK_REFUSED_SERVER_UNAVAILABLE); mqtt3_context_disconnect(db, context); rc = MOSQ_ERR_SUCCESS; goto handle_connect_error; } context->auth_result = CONNACK_REFUSED_NOT_AUTHORIZED ; pthread_mutex_lock(&db->auth_list_mutex) ; tmpauth->context = context ; tmpauth->next = db->waiting_auth_list ;//如果db->waiting_auth_list为空这里也可以没事的 assert( context->sock != -1) ; db->waiting_auth_list = tmpauth; db->contexts[context->db_index] = NULL ;//暂时将这个链接从contexts中移除出来,待验证完成后,放入finished_auth_list context->db_index = -1 ; pthread_mutex_unlock(&db->auth_list_mutex) ; //rc = mosquitto_unpwd_check(db, context->username, context->password); return MOSQ_ERR_SUCCESS ; } //查看系统是否允许匿名使用 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; } //没有用户名,那么OK,继续后面的处理 rc = mqtt3_handle_post_check_unpwd( db, context) ; return rc ; 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 try_wakeup_finished_auth_connections( struct mosquitto_db *db ){ int i=0, dbidx = 0 ; struct _mosquitto_auth_list * tofree = NULL; pthread_mutex_lock(&db->auth_list_mutex) ; struct _mosquitto_auth_list * tmpauth = db->finished_auth_list ; db->finished_auth_list = NULL ; while( tmpauth ){ //将链表每个元素还原到contexts数组里面 assert(tmpauth->context->sock != -1); for(i = dbidx ; i < db->context_count; i++){ if(db->contexts[i] == NULL){ db->contexts[i] = tmpauth->context ; break ; } } if( i == db->context_count){ struct mosquitto **tmp_contexts = NULL; tmp_contexts = _mosquitto_realloc(db->contexts, sizeof(struct mosquitto*)*(db->context_count+1)); if(tmp_contexts){ db->context_count += 1; db->contexts = tmp_contexts; db->contexts[i] = tmpauth->context; }else{ //到这里,说明contexts[]数组不够了,而且relloac也失败,怎么办,只能丢掉这个连接了。但是下面并没有return -1,而且还去访问了。是个bug // Out of memory mqtt3_context_cleanup(NULL, tmpauth->context, true); tmpauth = tmpauth->next ; continue ; } } //已经将这个连接放到contexts数组了。下面需要完成验证的后面部分 db->contexts[i]->db_index = i ; mqtt3_handle_post_check_unpwd(db, db->contexts[i]) ; dbidx = i+1 ; tofree = tmpauth ; tmpauth = tmpauth->next ; _mosquitto_free( tofree ) ; } pthread_mutex_unlock(&db->auth_list_mutex) ; return MOSQ_ERR_SUCCESS ; }