/**
 * Deserializes the supplied (wire) buffer into connect data structure
 * @param data the connect data structure to be filled out
 * @param buf the raw buffer data, of the correct length determined by the remaining length field
 * @param len the length in bytes of the data in the supplied buffer
 * @return error code.  1 is success, 0 is failure
 */
int MQTTDeserialize_connect( MQTTPacket_connectData* data, unsigned char* buf, int len )
{
    MQTTHeader header =
    { 0 };
    MQTTConnectFlags flags =
    { 0 };
    unsigned char* curdata = buf;
    unsigned char* enddata = &buf[ len ];
    int rc = 0;
    MQTTString Protocol;
    int version;
    int mylen = 0;

    FUNC_ENTRY;
    header.byte = readChar( &curdata );
    if ( header.bits.type != CONNECT )
        goto exit;

    curdata += MQTTPacket_decodeBuf( curdata, &mylen ); /* read remaining length */

    if ( !readMQTTLenString( &Protocol, &curdata, enddata ) || enddata - curdata < 0 ) /* do we have enough data to read the protocol version byte? */
        goto exit;

    version = (int) readChar( &curdata ); /* Protocol version */
    /* If we don't recognize the protocol version, we don't parse the connect packet on the
     * basis that we don't know what the format will be.
     */
    if ( MQTTPacket_checkVersion( &Protocol, version ) )
    {
        flags.all = readChar( &curdata );
        data->cleansession = flags.bits.cleansession;
        data->keepAliveInterval = readInt( &curdata );
        if ( !readMQTTLenString( &data->clientID, &curdata, enddata ) )
            goto exit;
        data->willFlag = flags.bits.will;
        if ( flags.bits.will )
        {
            data->will.qos = flags.bits.willQoS;
            data->will.retained = flags.bits.willRetain;
            if ( !readMQTTLenString( &data->will.topicName, &curdata, enddata ) || !readMQTTLenString( &data->will.message, &curdata, enddata ) )
                goto exit;
        }
        if ( flags.bits.username )
        {
            if ( enddata - curdata < 3 || !readMQTTLenString( &data->username, &curdata, enddata ) )
                goto exit;
            /* username flag set, but no username supplied - invalid */
            if ( flags.bits.password && ( enddata - curdata < 3 || !readMQTTLenString( &data->password, &curdata, enddata ) ) )
                goto exit;
            /* password flag set, but no password supplied - invalid */
        }
        else if ( flags.bits.password )
            goto exit;
        /* password flag set without username - invalid */
        rc = 1;
    }
    exit: FUNC_EXIT_RC(rc);
    return rc;
}
Exemple #2
0
/**
 * Process an incoming connect packet for a socket
 * @param pack pointer to the connect packet
 * @param sock the socket on which the packet was received
 * @return completion code
 */
int MQTTProtocol_handleConnects(void* pack, int sock, Clients* client)
{
	Connect* connect = (Connect*)pack;
	Node* elem = NULL;
	int terminate = 0;
	int rc = TCPSOCKET_COMPLETE;
#if !defined(SINGLE_LISTENER)
	Listener* listener = Socket_getParentListener(sock);
#endif

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 26, NULL, sock, connect->clientID);/*
			connect->Protocol, connect->flags.bits.cleanstart, connect->keepAliveTimer,
			connect->version, connect->username, connect->password);*/
	Socket_removeNew(sock);		
			
	if (bstate->state != BROKER_RUNNING)
		terminate = 1; /* don't accept new connection requests when we are shutting down */
	/* Now check the version.  If we don't recognize it we will not have parsed the packet,
	 * so nothing else in the packet structure will have been filled in.
	 */
	else if (!MQTTPacket_checkVersion(pack))
	{
		Log(LOG_WARNING, 32, NULL, connect->Protocol, connect->version);
		rc = MQTTPacket_send_connack(CONNACK_UNACCEPTABLE_PROTOCOL_VERSION, sock, Socket_getpeer(sock)); /* send response */
		terminate = 1;
	}
	else if (connect->clientID[0] == '\0' || (connect->version == 3 && strlen(connect->clientID) > 23))
	{
		rc = MQTTPacket_send_connack(CONNACK_IDENTIFIER_REJECTED, sock, Socket_getpeer(sock)); /* send response */
		terminate = 1;
	}
	else if (bstate->password_file != NULL)
	{
		if (connect->flags.bits.username && connect->flags.bits.password &&
				(Users_authenticate(connect->username, connect->password) == false))
		{
			Log(LOG_WARNING, 31, NULL, connect->clientID);
			rc = MQTTPacket_send_connack(CONNACK_BAD_USERNAME_OR_PASSWORD, sock, connect->clientID); /* send bad user/pass response */
			terminate = 1;
		}
		else if ((!connect->flags.bits.username || !connect->flags.bits.password) && !bstate->allow_anonymous)
		{
			Log(LOG_WARNING, 31, NULL, connect->clientID);
			rc = MQTTPacket_send_connack(CONNACK_BROKER_UNAVAILABLE, sock, connect->clientID); /* send broker unavailable response */
			terminate = 1;
		}
	}

	if (terminate)
		;
	else if (bstate->clientid_prefixes->count > 0 &&
		!ListFindItem(bstate->clientid_prefixes, connect->clientID, clientPrefixCompare))
	{
		Log(LOG_WARNING, 31, NULL, connect->clientID);
		terminate = 1;
	}
	else
	{
#if !defined(SINGLE_LISTENER)
		if (listener->max_connections > -1 &&
				listener->connections->count > listener->max_connections)
		{
			Log(LOG_WARNING, 141, NULL, connect->clientID, listener->max_connections, listener->port);
#else
		if (bstate->max_connections > -1 &&
			MQTTProtocol_getNoConnectedClients() >= bstate->max_connections)
		{
			Log(LOG_WARNING, 141, NULL, connect->clientID, bstate->max_connections, bstate->port);
#endif
			rc = MQTTPacket_send_connack(CONNACK_BROKER_UNAVAILABLE, sock, connect->clientID); /* send response */
			terminate = 1;
		}
	}

	if (terminate)
	{
		MQTTPacket_freeConnect(connect);
		Socket_close(sock);
		rc = TCPSOCKET_COMPLETE;
		goto exit;
	}

	if (bstate->connection_messages)
		Log(LOG_INFO,
#if !defined(SINGLE_LISTENER)
			33, NULL, listener->port, connect->clientID, Socket_getpeer(sock));
#else
			33, NULL, bstate->port, connect->clientID, Socket_getpeer(sock));
