int MQTTSProtocol_handleSubscribes(void* pack, int sock, char* clientAddr, Clients* client) { int rc = 0; MQTTS_Subscribe* sub = (MQTTS_Subscribe*)pack; int isnew; int topicId = 0; char* topicName = NULL , *preDefinedTopicName = NULL; FUNC_ENTRY; Log(LOG_PROTOCOL, 67, NULL, sock, clientAddr, client ? client->clientID : "", sub->msgId, (sub->flags.QoS == 3) ? -1: sub->flags.QoS, sub->flags.topicIdType); // NORMAL (topic name is in subscribe packet) or SHORT topic name if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_NORMAL || sub->flags.topicIdType == MQTTS_TOPIC_TYPE_SHORT) { topicName = sub->topicName; sub->topicName = NULL; } // Pre-defined topic else if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_PREDEFINED && client != NULL && sub->topicId != 0) { char *name = MQTTSProtocol_getPreRegisteredTopicName(client, sub->topicId) ; if (name) { preDefinedTopicName = MQTTSProtocol_replaceTopicNamePlaceholders(client , name ) ; } topicName = preDefinedTopicName ; topicId = sub->topicId; } // If topic name not found send SubAck with Rejected - Invalid topic ID if (topicName == NULL) rc = MQTTSPacket_send_subAck(client, sub, 0, sub->flags.QoS, MQTTS_RC_REJECTED_INVALID_TOPIC_ID); else { if (sub->flags.topicIdType == MQTTS_TOPIC_TYPE_NORMAL && !Topics_hasWildcards(topicName)) { char* regTopicName = malloc(strlen(topicName)+1); strcpy(regTopicName, topicName); topicId = (MQTTSProtocol_registerTopic(client, regTopicName))->id; } isnew = SubscriptionEngines_subscribe(bstate->se, client->clientID, topicName, sub->flags.QoS, client->noLocal, (client->cleansession == 0), PRIORITY_NORMAL); if ( (rc = MQTTSPacket_send_subAck(client, sub, topicId, sub->flags.QoS, MQTTS_RC_ACCEPTED)) == 0) if ((client->noLocal == 0) || isnew) MQTTProtocol_processRetaineds(client, topicName,sub->flags.QoS, PRIORITY_NORMAL); } time( &(client->lastContact) ); MQTTSPacket_free_packet(pack); if (preDefinedTopicName) free (preDefinedTopicName); FUNC_EXIT_RC(rc); return rc; }
/** * Process an incoming ping subscribe packet for a socket * @param pack pointer to the subscribe packet * @param sock the socket on which the packet was received * @return completion code */ int MQTTProtocol_handleSubscribes(void* pack, int sock, Clients* client) { int i, *aq, *isnew, *authorized; Subscribe* subscribe = (Subscribe*)pack; ListElement *curtopic = NULL, *curqos = NULL; int rc = TCPSOCKET_COMPLETE; #if !defined(SINGLE_LISTENER) Listener* listener = Socket_getParentListener(sock); #endif FUNC_ENTRY; if (Protocol_isClientQuiescing(client)) goto exit; /* don't accept new work */ Log(LOG_PROTOCOL, 6, NULL, sock, client->clientID, subscribe->msgId); aq = malloc(sizeof(int)*(subscribe->noTopics)); isnew = malloc(sizeof(int)*(subscribe->noTopics)); authorized = malloc(sizeof(int)*(subscribe->noTopics)); for (i = 0; i < subscribe->noTopics; ++i) { int j; ListElement *duptopic = NULL; ListNextElement(subscribe->topics, &curtopic); aq[i] = *(int*)(ListNextElement(subscribe->qoss, &curqos)->content); /* The mount_point topic transformation must be done before the topic syntax validity check * otherwise badly formed topics can get into the subscription engine. */ #if !defined(SINGLE_LISTENER) if (listener && listener->mount_point) { char* temp = malloc(strlen((char*)(curtopic->content)) + strlen(listener->mount_point) + 1); strcpy(temp, listener->mount_point); strcat(temp, (char*)(curtopic->content)); free((char*)(curtopic->content)); curtopic->content = temp; subscribe->topics->size += strlen(listener->mount_point); } #endif if (!Topics_isValidName((char*)curtopic->content)) { Log(LOG_WARNING, 153, NULL, (char*)curtopic->content, client->clientID, client->addr); free(curtopic->content); continue; } authorized[i] = true; if (bstate->password_file && bstate->acl_file) { authorized[i] = Users_authorise(client->user,(char*)(curtopic->content),ACL_READ); if (!authorized[i]) Log(LOG_AUDIT, 150, NULL, client->clientID, (char*)(curtopic->content)); } for (j = 0; j < i; ++j) { char* prevtopic = (char*)(ListNextElement(subscribe->topics, &duptopic)->content); if (strcmp(prevtopic, (char*)(curtopic->content)) == 0) duptopic->content = curtopic->content; } isnew[i] = SubscriptionEngines_subscribe(bstate->se, client->clientID, (char*)(curtopic->content), aq[i], client->noLocal, (client->cleansession == 0), PRIORITY_NORMAL); } /* send suback before sending the retained publications because a lot of retained publications could fill up the socket buffer */ if ((rc = MQTTPacket_send_suback(subscribe->msgId, subscribe->noTopics, aq, sock, client->clientID)) != SOCKET_ERROR) { curtopic = curqos = NULL; for (i = 0; i < subscribe->noTopics; ++i) { /* careful if you get >1 subscriptions using the same topic name in the same packet! */ /* The next line changes the semantics of subscribe for bridge connections, * so that retained messages are only sent for new subscriptions. This is to help * avoid "retained message storms" when a connection drops and is re-established. * This change could be applied to all subscriptions by removing the "noLocal" check. */ if (authorized[i] && ((client->noLocal == 0) || isnew[i])) MQTTProtocol_processRetaineds(client, (char*)(ListNextElement(subscribe->topics, &curtopic)->content), *(int*)(ListNextElement(subscribe->qoss, &curqos)->content), PRIORITY_NORMAL); } } free(aq); free(isnew); free(authorized); exit: MQTTPacket_freeSubscribe(subscribe, 0); FUNC_EXIT_RC(rc); return rc; }