Example #1
0
/**
 * See if any pending writes have been completed, and cleanup if so.
 * Cleaning up means removing any publication data that was stored because the write did
 * not originally complete.
 */
void MQTTProtocol_checkPendingWrites()
{
	FUNC_ENTRY;
	if (state.pending_writes.count > 0)
	{
		ListElement* le = state.pending_writes.first;
		while (le)
		{
			pending_write* pw = (pending_write*)(le->content);
			if (Socket_noPendingWrites(pw->socket))
			{
				Clients* client = pw->client;

				MQTTProtocol_removePublication(pw->p);
				state.pending_writes.current = le;
				ListRemove(&(state.pending_writes), le->content); /* does NextElement itself */
				le = state.pending_writes.current;
				/* now we might be able to write the next message in the queue */
				MQTTProtocol_processQueued(client);
			}
			else
				ListNextElement(&(state.pending_writes), &le);
		}
	}
	FUNC_EXIT;
}
Example #2
0
/**
 * Process an incoming puback packet for a socket
 * @param pack pointer to the publish packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handlePubacks(void* pack, int sock, Clients* client)
{
	Puback* puback = (Puback*)pack;
	//Clients* client = (Clients*)(TreeFind(bstate->clients, &sock)->content);
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 14, NULL, sock, client->clientID, puback->msgId);

	/* look for the message by message id in the records of outbound messages for this client */
	if (ListFindItem(client->outboundMsgs, &(puback->msgId), messageIDCompare) == NULL)
		Log(LOG_WARNING, 50, NULL, "PUBACK", client->clientID, puback->msgId);
	else
	{
		Messages* m = (Messages*)(client->outboundMsgs->current->content);
		if (m->qos != 1)
			Log(LOG_WARNING, 51, NULL, "PUBACK", client->clientID, puback->msgId, m->qos);
		else
		{
			Log(TRACE_MIN, 4, NULL, client->clientID, puback->msgId);
			++(bstate->msgs_sent);
			bstate->bytes_sent += m->publish->payloadlen;
			MQTTProtocol_removePublication(m->publish);
			ListRemove(client->outboundMsgs, m);
			/* now there is space in the inflight message queue we can process any queued messages */
			MQTTProtocol_processQueued(client);
		}
	}
	free(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
/**
 * Process an incoming puback packet for a socket
 * @param pack pointer to the publish packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handlePubacks(void* pack, int sock)
{
	Puback* puback = (Puback*)pack;
	Clients* client = NULL;
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
	Log(LOG_PROTOCOL, 14, NULL, sock, client->clientID, puback->msgId);

	/* look for the message by message id in the records of outbound messages for this client */
	if (ListFindItem(client->outboundMsgs, &(puback->msgId), messageIDCompare) == NULL)
		Log(TRACE_MIN, 3, NULL, "PUBACK", client->clientID, puback->msgId);
	else
	{
		Messages* m = (Messages*)(client->outboundMsgs->current->content);
		if (m->qos != 1)
			Log(TRACE_MIN, 4, NULL, "PUBACK", client->clientID, puback->msgId, m->qos);
		else
		{
			Log(TRACE_MIN, 6, NULL, "PUBACK", client->clientID, puback->msgId);
			#if !defined(NO_PERSISTENCE)
				rc = MQTTPersistence_remove(client, PERSISTENCE_PUBLISH_SENT, m->qos, puback->msgId);
			#endif
			MQTTProtocol_removePublication(m->publish);
			ListRemove(client->outboundMsgs, m);
		}
	}
	free(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #4
0
int MQTTSProtocol_handlePubacks(void* pack, int sock, char* clientAddr, Clients* client)
{
	int rc = 0;
	MQTTS_PubAck* puback = (MQTTS_PubAck*)pack;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 57, NULL, sock, clientAddr, client ? client->clientID : "", puback->msgId);

	/* look for the message by message id in the records of outbound messages for this client */
	if (ListFindItem(client->outboundMsgs, &(puback->msgId), messageIDCompare) == NULL)
		Log(LOG_WARNING, 50, NULL, "PUBACK", client->clientID, puback->msgId);
	else
	{
		Messages* m = (Messages*)(client->outboundMsgs->current->content);
		if (m->qos != 1)
			Log(LOG_WARNING, 51, NULL, "PUBACK", client->clientID, puback->msgId, m->qos);
		else
		{
			Log(TRACE_MAX, 4, NULL, client->clientID, puback->msgId);
			MQTTProtocol_removePublication(m->publish);
			ListRemove(client->outboundMsgs, m);
			/* TODO: msgs counts */
			/* (++state.msgs_sent);*/
		}
	}
	MQTTSPacket_free_packet(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #5
0
/**
 * Process an incoming pubrel packet for a socket
 * @param pack pointer to the publish packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handlePubrels(void* pack, int sock, Clients* client)
{
	Pubrel* pubrel = (Pubrel*)pack;
	//Clients* client = (Clients*)(TreeFind(bstate->clients, &sock)->content);
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 17, NULL, sock, client->clientID, pubrel->msgId);

	/* look for the message by message id in the records of inbound messages for this client */
	if (ListFindItem(client->inboundMsgs, &(pubrel->msgId), messageIDCompare) == NULL)
	{
		if (pubrel->header.bits.dup == 0)
			Log(LOG_WARNING, 50, NULL, "PUBREL", client->clientID, pubrel->msgId);
		/* Apparently this is "normal" behaviour, so we don't need to issue a warning */
		rc = MQTTPacket_send_pubcomp(pubrel->msgId, sock, client->clientID);
	}
	else
	{
		Messages* m = (Messages*)(client->inboundMsgs->current->content);
		if (m->qos != 2)
			Log(LOG_WARNING, 51, NULL, "PUBREL", client->clientID, pubrel->msgId, m->qos);
		else if (m->nextMessageType != PUBREL)
			Log(LOG_WARNING, 52, NULL, "PUBREL", client->clientID, pubrel->msgId);
		else
		{
			Publish publish;
			char* saved_clientid = malloc(strlen(client->clientID) + 1);

			strcpy(saved_clientid, client->clientID);
			/* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */
			rc = MQTTPacket_send_pubcomp(pubrel->msgId, sock, client->clientID);
			publish.header.bits.qos = m->qos;
			publish.header.bits.retain = m->retain;
			publish.msgId = m->msgid;
			publish.topic = m->publish->topic;
			publish.payload = m->publish->payload;
			publish.payloadlen = m->publish->payloadlen;
			++(bstate->msgs_received);
			bstate->bytes_received += m->publish->payloadlen;
			Protocol_processPublication(&publish, client->clientID);

			/* The client structure might have been removed in processPublication, on error */
			if (TreeFind(bstate->clients, &sock) || TreeFind(bstate->disconnected_clients, saved_clientid))
			{
				ListRemove(client->inboundMsgs, m);
				MQTTProtocol_removePublication(m->publish);
			}
			free(saved_clientid);
		}
	}
	free(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #6
0
int MQTTProtocol_handleGets(void* pack, int sock)
{
	Getack* getack = (Getack*)pack;
	Clients* client = NULL;
	char* clientid = NULL;
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
//	printf("------>%s, %s, %d\n", __func__, getack->ack_payload.ret_string, getack->ack_payload.ext_cmd);

	client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
	clientid = client->clientID;
//	Log(LOG_PROTOCOL, 11, NULL, sock, clientid, getack->msgId, get->header.bits.qos,
//			getack->header.bits.retain, min(20, getack->ext_payloadlen), get->ext_payload);

	/* here we needn't process some just like publish. only to parse ext ack, get one callback. */
#if 0
	if (get->header.bits.qos == 0)
		Protocol_processPublication(get, client);
	else if (get->header.bits.qos == 1)
	{
		/* send puback before processing the publications because a lot of return publications could fill up the socket buffer */
		rc = MQTTPacket_send_puback(publish->msgId, &client->net, client->clientID);
		/* if we get a socket error from sending the puback, should we ignore the publication? */
		Protocol_processPublication(publish, client);
	}
	else if (publish->header.bits.qos == 2)
	{
		/* store publication in inbound list */
		int len;
		ListElement* listElem = NULL;
		Messages* m = malloc(sizeof(Messages));
		Publications* p = MQTTProtocol_storePublication(publish, &len);
		m->publish = p;
		m->msgid = publish->msgId;
		m->qos = publish->header.bits.qos;
		m->retain = publish->header.bits.retain;
		m->nextMessageType = PUBREL;
		if ( ( listElem = ListFindItem(client->inboundMsgs, &(m->msgid), messageIDCompare) ) != NULL )
		{   /* discard queued publication with same msgID that the current incoming message */
			Messages* msg = (Messages*)(listElem->content);
			MQTTProtocol_removePublication(msg->publish);
			ListInsert(client->inboundMsgs, m, sizeof(Messages) + len, listElem);
			ListRemove(client->inboundMsgs, msg);
		} else
			ListAppend(client->inboundMsgs, m, sizeof(Messages) + len);
		rc = MQTTPacket_send_pubrec(publish->msgId, &client->net, client->clientID);
		publish->topic = NULL;
	}
	MQTTPacket_freePublish(publish);
#endif
	MQTTPacket_freeGet(getack);
	FUNC_EXIT_RC(rc);
	return rc;
}
/**
 * Empty a message list, leaving it able to accept new messages
 * @param msgList the message list to empty
 */
void MQTTProtocol_emptyMessageList(List* msgList)
{
	ListElement* current = NULL;

	FUNC_ENTRY;
	while (ListNextElement(msgList, &current))
	{
		Messages* m = (Messages*)(current->content);
		MQTTProtocol_removePublication(m->publish);
	}
	ListEmpty(msgList);
	FUNC_EXIT;
}
Example #8
0
int MQTTSProtocol_handlePubrels(void* pack, int sock, char* clientAddr, Clients* client)
{
	int rc = 0;
	MQTTS_PubRel* pubrel = (MQTTS_PubRel*)pack;

	FUNC_ENTRY;
	/* look for the message by message id in the records of inbound messages for this client */
	if (ListFindItem(client->inboundMsgs, &(pubrel->msgId), messageIDCompare) == NULL)
	{
		/* TODO: no dup flag in mqtts... not sure this is right
		if (pubrel->header.dup == 0)
			Log(LOG_WARNING, 50, "PUBREL", client->clientID, pubrel->msgId);
		else
		*/
			/* Apparently this is "normal" behavior, so we don't need to issue a warning */
			rc = MQTTSPacket_send_pubcomp(client,pubrel->msgId);
	}
	else
	{
		Messages* m = (Messages*)(client->inboundMsgs->current->content);
		if (m->qos != 2)
			Log(LOG_WARNING, 51, NULL, "PUBREL", client->clientID, pubrel->msgId, m->qos);
		else if (m->nextMessageType != PUBREL)
			Log(LOG_WARNING, 52, NULL, "PUBREL", client->clientID, pubrel->msgId);
		else
		{
			Publish publish;

			/* send pubcomp before processing the publications because a lot of return publications could fill up the socket buffer */
			rc = MQTTSPacket_send_pubcomp(client, pubrel->msgId);
			publish.header.bits.qos = m->qos;
			publish.header.bits.retain = m->retain;
			publish.msgId = m->msgid;
			publish.topic = m->publish->topic;
			publish.payload = m->publish->payload;
			publish.payloadlen = m->publish->payloadlen;
			Protocol_processPublication(&publish, client->clientID);
			MQTTProtocol_removePublication(m->publish);
			ListRemove(client->inboundMsgs, m);
			/* TODO: msgs counts */
			/* ++(state.msgs_received); */
		}
	}
	time( &(client->lastContact) );
	MQTTSPacket_free_packet(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #9
0
/**
 * Remove any QoS 0 messages from a message list.
 * This is used to clean up a session for a client which is non-cleansession.  QoS 0 messages
 * are non-persistent, so they are removed from the queue.
 * @param msgList the message list to empty
 */
void MQTTProtocol_removeQoS0Messages(List* msgList)
{
	ListElement* current = NULL;

	FUNC_ENTRY;
	ListNextElement(msgList, &current);
	while (current)
	{
		Messages* m = (Messages*)(current->content);
		if (m->qos == 0)
		{
			MQTTProtocol_removePublication(m->publish);
			msgList->current = current;
			ListRemove(msgList, current->content);
			current = msgList->current;
		}
		else
			ListNextElement(msgList, &current);
	}
	FUNC_EXIT;
}
Example #10
0
/**
 * See if any pending writes have been completed, and cleanup if so.
 * Cleaning up means removing any publication data that was stored because the write did
 * not originally complete.
 */
void MQTTProtocol_checkPendingWrites()
{
	FUNC_ENTRY;
	if (state.pending_writes.count > 0)
	{
		ListElement* le = state.pending_writes.first;
		while (le)
		{
			if (Socket_noPendingWrites(((pending_write*)(le->content))->socket))
			{
				MQTTProtocol_removePublication(((pending_write*)(le->content))->p);
				state.pending_writes.current = le;
				ListRemove(&(state.pending_writes), le->content); /* does NextElement itself */
				le = state.pending_writes.current;
			}
			else
				ListNextElement(&(state.pending_writes), &le);
		}
	}
	FUNC_EXIT;
}
Example #11
0
int MQTTSProtocol_handlePubcomps(void* pack, int sock, char* clientAddr, Clients* client)
{
	int rc = 0;
	MQTTS_PubComp* pubcomp = (MQTTS_PubComp*)pack;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 59, NULL, sock, clientAddr, client ? client->clientID : "", pubcomp->msgId);

	/* look for the message by message id in the records of outbound messages for this client */
	if (ListFindItem(client->outboundMsgs, &(pubcomp->msgId), messageIDCompare) == NULL)
	{
		/* No Dupe flag in MQTTs
		if (pubcomp->header.dup == 0)
		*/
		Log(LOG_WARNING, 50, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
	}
	else
	{
		Messages* m = (Messages*)(client->outboundMsgs->current->content);
		if (m->qos != 2)
			Log(LOG_WARNING, 51, NULL, "PUBCOMP", client->clientID, pubcomp->msgId, m->qos);
		else
		{
			if (m->nextMessageType != PUBCOMP)
				Log(LOG_WARNING, 52, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
			else
			{
				Log(TRACE_MAX, 5, NULL, client->clientID, pubcomp->msgId);
				MQTTProtocol_removePublication(m->publish);
				ListRemove(client->outboundMsgs, m);
				/* TODO: msgs counts */
				/*(++state.msgs_sent); */
			}
		}
	}
	MQTTSPacket_free_packet(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #12
0
/**
 * Process an incoming pubcomp packet for a socket
 * @param pack pointer to the publish packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handlePubcomps(void* pack, int sock)
{
	Pubcomp* pubcomp = (Pubcomp*)pack;
	Clients* client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 19, NULL, sock, client->clientID, pubcomp->msgId);

	/* look for the message by message id in the records of outbound messages for this client */
	if (ListFindItem(client->outboundMsgs, &(pubcomp->msgId), messageIDCompare) == NULL)
	{
		if (pubcomp->header.bits.dup == 0)
			Log(LOG_WARNING, 50, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
	}
	else
	{
		Messages* m = (Messages*)(client->outboundMsgs->current->content);
		if (m->qos != 2)
			Log(LOG_WARNING, 51, NULL, "PUBCOMP", client->clientID, pubcomp->msgId, m->qos);
		else
		{
			if (m->nextMessageType != PUBCOMP)
				Log(LOG_WARNING, 52, NULL, "PUBCOMP", client->clientID, pubcomp->msgId);
			else
			{
				Log(TRACE_MIN, 5, NULL, client->clientID, pubcomp->msgId);
				++(bstate->msgs_sent);
				bstate->bytes_sent += m->publish->payloadlen;
				MQTTProtocol_removePublication(m->publish);
				ListRemove(client->outboundMsgs, m);
			}
		}
	}
	free(pack);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #13
0
/**
 * Start the publish exchange for any queued messages, if possible.
 * When the inflight message queue is not at maximum capacity we can start a new
 * publication.
 * @param client the client to process queued messages for
 */
int MQTTProtocol_processQueued(Clients* client)
{
	int rc = 0;
#if defined(QOS0_SEND_LIMIT)
	int qos0count = 0;
#endif
	int threshold_log_message_issued = 0;

	FUNC_ENTRY;
	if (Protocol_isClientQuiescing(client))
		goto exit; /* don't create new work - just finish in-flight stuff */


	Log(TRACE_MAXIMUM, 0, NULL, client->clientID);
	while (client->good && Socket_noPendingWrites(client->socket) && /* no point in starting a publish if a write is still pending */
		client->outboundMsgs->count < bstate->max_inflight_messages &&
		queuedMsgsCount(client) > 0
#if defined(QOS0_SEND_LIMIT)
		&& qos0count < bstate->max_inflight_messages /* an arbitrary criterion - but when would we restart? */
#endif
		#if defined(MQTTS)
		&& (client->protocol == PROTOCOL_MQTT || client->outboundMsgs->count == 0)
#endif
		)
	{
		int pubrc = TCPSOCKET_COMPLETE;
		Messages* m = NULL;
		int threshold = (THRESHOLD * bstate->max_queued_messages) / 100;
		List* queue = NULL;
		int i;

		for (i = PRIORITY_MAX-1; i >= 0; --i)
		{
			if (client->queuedMsgs[i]->count > 0)
			{
				queue = client->queuedMsgs[i];
				break;
			}
		}
		m = (Messages*)(queue->first->content);

		Log(TRACE_MAXIMUM, 1, NULL, client->clientID);
#if defined(MQTTS)
		if (client->protocol == PROTOCOL_MQTTS && strlen(m->publish->topic) > 2 &&
				MQTTSProtocol_getRegisteredTopicId(client, m->publish->topic) == 0)
		{
			if (client->pendingRegistration == NULL)
				rc = MQTTSProtocol_startRegistration(client, m->publish->topic);
				goto exit;
		}

#endif
#if defined(QOS0_SEND_LIMIT)
		if (m->qos == 0)
			++qos0count;
#endif

		pubrc = MQTTProtocol_startQueuedPublish(client, m);
		/* regardless of whether the publish packet was sent on the wire (pubrc is good), the
		 * message has been put onto the outbound queue, so it must be removed from
		 * the queuedMsgs queue
		 */
		if (pubrc != TCPSOCKET_COMPLETE && pubrc != TCPSOCKET_INTERRUPTED)
			client->good = 0;
		if (m->qos == 0)
		{
			/* This is done primarily for MQTT-S.
			 * A qos-0 message will be on this queue if its topic
			 * has to be registered first. Now that the message
			 * has been sent, it needs to be cleaned up as there
			 * won't be an ack to trigger it.
			 *
			 * For MQTT, there is a scenario in which qos-0 messages
			 * could be on this list for which the same applies.
			 *
			 * Note (IGC): this is also a bug fix I just implemented - applies equally to MQTTs and MQTT!
			 */
			MQTTProtocol_removePublication(m->publish);
			if (!ListRemove(queue, m))
				Log(LOG_ERROR, 38, NULL);
		}
		else if (!ListDetach(queue, m))
			Log(LOG_ERROR, 38, NULL);
		if (queuedMsgsCount(client) == threshold - 1 && !threshold_log_message_issued)
		{
			Log(LOG_INFO, 146, NULL, client->clientID, THRESHOLD);
			threshold_log_message_issued = 1;
		}
	}
#if defined(QOS0_SEND_LIMIT)
	if (qos0count >= bstate->max_inflight_messages)
		rc = 1;
#endif
exit:
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #14
0
int Protocol_handlePublishes(Publish* publish, int sock, Clients* client, char* clientid)
{
	int rc = TCPSOCKET_COMPLETE;
#if !defined(SINGLE_LISTENER)
	Listener* listener = NULL;
#endif

	FUNC_ENTRY;
	if (Protocol_isClientQuiescing(client))
		goto exit; /* don't accept new work */
#if !defined(SINGLE_LISTENER)
	listener = Socket_getParentListener(sock);
	if (listener && listener->mount_point)
	{
		char* temp = malloc(strlen(publish->topic) + strlen(listener->mount_point) + 1);
		strcpy(temp, listener->mount_point);
		strcat(temp, publish->topic);
		free(publish->topic);
		publish->topic = temp;
	}
#endif

#if !defined(NO_BRIDGE)
	if (client && client->outbound)
		Bridge_handleInbound(client, publish);
#endif

	if (publish->header.bits.qos == 0)
	{
		if (strlen(publish->topic) < 5 || strncmp(publish->topic, sysprefix, strlen(sysprefix)) != 0)
		{
			++(bstate->msgs_received);
			bstate->bytes_received += publish->payloadlen;
		}
		Protocol_processPublication(publish, clientid);
	}
	else if (publish->header.bits.qos == 1)
	{
		/* send puback before processing the publications because a lot of return publications could fill up the socket buffer */
#if defined(MQTTS)
		if (client->protocol == PROTOCOL_MQTTS)
			rc = MQTTSPacket_send_puback(client, publish->msgId, MQTTS_RC_ACCEPTED);
		else
#endif
			rc = MQTTPacket_send_puback(publish->msgId, sock, clientid);
		/* if we get a socket error from sending the puback, should we ignore the publication? */
		Protocol_processPublication(publish, clientid);
		++(bstate->msgs_received);
		bstate->bytes_received += publish->payloadlen;
	}
	else if (publish->header.bits.qos == 2 && client->inboundMsgs->count < bstate->max_inflight_messages)
	{
		/* store publication in inbound list - if list is full, ignore and rely on client retry */
		int len;
		ListElement* listElem = NULL;
		Messages* m = NULL;
		Publications* p = MQTTProtocol_storePublication(publish, &len);

		if ((listElem = ListFindItem(client->inboundMsgs, &publish->msgId, messageIDCompare)) != NULL)
		{
			m = (Messages*)(listElem->content);
			MQTTProtocol_removePublication(m->publish); /* remove old publication data - could be different */
		}
		else
			m = malloc(sizeof(Messages));

		m->publish = p;
		m->msgid = publish->msgId;
		m->qos = publish->header.bits.qos;
		m->retain = publish->header.bits.retain;
		m->nextMessageType = PUBREL;

		if (listElem == NULL)
			ListAppend(client->inboundMsgs, m, sizeof(Messages) + len);
#if defined(MQTTS)
		if (client->protocol == PROTOCOL_MQTTS)
			rc = MQTTSPacket_send_pubrec(client, publish->msgId);
		else
#endif
			rc = MQTTPacket_send_pubrec(publish->msgId, sock, clientid);
	}
	else if (publish->header.bits.qos == 3) /* only applies to MQTT-S */
	{
		publish->header.bits.qos = 0;
		Protocol_processPublication(publish, clientid);
	}
exit:
	if (sock > 0)
		MQTTPacket_freePublish(publish);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #15
0
/**
 * Process an incoming publish packet for a socket
 * @param pack pointer to the publish packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handlePublishes(void* pack, int sock)
{
	Publish* publish = (Publish*)pack;
	Clients* client = NULL;
	char* clientid = NULL;
	int rc = TCPSOCKET_COMPLETE;
#if !defined(SINGLE_LISTENER)
	Listener* listener = Socket_getParentListener(sock);
#endif

	FUNC_ENTRY;
	if (sock == 0)
	  clientid = INTERNAL_CLIENTID; /* this is an internal client */
	else
	{
		client = (Clients*)(ListFindItem(bstate->clients, &sock, clientSocketCompare)->content);
		clientid = client->clientID;
		Log(LOG_PROTOCOL, 11, NULL, sock, clientid, publish->msgId, publish->header.bits.qos,
				publish->header.bits.retain, min(20, publish->payloadlen), publish->payload);
		if (Protocol_isClientQuiescing(client))
			goto exit; /* don't accept new work */
#if !defined(SINGLE_LISTENER)
		if (listener && listener->mount_point)
		{
			char* temp = malloc(strlen(publish->topic) + strlen(listener->mount_point) + 1);
			strcpy(temp, listener->mount_point);
			strcat(temp, publish->topic);
			free(publish->topic);
			publish->topic = temp;
		}
#endif
	}

#if !defined(NO_BRIDGE)
	if (client && client->outbound)
		Bridge_handleInbound(client, publish);
#endif

	if (publish->header.bits.qos == 0)
	{
		if (strlen(publish->topic) < 5 || strncmp(publish->topic, sysprefix, strlen(sysprefix)) != 0)
		{
			++(bstate->msgs_received);
			bstate->bytes_received += publish->payloadlen;
		}
		Protocol_processPublication(publish, clientid);
	}
	else if (publish->header.bits.qos == 1)
	{
		/* send puback before processing the publications because a lot of return publications could fill up the socket buffer */
		rc = MQTTPacket_send_puback(publish->msgId, sock, clientid);
		/* if we get a socket error from sending the puback, should we ignore the publication? */
		Protocol_processPublication(publish, clientid);
		++(bstate->msgs_received);
		bstate->bytes_received += publish->payloadlen;
	}
	else if (publish->header.bits.qos == 2)
	{
		/* store publication in inbound list */
		int len;
		ListElement* listElem = NULL;
		Messages* m = NULL;
		Publications* p = NULL;

		/*if list is full, disconnect the client with warning message */
		if (client->inboundMsgs->count >= (bstate->max_inflight_messages*2))
		{
			Log(LOG_WARNING, 69, NULL, clientid);
			rc = SOCKET_ERROR; /* will cause the client to be disconnected */
			goto exit;
		}

		p = MQTTProtocol_storePublication(publish, &len);
		if ((listElem = ListFindItem(client->inboundMsgs, &publish->msgId, messageIDCompare)) != NULL)
		{
			m = (Messages*)(listElem->content);
			MQTTProtocol_removePublication(m->publish); /* remove old publication data - could be different */
		}
		else
			m = malloc(sizeof(Messages));

		m->publish = p;
		m->msgid = publish->msgId;
		m->qos = publish->header.bits.qos;
		m->priority = publish->priority;
		m->retain = publish->header.bits.retain;
		m->nextMessageType = PUBREL;

		if (listElem == NULL)
			ListAppend(client->inboundMsgs, m, sizeof(Messages) + len);
		rc = MQTTPacket_send_pubrec(publish->msgId, sock, clientid);
	}
exit:
	if (sock < -1 || sock > 0)
		MQTTPacket_freePublish(publish);
	FUNC_EXIT_RC(rc);
	return rc;
}
Example #16
0
/**
 * Close any active session for a client and clean up.
 * @param client the client to clean up
 * @param send_will flag to indicate whether a will messsage should be sent if it has been set
 */
void MQTTProtocol_closeSession(Clients* client, int send_will)
{
	FUNC_ENTRY;
	client->good = 0;
	if (in_MQTTPacket_Factory == client->socket || client->closing)
		goto exit;
	client->closing = 1;
	if (client->socket > 0)
	{
		if (client->connected)
		{
			if (client->outbound && client->will)
			{
				Publish pub;
				pub.payload = "0";
				pub.payloadlen = 1;
				pub.topic = client->will->topic;
#if defined(MQTTS)
				if (client->protocol == PROTOCOL_MQTTS)
					MQTTSProtocol_startPublishCommon(client, &pub, 0,0,1);
				if (client->protocol == PROTOCOL_MQTTS_DTLS)
					MQTTSProtocol_startPublishCommon(client, &pub, 0,0,1);
					//TODO LW
				else
#endif
					MQTTPacket_send_publish(&pub, 0, 0, 1, client->socket, client->clientID);
				MQTTProtocol_sys_publish(client->will->topic, "0");
			}
#if defined(MQTTS)
			if (client->protocol == PROTOCOL_MQTTS_MULTICAST)
				;
			else if (client->protocol == PROTOCOL_MQTTS)
				MQTTSPacket_send_disconnect(client, 0);
			else if (client->protocol == PROTOCOL_MQTTS_DTLS)
				MQTTSPacket_send_disconnect(client, 0);
			else
#endif
			if (client->outbound)
				MQTTPacket_send_disconnect(client->socket, client->clientID);
		}

		if (ListFindItem(&(state.pending_writes), &(client->socket), intcompare))
		{
			pending_write* pw = (pending_write*)(state.pending_writes.current->content);
			MQTTProtocol_removePublication(pw->p);
			ListRemove(&(state.pending_writes), pw);
		}

#if defined(MQTTS)
		if (client->protocol == PROTOCOL_MQTT || client->outbound == 1)
		{
			if (client->protocol == PROTOCOL_MQTTS_MULTICAST)
				Socket_close_only(client->socket);
			else
#endif
				Socket_close(client->socket);
#if defined(MQTTS)
		}
#endif
	}
	if (client->connected || client->connect_state)
	{
		client->connected = 0;
		client->connect_state = 0;
	}
	if (client->outbound == 0 && client->will != NULL && send_will)
	{
		Publish publish;
		publish.payload = client->will->msg;
		publish.payloadlen = strlen(client->will->msg);
		publish.topic = client->will->topic;
		publish.header.bits.qos = client->will->qos;
		publish.header.bits.retain = client->will->retained;
		Protocol_processPublication(&publish, client->clientID);
	}
#if defined(MQTTS)
	if (client->protocol == PROTOCOL_MQTTS)
		MQTTSProtocol_emptyRegistrationList(client->registrations);
	else if (client->protocol == PROTOCOL_MQTTS_DTLS)
		MQTTSProtocol_emptyRegistrationList(client->registrations);
#endif
	if (client->cleansession)
	{
		if (client->outbound && ((BridgeConnections*)(client->bridge_context))->state != CONNECTION_DELETE)
		{ /* bridge outbound client structures are reused on reconnection */
			int i;
			MQTTProtocol_removeAllSubscriptions(client->clientID);
			MQTTProtocol_emptyMessageList(client->inboundMsgs);
			MQTTProtocol_emptyMessageList(client->outboundMsgs);
			for (i = 0; i < PRIORITY_MAX; ++i)
				MQTTProtocol_emptyMessageList(client->queuedMsgs[i]);
			client->msgID = 0;
		}
		else
		{
#if defined(MQTTS)
			if ((client->protocol == PROTOCOL_MQTTS && client->outbound == 0) || (client->protocol == PROTOCOL_MQTTS_DTLS && client->outbound == 0) || client->protocol == PROTOCOL_MQTTS_MULTICAST)
			{
				if (!TreeRemove(bstate->mqtts_clients, client) && !TreeRemove(bstate->disconnected_mqtts_clients, client))
					Log(LOG_ERROR, 39, NULL);
				else
					Log(TRACE_MAX, 2, NULL, client->clientID, client->socket);
			}
			else
			{
#endif
				if (!TreeRemove(bstate->clients, client) && !TreeRemove(bstate->disconnected_clients, client))
					Log(LOG_ERROR, 39, NULL);
				else
					Log(TRACE_MAX, 2, NULL, client->clientID, client->socket);
#if defined(MQTTS)
			}
#endif
			MQTTProtocol_freeClient(client);
		}
	}
	else
	{
		int i;
		for (i = 0; i < PRIORITY_MAX; ++i)
			MQTTProtocol_removeQoS0Messages(client->queuedMsgs[i]);
#if defined(MQTTS)
		if ((client->protocol == PROTOCOL_MQTTS && client->outbound == 0)||(client->protocol == PROTOCOL_MQTTS_DTLS && client->outbound == 0))
		{
			if (TreeRemove(bstate->mqtts_clients, client))
			{
				client->socket = 0;
				TreeAdd(bstate->disconnected_mqtts_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List));
			}
		}
		else
		{
#endif
		if (TreeRemove(bstate->clients, client))
		{
			client->socket = 0;
			TreeAdd(bstate->disconnected_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List));
		}
#if defined(MQTTS)
		}
#endif
    	client->closing = 0;
	}

exit:
	FUNC_EXIT;
}