Ejemplo n.º 1
0
/**
 * Utility function to start a new publish exchange.
 * @param pubclient the client to send the publication to
 * @param publish the publication data
 * @param qos the MQTT QoS to use
 * @param retained boolean - whether to set the MQTT retained flag
 * @return the completion code
 */
int MQTTProtocol_startPublishCommon(Clients* pubclient, Publish* publish, int qos, int retained)
{
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	if (qos == 0 && (strlen(publish->topic) < 5 || strncmp(publish->topic, sysprefix, strlen(sysprefix)) != 0))
	{
		++(bstate->msgs_sent);
		bstate->bytes_sent += publish->payloadlen;
	}
#if defined(MQTTS)
	if (pubclient->protocol == PROTOCOL_MQTTS)
	{
		rc = MQTTSProtocol_startPublishCommon(pubclient,publish,0,qos,retained);
	}
	else if (pubclient->protocol == PROTOCOL_MQTTS_DTLS)
	{
		rc = MQTTSProtocol_startPublishCommon(pubclient,publish,0,qos,retained);
	}
	else
	{
#endif
	rc = MQTTPacket_send_publish(publish, 0, qos, retained, pubclient->socket, pubclient->clientID);
	if (qos == 0 && rc == TCPSOCKET_INTERRUPTED)
		MQTTProtocol_storeQoS0(pubclient, publish);
#if defined(MQTTS)
	}
#endif
	FUNC_EXIT_RC(rc);
	return rc;
}
Ejemplo n.º 2
0
/**
 * Kick off a new publication, queue it or send it as appropriate.
 * @param pubclient the client to send the publication to
 * @param publish the publication data
 * @param qos the MQTT QoS to use
 * @param retained boolean - whether to set the MQTT retained flag
 * @param mm - pointer to the message to send
 * @return the completion code
 */
int Protocol_startOrQueuePublish(Clients* pubclient, Publish* publish, int qos, int retained, int priority, Messages** mm)
{
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	if (pubclient->connected && pubclient->good &&           /* client is connected and has no errors */
		Socket_noPendingWrites(pubclient->socket) &&         /* there aren't any previous packets still stacked up on the socket */
		queuedMsgsCount(pubclient) == 0 &&                   /* there are no messages ahead in the queue */
		pubclient->outboundMsgs->count < bstate->max_inflight_messages) /* the queue is not full */
	{
#if defined(MQTTS)
		if (pubclient->protocol == PROTOCOL_MQTTS_MULTICAST)
		{
			MQTTSProtocol_startPublishCommon(pubclient, publish, 0, 3, retained);
		}
		else if (pubclient->protocol == PROTOCOL_MQTTS && strlen(publish->topic) > 2 &&
				MQTTSProtocol_getRegisteredTopicId(pubclient, publish->topic) == 0)
		{
			if (pubclient->pendingRegistration == NULL)
				rc = MQTTSProtocol_startRegistration(pubclient, publish->topic);
			rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
		}
		else if (pubclient->protocol == PROTOCOL_MQTTS && qos > 0 && pubclient->outboundMsgs->count > 0)
		{
			/* can only have 1 qos 1/2 message in flight with MQTT-S */
			rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
		}
		else
		{
#endif
			rc = MQTTProtocol_startPublish(pubclient, publish, qos, retained, mm);
			/* We don't normally queue QoS 0 messages just send them straight through.  But in the case when none of the packet
			 * is written we need to queue it up.  If only part of the packet is written, then it is buffered by the socket module.
			 */
			if (qos == 0 && rc == TCPSOCKET_NOWORK)
				rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
#if defined(MQTTS)
		}
#endif
	}
	else if (qos != 0 || (pubclient->connected && pubclient->good))    /* only queue qos 0 if the client is connected in a good way */
		rc = MQTTProtocol_queuePublish(pubclient, publish, qos, retained, priority, mm);
	FUNC_EXIT_RC(rc);
	return rc;
}
Ejemplo n.º 3
0
/**
 * MQTT retry processing per client
 * @param now current time
 * @param client - the client to which to apply the retry processing
 */