#endif

	elem = TreeFindIndex(bstate->clients, connect->clientID, 1);
	if (elem == NULL)
	{
		client = TreeRemoveKey(bstate->disconnected_clients, connect->clientID);
		if (client == NULL)
		{
			int i;
			char* tmpAddr = NULL;

			client = malloc(sizeof(Clients));
			memset(client, '\0', sizeof(Clients));
			tmpAddr = Socket_getpeer(sock);
			client->addr = malloc(strlen(tmpAddr)+1);
			strcpy(client->addr, tmpAddr);
	#if defined(MQTTS)
			client->protocol = PROTOCOL_MQTT;
	#endif
			client->clientID = connect->clientID;
			client->outboundMsgs = ListInitialize();
			client->inboundMsgs = ListInitialize();
			for (i = 0; i < PRIORITY_MAX; ++i)
				client->queuedMsgs[i] = ListInitialize();
			connect->clientID = NULL; /* don't want to free this space as it is being used in the client structure */
		}
		client->socket = sock;
		TreeAdd(bstate->clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List));
	}
	else
	{
		client = (Clients*)(elem->content);
		if (client->connected)
		{
			Log(LOG_INFO, 34, NULL, connect->clientID, Socket_getpeer(sock));
			if (client->socket != sock)
				Socket_close(client->socket);
		}

		if (connect->flags.bits.cleanstart)
		{
			int i;
			/* empty pending message lists */
			MQTTProtocol_emptyMessageList(client->outboundMsgs);
			MQTTProtocol_emptyMessageList(client->inboundMsgs);
			for (i = 0; i < PRIORITY_MAX; ++i)
				MQTTProtocol_emptyMessageList(client->queuedMsgs[i]);
			client->msgID = client->outbound = client->ping_outstanding = 0;
		}

		/* have to remove and re-add client so it is in the right order for new socket */
		if (client->socket != sock)
		{
			TreeRemoveNodeIndex(bstate->clients, elem, 1);
			TreeRemoveKeyIndex(bstate->clients, &client->socket, 0);
			client->socket = sock;
			TreeAdd(bstate->clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List));
		}
	}

	client->good = client->connected = 1;
	client->cleansession = connect->flags.bits.cleanstart;
	client->keepAliveInterval = connect->keepAliveTimer;
	client->noLocal = (connect->version == PRIVATE_PROTOCOL_VERSION) ? 1 : 0;
	if (client->cleansession)
		MQTTProtocol_removeAllSubscriptions(client->clientID); /* clear any persistent subscriptions */
#if !defined(SINGLE_LISTENER)
	if (listener && listener->mount_point && connect->flags.bits.will)
	{
		char* temp = malloc(strlen(connect->willTopic) + strlen(listener->mount_point) + 1);
		strcpy(temp, listener->mount_point);
		strcat(temp, connect->willTopic);
		free(connect->willTopic);
		connect->willTopic = temp;
	}
#endif
#if defined(MQTTS)
	if (connect->flags.bits.will)
	{
		MQTTProtocol_setWillTopic(client, connect->willTopic,
									connect->flags.bits.willRetain, connect->flags.bits.willQoS);
		MQTTProtocol_setWillMsg(client, connect->willMsg);
		connect->willTopic = NULL;
		connect->willMsg = NULL;
	}
#else
	MQTTProtocol_setWill(connect, client);
#endif

	if (connect->flags.bits.username)
	{
		client->user = Users_get_user(connect->username);
	}

	rc = MQTTPacket_send_connack(CONNACK_CONNECTION_ACCEPTED, sock, client->clientID); /* send response */

	if (client->cleansession == 0)
	{
		ListElement* outcurrent = NULL;
		time_t now = 0;

		/* ensure that inflight messages are retried now by setting the last touched time
		 * to very old (0) before calling the retry function
		 */
		time(&(now));
		while (ListNextElement(client->outboundMsgs, &outcurrent))
		{
			Messages* m = (Messages*)(outcurrent->content);
			m->lastTouch = 0;
		}
		MQTTProtocol_retries(now, client);
		MQTTProtocol_processQueued(client);
	}
	time(&(client->lastContact));

	MQTTPacket_freeConnect(connect);

exit:
	FUNC_EXIT_RC(rc);
	return rc;
}


/**
 * Process an incoming ping request 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_handlePingreqs(void* pack, int sock, Clients* client)
{
	int rc = TCPSOCKET_COMPLETE;

	FUNC_ENTRY;
	Log(LOG_PROTOCOL, 3, NULL, sock, client->clientID);
	rc = MQTTPacket_send_pingresp(sock, client->clientID);
	FUNC_EXIT_RC(rc);
	return rc;
}