int _mosquitto_log_printf(struct mosquitto *mosq, int priority, const char *fmt, ...) { va_list va; char *s; int len; assert(mosq); assert(fmt); pthread_mutex_lock(&mosq->log_callback_mutex); if(mosq->on_log){ len = (int)strlen(fmt) + 500; s = _mosquitto_malloc(len*sizeof(char)); if(!s){ pthread_mutex_unlock(&mosq->log_callback_mutex); return MOSQ_ERR_NOMEM; } va_start(va, fmt); vsnprintf(s, len, fmt, va); va_end(va); s[len-1] = '\0'; /* Ensure string is null terminated. */ mosq->on_log(mosq, mosq->userdata, priority, s); _mosquitto_free(s); } pthread_mutex_unlock(&mosq->log_callback_mutex); return MOSQ_ERR_SUCCESS; }
int _mosquitto_packet_alloc(struct _mosquitto_packet *packet) { uint8_t remaining_bytes[5], byte; uint32_t remaining_length; int i; assert(packet); remaining_length = packet->remaining_length; packet->payload = NULL; packet->remaining_count = 0; do{ byte = remaining_length % 128; remaining_length = remaining_length / 128; /* If there are more digits to encode, set the top bit of this digit */ if(remaining_length > 0){ byte = byte | 0x80; } remaining_bytes[packet->remaining_count] = byte; packet->remaining_count++; }while(remaining_length > 0 && packet->remaining_count < 5); if(packet->remaining_count == 5) return MOSQ_ERR_PAYLOAD_SIZE; packet->packet_length = packet->remaining_length + 1 + packet->remaining_count; packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); if(!packet->payload) return MOSQ_ERR_NOMEM; packet->payload[0] = packet->command; for(i=0; i<packet->remaining_count; i++){ packet->payload[i+1] = remaining_bytes[i]; } packet->pos = 1 + packet->remaining_count; return MOSQ_ERR_SUCCESS; }
int _mosquitto_handle_suback(struct mosquitto *mosq) { uint16_t mid; uint8_t *granted_qos; int qos_count; int i = 0; int rc; assert(mosq); _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Received SUBACK"); rc = _mosquitto_read_uint16(&mosq->core.in_packet, &mid); if(rc) return rc; qos_count = mosq->core.in_packet.remaining_length - mosq->core.in_packet.pos; granted_qos = _mosquitto_malloc(qos_count*sizeof(uint8_t)); if(!granted_qos) return MOSQ_ERR_NOMEM; while(mosq->core.in_packet.pos < mosq->core.in_packet.remaining_length){ rc = _mosquitto_read_byte(&mosq->core.in_packet, &(granted_qos[i])); if(rc){ _mosquitto_free(granted_qos); return rc; } i++; } if(mosq->on_subscribe){ mosq->on_subscribe(mosq->obj, mid, qos_count, granted_qos); } _mosquitto_free(granted_qos); return MOSQ_ERR_SUCCESS; }
static int _sub_add(struct mosquitto_db *db, struct mosquitto *context, int qos, struct _mosquitto_subhier *subhier, struct _sub_token *tokens) { struct _mosquitto_subhier *branch, *last = NULL; struct _mosquitto_subleaf *leaf, *last_leaf; if(!tokens){ if(context){ leaf = subhier->subs; last_leaf = NULL; while(leaf){ if(!strcmp(leaf->context->id, context->id)){ /* Client making a second subscription to same topic. Only * need to update QoS. Return -1 to indicate this to the * calling function. */ leaf->qos = qos; return -1; } last_leaf = leaf; leaf = leaf->next; } leaf = _mosquitto_malloc(sizeof(struct _mosquitto_subleaf)); if(!leaf) return MOSQ_ERR_NOMEM; leaf->next = NULL; leaf->context = context; leaf->qos = qos; if(last_leaf){ last_leaf->next = leaf; leaf->prev = last_leaf; }else{ subhier->subs = leaf; leaf->prev = NULL; } db->subscription_count++; } return MOSQ_ERR_SUCCESS; } branch = subhier->children; while(branch){ if(!strcmp(branch->topic, tokens->topic)){ return _sub_add(db, context, qos, branch, tokens->next); } last = branch; branch = branch->next; } /* Not found */ branch = _mosquitto_calloc(1, sizeof(struct _mosquitto_subhier)); if(!branch) return MOSQ_ERR_NOMEM; branch->topic = _mosquitto_strdup(tokens->topic); if(!branch->topic){ _mosquitto_free(branch); return MOSQ_ERR_NOMEM; } if(!last){ subhier->children = branch; }else{ last->next = branch; } return _sub_add(db, context, qos, branch, tokens->next); }
int _mosquitto_log_printf(struct mosquitto *mosq, int priority, const char *fmt, ...) { va_list va; char *s; int len; assert(mosq); assert(fmt); if((mosq->log_priorities & priority) && mosq->log_destinations != MOSQ_LOG_NONE){ len = strlen(fmt) + 500; s = _mosquitto_malloc(len*sizeof(char)); if(!s) return MOSQ_ERR_NOMEM; va_start(va, fmt); vsnprintf(s, len, fmt, va); va_end(va); s[len-1] = '\0'; /* Ensure string is null terminated. */ if(mosq->log_destinations & MOSQ_LOG_STDOUT){ fprintf(stdout, "%s\n", s); fflush(stdout); } if(mosq->log_destinations & MOSQ_LOG_STDERR){ fprintf(stderr, "%s\n", s); fflush(stderr); } _mosquitto_free(s); } return MOSQ_ERR_SUCCESS; }
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; }
int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { struct mosquitto_message_all *message; uint16_t local_mid; if(!mosq || !topic || qos<0 || qos>2) return MOSQ_ERR_INVAL; if(strlen(topic) == 0) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(_mosquitto_topic_wildcard_len_check(topic) != MOSQ_ERR_SUCCESS) { return MOSQ_ERR_INVAL; } //获取总共发送信息数,并加1返回 local_mid = _mosquitto_mid_generate(mosq); if(mid) { *mid = local_mid; } if(qos == 0) { return _mosquitto_send_publish(mosq, local_mid, topic, payloadlen, payload, qos, retain, false); } else { message = _mosquitto_calloc(1, sizeof(struct mosquitto_message_all)); if(!message) return MOSQ_ERR_NOMEM; message->next = NULL; message->timestamp = time(NULL); message->direction = mosq_md_out; if(qos == 1) { message->state = mosq_ms_wait_puback; } else if(qos == 2) { message->state = mosq_ms_wait_pubrec; } message->msg.mid = local_mid; message->msg.topic = _mosquitto_strdup(topic); if(!message->msg.topic) { _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } if(payloadlen) { message->msg.payloadlen = payloadlen; message->msg.payload = _mosquitto_malloc(payloadlen*sizeof(uint8_t)); if(!message->msg.payload) { _mosquitto_message_cleanup(&message); return MOSQ_ERR_NOMEM; } memcpy(message->msg.payload, payload, payloadlen*sizeof(uint8_t)); } else { message->msg.payloadlen = 0; message->msg.payload = NULL; } message->msg.qos = qos; message->msg.retain = retain; message->dup = false; _mosquitto_message_queue(mosq, message); return _mosquitto_send_publish(mosq, message->msg.mid, message->msg.topic, message->msg.payloadlen, message->msg.payload, message->msg.qos, message->msg.retain, message->dup); } }
int _mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain) { int rc = MOSQ_ERR_SUCCESS; if(!mosq || !topic) return MOSQ_ERR_INVAL; if(payloadlen < 0 || payloadlen > MQTT_MAX_PAYLOAD) return MOSQ_ERR_PAYLOAD_SIZE; if(payloadlen > 0 && !payload) return MOSQ_ERR_INVAL; if(mosquitto_pub_topic_check(topic)) return MOSQ_ERR_INVAL; if(mosq->will){ if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; } mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!mosq->will) return MOSQ_ERR_NOMEM; mosq->will->topic = _mosquitto_strdup(topic); if(!mosq->will->topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } mosq->will->payloadlen = payloadlen; if(mosq->will->payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } mosq->will->payload = _mosquitto_malloc(sizeof(char)*mosq->will->payloadlen); if(!mosq->will->payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } memcpy(mosq->will->payload, payload, payloadlen); } mosq->will->qos = qos; mosq->will->retain = retain; return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ if(mosq->will->topic) _mosquitto_free(mosq->will->topic); if(mosq->will->payload) _mosquitto_free(mosq->will->payload); } _mosquitto_free(mosq->will); mosq->will = NULL; return rc; }
int _mosquitto_will_set(struct mosquitto *mosq, bool will, const char *topic, uint32_t payloadlen, const uint8_t *payload, int qos, bool retain) { int rc = MOSQ_ERR_SUCCESS; if(!mosq || (will && !topic)) return MOSQ_ERR_INVAL; if(payloadlen > 268435455) return MOSQ_ERR_PAYLOAD_SIZE; if(mosq->will){ if(mosq->will->topic){ _mosquitto_free(mosq->will->topic); mosq->will->topic = NULL; } if(mosq->will->payload){ _mosquitto_free(mosq->will->payload); mosq->will->payload = NULL; } _mosquitto_free(mosq->will); mosq->will = NULL; } if(will){ mosq->will = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!mosq->will) return MOSQ_ERR_NOMEM; mosq->will->topic = _mosquitto_strdup(topic); if(!mosq->will->topic){ rc = MOSQ_ERR_NOMEM; goto cleanup; } mosq->will->payloadlen = payloadlen; if(mosq->will->payloadlen > 0){ if(!payload){ rc = MOSQ_ERR_INVAL; goto cleanup; } mosq->will->payload = _mosquitto_malloc(sizeof(uint8_t)*mosq->will->payloadlen); if(!mosq->will->payload){ rc = MOSQ_ERR_NOMEM; goto cleanup; } memcpy(mosq->will->payload, payload, payloadlen); } mosq->will->qos = qos; mosq->will->retain = retain; } return MOSQ_ERR_SUCCESS; cleanup: if(mosq->will){ if(mosq->will->topic) _mosquitto_free(mosq->will->topic); if(mosq->will->payload) _mosquitto_free(mosq->will->payload); } _mosquitto_free(mosq->will); mosq->will = NULL; return rc; }
int mosquitto_connect_srv(struct mosquitto *mosq, const char *host, int keepalive, const char *bind_address) { #ifdef WITH_SRV char *h; int rc; if(!mosq) return MOSQ_ERR_INVAL; rc = ares_init(&mosq->achan); if(rc != ARES_SUCCESS){ return MOSQ_ERR_UNKNOWN; } if(!host){ // get local domain }else{ #ifdef WITH_TLS if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk){ h = _mosquitto_malloc(strlen(host) + strlen("_secure-mqtt._tcp.") + 1); if(!h) return MOSQ_ERR_NOMEM; sprintf(h, "_secure-mqtt._tcp.%s", host); }else{ #endif h = _mosquitto_malloc(strlen(host) + strlen("_mqtt._tcp.") + 1); if(!h) return MOSQ_ERR_NOMEM; sprintf(h, "_mqtt._tcp.%s", host); #ifdef WITH_TLS } #endif ares_search(mosq->achan, h, ns_c_in, ns_t_srv, srv_callback, mosq); _mosquitto_free(h); } pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_connect_srv; pthread_mutex_unlock(&mosq->state_mutex); mosq->keepalive = keepalive; return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif }
int mqtt3_sub_add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, struct _mosquitto_subhier *root) { int rc = 0; struct _mosquitto_subhier *subhier, *child; struct _sub_token *tokens = NULL, *tail; assert(root); assert(sub); if(_sub_topic_tokenise(sub, &tokens)) return 1; subhier = root->children; while(subhier){ if(!strcmp(subhier->topic, tokens->topic)){ rc = _sub_add(db, context, qos, subhier, tokens); break; } subhier = subhier->next; } if(!subhier){ child = _mosquitto_malloc(sizeof(struct _mosquitto_subhier)); if(!child){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->topic = _mosquitto_strdup(tokens->topic); if(!child->topic){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } child->subs = NULL; child->children = NULL; child->retained = NULL; if(db->subs.children){ child->next = db->subs.children; }else{ child->next = NULL; } db->subs.children = child; rc = _sub_add(db, context, qos, child, tokens); } while(tokens){ tail = tokens->next; _mosquitto_free(tokens->topic); _mosquitto_free(tokens); tokens = tail; } /* We aren't worried about -1 (already subscribed) return codes. */ if(rc == -1) rc = MOSQ_ERR_SUCCESS; return rc; }
mqtt3_context *mqtt3_context_init(int sock) { mqtt3_context *context; struct sockaddr_storage addr; socklen_t addrlen; char address[1024]; context = _mosquitto_malloc(sizeof(mqtt3_context)); if(!context) return NULL; context->core.state = mosq_cs_new; context->duplicate = false; context->core.sock = sock; context->core.last_msg_in = time(NULL); context->core.last_msg_out = time(NULL); context->core.keepalive = 60; /* Default to 60s */ context->clean_session = true; context->core.id = NULL; context->core.last_mid = 0; context->core.will = NULL; context->core.username = NULL; context->core.password = NULL; context->core.in_packet.payload = NULL; _mosquitto_packet_cleanup(&context->core.in_packet); context->core.out_packet = NULL; addrlen = sizeof(addr); context->address = NULL; if(!getpeername(sock, (struct sockaddr *)&addr, &addrlen)){ if(addr.ss_family == AF_INET){ if(inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr.s_addr, address, 1024)){ context->address = _mosquitto_strdup(address); } }else if(addr.ss_family == AF_INET6){ if(inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, address, 1024)){ context->address = _mosquitto_strdup(address); } } } context->bridge = NULL; context->msgs = NULL; return context; }
int mosquitto_ssl_set(struct mosquitto *mosq, const char *pemfile, const char *password) { #ifdef WITH_SSL if(!mosq || mosq->ssl) return MOSQ_ERR_INVAL; //FIXME mosq->ssl = _mosquitto_malloc(sizeof(struct _mosquitto_ssl)); if(!mosq->ssl) return MOSQ_ERR_NOMEM; mosq->ssl->ssl_ctx = SSL_CTX_new(TLSv1_method()); if(!mosq->ssl->ssl_ctx) return MOSQ_ERR_SSL; mosq->ssl->ssl = SSL_new(mosq->ssl->ssl_ctx); return MOSQ_ERR_SUCCESS; #else return MOSQ_ERR_NOT_SUPPORTED; #endif }
int _mosquitto_handle_suback(struct mosquitto *mosq) { uint16_t mid; uint8_t qos; int *granted_qos; int qos_count; int i = 0; int rc; assert(mosq); #ifdef WITH_BROKER _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Received SUBACK from %s", mosq->id); #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s received SUBACK1", mosq->id); #endif rc = _mosquitto_read_uint16(&mosq->in_packet, &mid); if(rc) return rc; qos_count = mosq->in_packet.remaining_length - mosq->in_packet.pos; granted_qos = _mosquitto_malloc(qos_count*sizeof(int)); if(!granted_qos) return MOSQ_ERR_NOMEM; while(mosq->in_packet.pos < mosq->in_packet.remaining_length){ rc = _mosquitto_read_byte(&mosq->in_packet, &qos); if(rc){ _mosquitto_free(granted_qos); return rc; } granted_qos[i] = (int)qos; i++; } #ifndef WITH_BROKER pthread_mutex_lock(&mosq->callback_mutex); if(mosq->on_subscribe){ mosq->in_callback = true; mosq->on_subscribe(mosq, mosq->userdata, mid, qos_count, granted_qos); mosq->in_callback = false; } pthread_mutex_unlock(&mosq->callback_mutex); #endif _mosquitto_free(granted_qos); return MOSQ_ERR_SUCCESS; }
int _mosquitto_read_string(struct _mosquitto_packet *packet, char **str) { uint16_t len; int rc; assert(packet); rc = _mosquitto_read_uint16(packet, &len); if(rc) return rc; if(packet->pos+len > packet->remaining_length) return MOSQ_ERR_PROTOCOL; *str = _mosquitto_malloc(len+1); if(*str){ memcpy(*str, &(packet->payload[packet->pos]), len); (*str)[len] = '\0'; packet->pos += len; }else{ return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; }
int mosquitto_message_copy(struct mosquitto_message *dst, const struct mosquitto_message *src) { if(!dst || !src) return MOSQ_ERR_INVAL; dst->mid = src->mid; dst->topic = _mosquitto_strdup(src->topic); if(!dst->topic) return MOSQ_ERR_NOMEM; dst->qos = src->qos; dst->retain = src->retain; if(src->payloadlen){ dst->payload = _mosquitto_malloc(src->payloadlen); if(!dst->payload){ _mosquitto_free(dst->topic); return MOSQ_ERR_NOMEM; } memcpy(dst->payload, src->payload, src->payloadlen); dst->payloadlen = src->payloadlen; }else{ dst->payloadlen = 0; dst->payload = NULL; } return MOSQ_ERR_SUCCESS; }
/* Function called when started as a service. */ void __stdcall service_main(DWORD dwArgc, LPTSTR *lpszArgv) { char **argv; int argc = 1; char conf_path[MAX_PATH + 20]; int rc; service_handle = RegisterServiceCtrlHandler("mosquitto", service_handler); if(service_handle){ rc = GetEnvironmentVariable("MOSQUITTO_DIR", conf_path, MAX_PATH); if(!rc || rc == MAX_PATH){ service_status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(service_handle, &service_status); return; } strcat(conf_path, "/mosquitto.conf"); argv = _mosquitto_malloc(sizeof(char *)*3); argv[0] = "mosquitto"; argv[1] = "-c"; argv[2] = conf_path; argc = 3; service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwCurrentState = SERVICE_RUNNING; service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; service_status.dwWin32ExitCode = NO_ERROR; service_status.dwCheckPoint = 0; SetServiceStatus(service_handle, &service_status); main(argc, argv); _mosquitto_free(argv); service_status.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(service_handle, &service_status); } }
static int _db_subs_retain_write(mosquitto_db *db, FILE *db_fptr, struct _mosquitto_subhier *node, const char *topic) { struct _mosquitto_subhier *subhier; struct _mosquitto_subleaf *sub; char *thistopic; uint32_t length; uint16_t i16temp; dbid_t i64temp; int slen; slen = strlen(topic) + strlen(node->topic) + 2; thistopic = _mosquitto_malloc(sizeof(char)*slen); if(!thistopic) return MOSQ_ERR_NOMEM; if(strlen(topic)){ snprintf(thistopic, slen, "%s/%s", topic, node->topic); }else{ snprintf(thistopic, slen, "%s", node->topic); } sub = node->subs; while(sub){ if(sub->context->clean_session == false){ length = htonl(2+strlen(sub->context->id) + 2+strlen(thistopic) + sizeof(uint8_t)); i16temp = htons(DB_CHUNK_SUB); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); slen = strlen(sub->context->id); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, sub->context->id, slen); slen = strlen(thistopic); i16temp = htons(slen); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, thistopic, slen); write_e(db_fptr, &sub->qos, sizeof(uint8_t)); } sub = sub->next; } if(node->retained){ length = htonl(sizeof(dbid_t)); i16temp = htons(DB_CHUNK_RETAIN); write_e(db_fptr, &i16temp, sizeof(uint16_t)); write_e(db_fptr, &length, sizeof(uint32_t)); i64temp = node->retained->db_id; write_e(db_fptr, &i64temp, sizeof(dbid_t)); } subhier = node->children; while(subhier){ _db_subs_retain_write(db, db_fptr, subhier, thistopic); subhier = subhier->next; } _mosquitto_free(thistopic); return MOSQ_ERR_SUCCESS; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); return 1; }
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_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 mqtt3_handle_connect(struct mosquitto_db *db, struct mosquitto *context) { char *protocol_name = NULL; uint8_t protocol_version; uint8_t connect_flags; uint8_t connect_ack = 0; char *client_id = NULL; char *will_payload = NULL, *will_topic = NULL; char *will_topic_mount; uint16_t will_payloadlen; struct mosquitto_message *will_struct = NULL; uint8_t will, will_retain, will_qos, clean_session; uint8_t username_flag, password_flag; char *username = NULL, *password = NULL; int rc; struct _mosquitto_acl_user *acl_tail; struct mosquitto_client_msg *msg_tail, *msg_prev; struct mosquitto *found_context; int slen; struct _mosquitto_subleaf *leaf; int i; #ifdef WITH_TLS X509 *client_cert = NULL; X509_NAME *name; X509_NAME_ENTRY *name_entry; #endif #ifdef WITH_SYS_TREE g_connection_count++; #endif g_epoll_mqtt_connections++; /* Don't accept multiple CONNECT commands. */ if(context->state != mosq_cs_new){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &protocol_name)){ rc = 1; goto handle_connect_error; return 1; } if(!protocol_name){ rc = 3; goto handle_connect_error; return 3; } if(_mosquitto_read_byte(&context->in_packet, &protocol_version)){ rc = 1; goto handle_connect_error; return 1; } if(!strcmp(protocol_name, PROTOCOL_NAME_v31)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v31){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt31; }else if(!strcmp(protocol_name, PROTOCOL_NAME_v311)){ if((protocol_version&0x7F) != PROTOCOL_VERSION_v311){ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol version %d in CONNECT from %s.", protocol_version, context->address); } _mosquitto_send_connack(context, 0, CONNACK_REFUSED_PROTOCOL_VERSION); _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } if((context->in_packet.command&0x0F) != 0x00){ /* Reserved flags not set to 0, must disconnect. */ _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } context->protocol = mosq_p_mqtt311; }else{ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid protocol \"%s\" in CONNECT from %s.", protocol_name, context->address); } _mosquitto_free(protocol_name); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } _mosquitto_free(protocol_name); if(_mosquitto_read_byte(&context->in_packet, &connect_flags)){ rc = 1; goto handle_connect_error; } clean_session = (connect_flags & 0x02) >> 1; will = connect_flags & 0x04; will_qos = (connect_flags & 0x18) >> 3; if(will_qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid Will QoS in CONNECT from %s.", context->address); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } will_retain = connect_flags & 0x20; password_flag = connect_flags & 0x40; username_flag = connect_flags & 0x80; if(_mosquitto_read_uint16(&context->in_packet, &(context->keepalive))){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &client_id)){ rc = 1; goto handle_connect_error; } slen = strlen(client_id); if(slen == 0){ if(context->protocol == mosq_p_mqtt31){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ /* mqtt311 */ _mosquitto_free(client_id); client_id = NULL; if(clean_session == 0 || db->config->allow_zero_length_clientid == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_IDENTIFIER_REJECTED); rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; }else{ client_id = client_id_gen(db); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } } } } /* clientid_prefixes check */ if(db->config->clientid_prefixes){ if(strncmp(db->config->clientid_prefixes, client_id, strlen(db->config->clientid_prefixes))){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } if(will){ will_struct = _mosquitto_calloc(1, sizeof(struct mosquitto_message)); if(!will_struct){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } if(_mosquitto_read_string(&context->in_packet, &will_topic)){ rc = 1; goto handle_connect_error; } if(STREMPTY(will_topic)){ rc = 1; goto handle_connect_error; } if(context->listener && context->listener->mount_point){ slen = strlen(context->listener->mount_point) + strlen(will_topic); will_topic_mount = _mosquitto_malloc(slen+1); if(!will_topic_mount){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } snprintf(will_topic_mount, slen, "%s%s", context->listener->mount_point, will_topic); will_topic_mount[slen] = '\0'; _mosquitto_free(will_topic); will_topic = will_topic_mount; } if(mosquitto_pub_topic_check(will_topic)){ rc = 1; goto handle_connect_error; } if(_mosquitto_read_uint16(&context->in_packet, &will_payloadlen)){ rc = 1; goto handle_connect_error; } if(will_payloadlen > 0){ will_payload = _mosquitto_malloc(will_payloadlen); if(!will_payload){ rc = 1; goto handle_connect_error; } rc = _mosquitto_read_bytes(&context->in_packet, will_payload, will_payloadlen); if(rc){ rc = 1; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(will_qos != 0 || will_retain != 0){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } if(username_flag){ rc = _mosquitto_read_string(&context->in_packet, &username); if(rc == MOSQ_ERR_SUCCESS){ if(password_flag){ rc = _mosquitto_read_string(&context->in_packet, &password); if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else if(rc == MOSQ_ERR_PROTOCOL){ if(context->protocol == mosq_p_mqtt31){ /* Password flag given, but no password. Ignore. */ password_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } }else if(rc == MOSQ_ERR_NOMEM){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; }else{ if(context->protocol == mosq_p_mqtt31){ /* Username flag given, but no username. Ignore. */ username_flag = 0; }else if(context->protocol == mosq_p_mqtt311){ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } }else{ if(context->protocol == mosq_p_mqtt311){ if(password_flag){ /* username_flag == 0 && password_flag == 1 is forbidden */ rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } } } #ifdef WITH_TLS if(context->listener && context->listener->ssl_ctx && context->listener->use_identity_as_username){ if(!context->ssl){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } #ifdef REAL_WITH_TLS_PSK if(context->listener->psk_hint){ /* Client should have provided an identity to get this far. */ if(!context->username){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } }else{ #endif /* REAL_WITH_TLS_PSK */ client_cert = SSL_get_peer_certificate(context->ssl); if(!client_cert){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name = X509_get_subject_name(client_cert); if(!name){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); if(i == -1){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_BAD_USERNAME_PASSWORD); rc = 1; goto handle_connect_error; } name_entry = X509_NAME_get_entry(name, i); context->username = _mosquitto_strdup((char *)ASN1_STRING_data(name_entry->value)); if(!context->username){ rc = 1; goto handle_connect_error; } X509_free(client_cert); client_cert = NULL; #ifdef REAL_WITH_TLS_PSK } #endif /* REAL_WITH_TLS_PSK */ }else{ #endif /* WITH_TLS */ if(username_flag){ rc = mosquitto_unpwd_check(db, username, password); switch(rc){ case MOSQ_ERR_SUCCESS: break; case MOSQ_ERR_AUTH: _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; default: mqtt3_context_disconnect(db, context); rc = 1; goto handle_connect_error; break; } context->username = username; context->password = password; username = NULL; /* Avoid free() in error: below. */ password = NULL; } if(!username_flag && db->config->allow_anonymous == false){ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } #ifdef WITH_TLS } #endif if(context->listener && context->listener->use_username_as_clientid){ if(context->username){ _mosquitto_free(client_id); client_id = _mosquitto_strdup(context->username); if(!client_id){ rc = MOSQ_ERR_NOMEM; goto handle_connect_error; } }else{ _mosquitto_send_connack(context, 0, CONNACK_REFUSED_NOT_AUTHORIZED); rc = 1; goto handle_connect_error; } } /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND(hh_id, db->contexts_by_id, client_id, strlen(client_id), found_context); if(found_context){ /* Found a matching client */ if(found_context->sock == INVALID_SOCKET){ /* Client is reconnecting after a disconnect */ /* FIXME - does anything need to be done here? */ }else{ /* Client is already connected, disconnect old version. This is * done in mqtt3_context_cleanup() below. */ if(db->config->connection_messages == true){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Client %s already connected, closing old connection.", client_id); } } if(context->protocol == mosq_p_mqtt311){ if(clean_session == 0){ connect_ack |= 0x01; } } context->clean_session = clean_session; if(context->clean_session == false && found_context->clean_session == false){ if(found_context->msgs){ context->msgs = found_context->msgs; found_context->msgs = NULL; mqtt3_db_message_reconnect_reset(db, context); } context->subs = found_context->subs; found_context->subs = NULL; context->sub_count = found_context->sub_count; found_context->sub_count = 0; for(i=0; i<context->sub_count; i++){ if(context->subs[i]){ leaf = context->subs[i]->subs; while(leaf){ if(leaf->context == found_context){ leaf->context = context; } leaf = leaf->next; } } } } found_context->clean_session = true; found_context->state = mosq_cs_disconnecting; if(g_flag_epoll) { epoll_do_disconnect(db,found_context); } else { do_disconnect(db, found_context); } } /* Associate user with its ACL, assuming we have ACLs loaded. */ if(db->acl_list){ acl_tail = db->acl_list; while(acl_tail){ if(context->username){ if(acl_tail->username && !strcmp(context->username, acl_tail->username)){ context->acl_list = acl_tail; break; } }else{ if(acl_tail->username == NULL){ context->acl_list = acl_tail; break; } } acl_tail = acl_tail->next; } }else{ context->acl_list = NULL; } if(will_struct){ context->will = will_struct; context->will->topic = will_topic; if(will_payload){ context->will->payload = will_payload; context->will->payloadlen = will_payloadlen; }else{ context->will->payload = NULL; context->will->payloadlen = 0; } context->will->qos = will_qos; context->will->retain = will_retain; } if(db->config->connection_messages == true){ if(context->is_bridge){ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New bridge connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } }else{ if(context->username){ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d, u'%s').", context->address, client_id, clean_session, context->keepalive, context->username); }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_NOTICE, "New client connected from %s as %s (c%d, k%d).", context->address, client_id, clean_session, context->keepalive); } } } context->id = client_id; client_id = NULL; context->clean_session = clean_session; context->ping_t = 0; context->is_dropping = false; if((protocol_version&0x80) == 0x80){ context->is_bridge = true; } /* Remove any queued messages that are no longer allowed through ACL, * assuming a possible change of username. */ msg_tail = context->msgs; msg_prev = NULL; while(msg_tail){ if(msg_tail->direction == mosq_md_out){ if(mosquitto_acl_check(db, context, msg_tail->store->topic, MOSQ_ACL_READ) != MOSQ_ERR_SUCCESS){ mosquitto__db_msg_store_deref(db, &msg_tail->store); if(msg_prev){ msg_prev->next = msg_tail->next; _mosquitto_free(msg_tail); msg_tail = msg_prev->next; }else{ context->msgs = context->msgs->next; _mosquitto_free(msg_tail); msg_tail = context->msgs; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } }else{ msg_prev = msg_tail; msg_tail = msg_tail->next; } } HASH_ADD_KEYPTR(hh_id, db->contexts_by_id, context->id, strlen(context->id), context); #ifdef WITH_PERSISTENCE if(!clean_session){ db->persistence_changes++; } #endif context->state = mosq_cs_connected; return _mosquitto_send_connack(context, connect_ack, CONNACK_ACCEPTED); handle_connect_error: if(client_id) _mosquitto_free(client_id); if(username) _mosquitto_free(username); if(password) _mosquitto_free(password); if(will_payload) _mosquitto_free(will_payload); if(will_topic) _mosquitto_free(will_topic); if(will_struct) _mosquitto_free(will_struct); #ifdef WITH_TLS if(client_cert) X509_free(client_cert); #endif /* We return an error here which means the client is freed later on. */ return rc; }
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 _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_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_send_publish(struct mosquitto *mosq, uint16_t mid, const char *topic, uint32_t payloadlen, const void *payload, int qos, bool retain, bool dup) { #ifdef WITH_BROKER size_t len; #ifdef WITH_BRIDGE int i; struct _mqtt3_bridge_topic *cur_topic; bool match; int rc; char *mapped_topic = NULL; char *topic_temp = NULL; #endif #endif assert(mosq); assert(topic); #if defined(WITH_BROKER) && defined(WITH_WEBSOCKETS) if(mosq->sock == INVALID_SOCKET && !mosq->wsi) return MOSQ_ERR_NO_CONN; #else if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN; #endif #ifdef WITH_BROKER if(mosq->listener && mosq->listener->mount_point){ len = strlen(mosq->listener->mount_point); if(len < strlen(topic)){ topic += len; }else{ /* Invalid topic string. Should never happen, but silently swallow the message anyway. */ return MOSQ_ERR_SUCCESS; } } #ifdef WITH_BRIDGE if(mosq->bridge && mosq->bridge->topics && mosq->bridge->topic_remapping){ for(i=0; i<mosq->bridge->topic_count; i++){ cur_topic = &mosq->bridge->topics[i]; if((cur_topic->direction == bd_both || cur_topic->direction == bd_out) && (cur_topic->remote_prefix || cur_topic->local_prefix)){ /* Topic mapping required on this topic if the message matches */ rc = mosquitto_topic_matches_sub(cur_topic->local_topic, topic, &match); if(rc){ return rc; } if(match){ mapped_topic = _mosquitto_strdup(topic); if(!mapped_topic) return MOSQ_ERR_NOMEM; if(cur_topic->local_prefix){ /* This prefix needs removing. */ if(!strncmp(cur_topic->local_prefix, mapped_topic, strlen(cur_topic->local_prefix))){ topic_temp = _mosquitto_strdup(mapped_topic+strlen(cur_topic->local_prefix)); _mosquitto_free(mapped_topic); if(!topic_temp){ return MOSQ_ERR_NOMEM; } mapped_topic = topic_temp; } } if(cur_topic->remote_prefix){ /* This prefix needs adding. */ len = strlen(mapped_topic) + strlen(cur_topic->remote_prefix)+1; topic_temp = _mosquitto_malloc(len+1); if(!topic_temp){ _mosquitto_free(mapped_topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->remote_prefix, mapped_topic); cur_topic->remote_prefix[len] = '\0'; _mosquitto_free(mapped_topic); mapped_topic = topic_temp; } _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, mapped_topic, (long)payloadlen); #ifdef WITH_SYS_TREE g_pub_bytes_sent += payloadlen; #endif rc = _mosquitto_send_real_publish(mosq, mid, mapped_topic, payloadlen, payload, qos, retain, dup); _mosquitto_free(mapped_topic); return rc; } } } } #endif _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Sending PUBLISH to %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes)) payload is %s", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen, payload); # ifdef WITH_SYS_TREE g_pub_bytes_sent += payloadlen; # endif #else _mosquitto_log_printf(mosq, MOSQ_LOG_DEBUG, "Client %s sending PUBLISH (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", mosq->id, dup, qos, retain, mid, topic, (long)payloadlen); #endif return _mosquitto_send_real_publish(mosq, mid, topic, payloadlen, payload, qos, retain, dup); }
int mosquitto__socks5_send(struct mosquitto *mosq) { struct _mosquitto_packet *packet; int slen; int ulen, plen; if(mosq->state == mosq_cs_socks5_new){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; if(mosq->socks5_username){ packet->packet_length = 4; }else{ packet->packet_length = 3; } packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); packet->payload[0] = 0x05; if(mosq->socks5_username){ packet->payload[1] = 2; packet->payload[2] = SOCKS_AUTH_NONE; packet->payload[3] = SOCKS_AUTH_USERPASS; }else{ packet->payload[1] = 1; packet->payload[2] = SOCKS_AUTH_NONE; } pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_start; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 2; mosq->in_packet.to_process = 2; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*2); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); }else if(mosq->state == mosq_cs_socks5_auth_ok){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; packet->packet_length = (int)(7 + strlen(mosq->host)); packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); slen = (int)strlen(mosq->host); packet->payload[0] = 0x05; packet->payload[1] = 1; packet->payload[2] = 0; packet->payload[3] = SOCKS_ATYPE_DOMAINNAME; packet->payload[4] = slen; memcpy(&(packet->payload[5]), mosq->host, slen); packet->payload[5+slen] = MOSQ_MSB(mosq->port); packet->payload[6+slen] = MOSQ_LSB(mosq->port); pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_request; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 5; mosq->in_packet.to_process = 5; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*5); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); }else if(mosq->state == mosq_cs_socks5_send_userpass){ packet = _mosquitto_calloc(1, sizeof(struct _mosquitto_packet)); if(!packet) return MOSQ_ERR_NOMEM; ulen = (int)strlen(mosq->socks5_username); plen = (int)strlen(mosq->socks5_password); packet->packet_length = 3 + ulen + plen; packet->payload = _mosquitto_malloc(sizeof(uint8_t)*packet->packet_length); packet->payload[0] = 0x01; packet->payload[1] = ulen; memcpy(&(packet->payload[2]), mosq->socks5_username, ulen); packet->payload[2+ulen] = plen; memcpy(&(packet->payload[3+ulen]), mosq->socks5_password, plen); pthread_mutex_lock(&mosq->state_mutex); mosq->state = mosq_cs_socks5_userpass_reply; pthread_mutex_unlock(&mosq->state_mutex); mosq->in_packet.pos = 0; mosq->in_packet.packet_length = 2; mosq->in_packet.to_process = 2; mosq->in_packet.payload = _mosquitto_malloc(sizeof(uint8_t)*2); if(!mosq->in_packet.payload){ _mosquitto_free(packet->payload); _mosquitto_free(packet); return MOSQ_ERR_NOMEM; } return _mosquitto_packet_queue(mosq, packet); } 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; }
static int _db_msg_store_chunk_restore(mosquitto_db *db, FILE *db_fptr) { dbid_t i64temp, store_id; uint32_t i32temp, payloadlen; uint16_t i16temp, slen, source_mid, mid; uint8_t qos, retain, *payload = NULL; char *source_id = NULL; char *topic = NULL; int rc = 0; struct mosquitto_msg_store *stored = NULL; read_e(db_fptr, &i64temp, sizeof(dbid_t)); store_id = i64temp; read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ source_id = _mosquitto_calloc(slen+1, sizeof(char)); if(!source_id){ fclose(db_fptr); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(source_id, 1, slen, db_fptr) != slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); return 1; } } read_e(db_fptr, &i16temp, sizeof(uint16_t)); source_mid = ntohs(i16temp); read_e(db_fptr, &i16temp, sizeof(uint16_t)); mid = ntohs(i16temp); read_e(db_fptr, &i16temp, sizeof(uint16_t)); slen = ntohs(i16temp); if(slen){ topic = _mosquitto_calloc(slen+1, sizeof(char)); if(!topic){ fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(topic, 1, slen, db_fptr) != slen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); return 1; } }else{ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Invalid msg_store chunk when restoring persistent database."); fclose(db_fptr); _mosquitto_free(source_id); return 1; } read_e(db_fptr, &qos, sizeof(uint8_t)); read_e(db_fptr, &retain, sizeof(uint8_t)); read_e(db_fptr, &i32temp, sizeof(uint32_t)); payloadlen = ntohl(i32temp); if(payloadlen){ payload = _mosquitto_malloc(payloadlen); if(!payload){ fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); return MOSQ_ERR_NOMEM; } if(fread(payload, 1, payloadlen, db_fptr) != payloadlen){ _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); fclose(db_fptr); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_free(payload); return 1; } } rc = mqtt3_db_message_store(db, source_id, source_mid, topic, qos, payloadlen, payload, retain, &stored, store_id); _mosquitto_free(source_id); _mosquitto_free(topic); _mosquitto_free(payload); return rc; error: _mosquitto_log_printf(NULL, MOSQ_LOG_ERR, "Error: %s.", strerror(errno)); if(db_fptr) fclose(db_fptr); if(source_id) _mosquitto_free(source_id); if(topic) _mosquitto_free(topic); return 1; }
int 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 mqtt3_handle_publish(struct mosquitto_db *db, struct mosquitto *context) { char *topic; void *payload = NULL; uint32_t payloadlen; uint8_t dup, qos, retain; uint16_t mid = 0; int rc = 0; uint8_t header = context->in_packet.command; int res = 0; struct mosquitto_msg_store *stored = NULL; int len; char *topic_mount; #ifdef WITH_BRIDGE char *topic_temp; int i; struct _mqtt3_bridge_topic *cur_topic; bool match; #endif dup = (header & 0x08)>>3; qos = (header & 0x06)>>1; if(qos == 3){ _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Invalid QoS in PUBLISH from %s, disconnecting.", context->id); return 1; } retain = (header & 0x01); if(_mosquitto_read_string(&context->in_packet, &topic)) return 1; if(STREMPTY(topic)){ /* Invalid publish topic, disconnect client. */ _mosquitto_free(topic); return 1; } #ifdef WITH_BRIDGE if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ for(i=0; i<context->bridge->topic_count; i++){ cur_topic = &context->bridge->topics[i]; if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) && (cur_topic->remote_prefix || cur_topic->local_prefix)){ /* Topic mapping required on this topic if the message matches */ rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, topic, &match); if(rc){ _mosquitto_free(topic); return rc; } if(match){ if(cur_topic->remote_prefix){ /* This prefix needs removing. */ if(!strncmp(cur_topic->remote_prefix, topic, strlen(cur_topic->remote_prefix))){ topic_temp = _mosquitto_strdup(topic+strlen(cur_topic->remote_prefix)); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } _mosquitto_free(topic); topic = topic_temp; } } if(cur_topic->local_prefix){ /* This prefix needs adding. */ len = strlen(topic) + strlen(cur_topic->local_prefix)+1; topic_temp = _mosquitto_malloc(len+1); if(!topic_temp){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, topic); topic_temp[len] = '\0'; _mosquitto_free(topic); topic = topic_temp; } break; } } } } #endif if(mosquitto_pub_topic_check(topic) != MOSQ_ERR_SUCCESS){ /* Invalid publish topic, just swallow it. */ _mosquitto_free(topic); return 1; } if(qos > 0){ if(_mosquitto_read_uint16(&context->in_packet, &mid)){ _mosquitto_free(topic); return 1; } } payloadlen = context->in_packet.remaining_length - context->in_packet.pos; #ifdef WITH_SYS_TREE g_pub_bytes_received += payloadlen; #endif if(context->listener && context->listener->mount_point){ len = strlen(context->listener->mount_point) + strlen(topic) + 1; topic_mount = _mosquitto_malloc(len+1); if(!topic_mount){ _mosquitto_free(topic); return MOSQ_ERR_NOMEM; } snprintf(topic_mount, len, "%s%s", context->listener->mount_point, topic); topic_mount[len] = '\0'; _mosquitto_free(topic); topic = topic_mount; } if(payloadlen){ if(db->config->message_size_limit && payloadlen > db->config->message_size_limit){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Dropped too large PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", context->id, dup, qos, retain, mid, topic, (long)payloadlen); goto process_bad_message; } payload = _mosquitto_calloc(payloadlen+1, 1); if(!payload){ _mosquitto_free(topic); return 1; } if(_mosquitto_read_bytes(&context->in_packet, payload, payloadlen)){ _mosquitto_free(topic); _mosquitto_free(payload); return 1; } } /* Check for topic access */ rc = mosquitto_acl_check(db, context, topic, MOSQ_ACL_WRITE); if(rc == MOSQ_ERR_ACL_DENIED){ _mosquitto_log_printf(NULL, MOSQ_LOG_DEBUG, "Denied PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes))", context->id, dup, qos, retain, mid, topic, (long)payloadlen); goto process_bad_message; }else if(rc != MOSQ_ERR_SUCCESS){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; } _mosquitto_log_printf(NULL, MOSQ_LOG_INFO, "Received PUBLISH from %s (d%d, q%d, r%d, m%d, '%s', ... (%ld bytes) payload %s)", context->id, dup, qos, retain, mid, topic, (long)payloadlen, (char *)payload); //Prathamesh write(pipeFDS[1],payload, payloadlen); if(qos > 0){ mqtt3_db_message_store_find(context, mid, &stored); } if(!stored){ dup = 0; if(mqtt3_db_message_store(db, context->id, mid, topic, qos, payloadlen, payload, retain, &stored, 0)){ _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return 1; } }else{ dup = 1; } switch(qos){ case 0: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, &stored)) rc = 1; break; case 1: if(mqtt3_db_messages_queue(db, context->id, topic, qos, retain, &stored)) rc = 1; if(_mosquitto_send_puback(context, mid)) rc = 1; break; case 2: if(!dup){ res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, retain, stored); }else{ res = 0; } /* mqtt3_db_message_insert() returns 2 to indicate dropped message * due to queue. This isn't an error so don't disconnect them. */ if(!res){ if(_mosquitto_send_pubrec(context, mid)) rc = 1; }else if(res == 1){ rc = 1; } break; } _mosquitto_free(topic); if(payload) _mosquitto_free(payload); return rc; process_bad_message: _mosquitto_free(topic); if(payload) _mosquitto_free(payload); switch(qos){ case 0: return MOSQ_ERR_SUCCESS; case 1: return _mosquitto_send_puback(context, mid); case 2: mqtt3_db_message_store_find(context, mid, &stored); if(!stored){ if(mqtt3_db_message_store(db, context->id, mid, NULL, qos, 0, NULL, false, &stored, 0)){ return 1; } res = mqtt3_db_message_insert(db, context, mid, mosq_md_in, qos, false, stored); }else{ res = 0; } if(!res){ res = _mosquitto_send_pubrec(context, mid); } return res; } return 1; }