void MQTTProtocol_retries(time_t now, Clients* client)
{
	ListElement* outcurrent = NULL;
	FUNC_ENTRY;
#if defined(MQTTS)
	if (client->protocol == PROTOCOL_MQTTS)
	{
		if (client->pendingRegistration != NULL &&
				difftime(now, client->pendingRegistration->sent) > bstate->retry_interval)
		{
			Registration* reg = client->pendingRegistration->registration;
			time(&client->pendingRegistration->sent);
			/* NB: no dup bit for these packets */
			if (MQTTSPacket_send_register(client, reg->id, reg->topicName, client->pendingRegistration->msgId) == SOCKET_ERROR)
			{
				client->good = 0;
				//TODO: update message
				Log(LOG_WARNING, 29, NULL, client->clientID, client->socket);
				MQTTProtocol_closeSession(client, 1);
				client = NULL;
			}
		}
#if !defined(NO_BRIDGE)
		if (client->pendingSubscription != NULL &&
				difftime(now, client->pendingSubscription->sent) > bstate->retry_interval)
		{
			time(&client->pendingSubscription->sent);
			if (MQTTSPacket_send_subscribe(client, client->pendingSubscription->topicName,client->pendingSubscription->qos, client->pendingSubscription->msgId) == SOCKET_ERROR)
			{
				client->good = 0;
				//TODO: update message
				Log(LOG_WARNING, 29, NULL, client->clientID, client->socket);
				MQTTProtocol_closeSession(client, 1);
				client = NULL;
			}
		}
#endif
	}
#endif
	while (client && ListNextElement(client->outboundMsgs, &outcurrent) &&
		   client->connected && client->good &&           /* client is connected and has no errors */
			Socket_noPendingWrites(client->socket))  /* there aren't any previous packets still stacked up on the socket */
	{
		Messages* m = (Messages*)(outcurrent->content);


		if (difftime(now, m->lastTouch) > bstate->retry_interval)
		{
			if (m->qos == 1 || (m->qos == 2 && m->nextMessageType == PUBREC))
			{
				Publish publish;
				int rc;
				Log(LOG_INFO, 28, NULL, client->clientID, client->socket, m->msgid);
				publish.msgId = m->msgid;
				publish.topic = m->publish->topic;
				publish.payload = m->publish->payload;
				publish.payloadlen = m->publish->payloadlen;
#if defined(MQTTS)
				if (client->protocol == PROTOCOL_MQTTS)
				{
					if (MQTTSProtocol_startPublishCommon(client, &publish, 1, m->qos, m->retain) == SOCKET_ERROR)
					{
						client->good = 0;
						Log(LOG_WARNING, 29, NULL, client->clientID, client->socket);
						MQTTProtocol_closeSession(client, 1);
						client = NULL;
					}
					else
						time(&(m->lastTouch));
				}
				else
				{
#endif
					rc = MQTTPacket_send_publish(&publish, 1, m->qos, m->retain, client->socket, client->clientID);
					if (rc == SOCKET_ERROR)
					{
						client->good = 0;
						Log(LOG_WARNING, 29, NULL, client->clientID, client->socket);
						MQTTProtocol_closeSession(client, 1);
						client = NULL;
					}
					else
					{
						if (m->qos == 0 && rc == TCPSOCKET_INTERRUPTED)
							MQTTProtocol_storeQoS0(client, &publish);
						time(&(m->lastTouch));
					}
#if defined(MQTTS)
				}
#endif
			}
			else if (m->qos && m->nextMessageType == PUBCOMP)
			{
				Log(LOG_WARNING, 30, NULL, client->clientID, m->msgid);
#if defined(MQTTS)
				if (client->protocol == PROTOCOL_MQTTS)
				{
					/* NB: no dup bit for PUBREL */
					if (MQTTSPacket_send_pubrel(client, m->msgid) == SOCKET_ERROR)
					{
						client->good = 0;
						Log(LOG_WARNING, 18, NULL, client->clientID, client->socket,
								Socket_getpeer(client->socket));
						MQTTProtocol_closeSession(client, 1);
						client = NULL;
					}
					else
						time(&(m->lastTouch));
				}
				else
#endif
					if (MQTTPacket_send_pubrel(m->msgid, 1, client->socket, client->clientID) != TCPSOCKET_COMPLETE)
					{
						client->good = 0;
						Log(LOG_WARNING, 18, NULL, client->clientID, client->socket,
								Socket_getpeer(client->socket));
						MQTTProtocol_closeSession(client, 1);
						client = NULL;
					}
					else
						time(&(m->lastTouch));
			}
			/* break; why not do all retries at once? */
		}
	}
	FUNC_EXIT;
}
Ejemplo n.º 4
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;
}