int MQTTSProtocol_handleRegacks(void* pack, int sock, char* clientAddr, Clients* client) { int rc = 0; MQTTS_RegAck* regack = (MQTTS_RegAck*)pack; FUNC_ENTRY; if (client->pendingRegistration == NULL || regack->msgId != client->pendingRegistration->msgId) { /* unexpected regack*/ } else if (!client->outbound) { if (regack->topicId != client->pendingRegistration->registration->id) { /* unexpected regack*/ } else if (regack->returnCode != MQTTS_RC_ACCEPTED) { /* rejected ack... what do we do now? */ } else { free(client->pendingRegistration); client->pendingRegistration = NULL; rc = MQTTProtocol_processQueued(client); } } else /* outbound client */ { if (regack->returnCode != MQTTS_RC_ACCEPTED) { /* rejected ack... what do we do now? */ } else { Registration* reg = client->pendingRegistration->registration; free(client->pendingRegistration); client->pendingRegistration = NULL; reg->id = regack->topicId; ListAppend(client->registrations, reg, sizeof(reg) + strlen(reg->topicName)+1); rc = MQTTProtocol_processQueued(client); } } time( &(client->lastContact) ); MQTTSPacket_free_packet(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, 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; }
/** * 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; }
/** * MQTT retry protocol and socket pending writes processing. * @param now current time * @param doRetry boolean - retries as well as pending writes? * @return not actually used */ int MQTTProtocol_retry(time_t now, int doRetry) { Node* current = NULL; int rc = 0; FUNC_ENTRY; current = TreeNextElement(bstate->clients, current); /* look through the outbound message list of each client, checking to see if a retry is necessary */ while (current) { Clients* client = (Clients*)(current->content); current = TreeNextElement(bstate->clients, current); if (client->connected == 0) { #if defined(MQTTS) if (client->protocol == PROTOCOL_MQTTS) { if (difftime(now,client->lastContact) > bstate->retry_interval) { int rc2 = 0; /* NB: no dup bit for these packets */ if (client->connect_state == 1) /* TODO: handle err */ rc2 = MQTTSPacket_send_willTopicReq(client); else if (client->connect_state == 2) /* TODO: handle err */ rc2 = MQTTSPacket_send_willMsgReq(client); if (rc2 == SOCKET_ERROR) { client->good = 0; Log(LOG_WARNING, 29, NULL, client->clientID, client->socket); MQTTProtocol_closeSession(client, 1); client = NULL; } } } #endif continue; } if (client->good == 0) { MQTTProtocol_closeSession(client, 1); continue; } if (Socket_noPendingWrites(client->socket) == 0) continue; if (doRetry) MQTTProtocol_retries(now, client); if (client) { if (MQTTProtocol_processQueued(client)) rc = 1; } } FUNC_EXIT_RC(rc); return rc; }
int MQTTSProtocol_handleConnects(void* pack, int sock, char* clientAddr, Clients* client, uint8_t* wirelessNodeId , uint8_t wirelessNodeIdLen) { MQTTS_Connect* connect = (MQTTS_Connect*)pack; Listener* list = NULL; int terminate = 0; Node* elem = NULL; int rc = 0; int existingClient = 0; FUNC_ENTRY; Log(LOG_PROTOCOL, 39, NULL, sock, clientAddr, client ? client->clientID : "", connect->flags.cleanSession); if (bstate->clientid_prefixes->count > 0 && !ListFindItem(bstate->clientid_prefixes, connect->clientID, clientPrefixCompare)) { Log(LOG_WARNING, 31, NULL, connect->clientID); terminate = 1; } else { list = Socket_getParentListener(sock); if (list->max_connections > -1 && list->connections->count > list->max_connections) { /* TODO: why is this commented out? delete if not needed //MQTTPacket_send_connack(3, sock); */ Log(LOG_WARNING, 141, NULL, connect->clientID, list->max_connections, list->port); terminate = 1; } else if (connect->protocolID != 1) { Log(LOG_WARNING, 32, NULL, "MQTT-S", connect->protocolID); /* TODO: why is this commented out? delete if not needed //MQTTPacket_send_connack(1, sock); */ terminate = 1; } } if (terminate) { /*TODO: process the terminate*/ MQTTSPacket_free_packet(pack); goto exit; } if (client != NULL && !strcmp(client->clientID, connect->clientID)) { /* Connect for a new client id on a used addr * TODO: clean out 'old' Client (that may be 'connected') */ } elem = TreeFindIndex(bstate->mqtts_clients, connect->clientID, 1); if (elem == NULL) { client = TreeRemoveKey(bstate->disconnected_mqtts_clients, connect->clientID); if (client == NULL) /* this is a totally new connection */ { /* Brand new client connection */ int i; client = malloc(sizeof(Clients)); memset(client, '\0', sizeof(Clients)); client->protocol = PROTOCOL_MQTTS; client->outboundMsgs = ListInitialize(); client->inboundMsgs = ListInitialize(); for (i = 0; i < PRIORITY_MAX; ++i) client->queuedMsgs[i] = ListInitialize(); client->registrations = ListInitialize(); client->noLocal = 0; /* (connect->version == PRIVATE_PROTOCOL_VERSION) ? 1 : 0; */ client->clientID = connect->clientID; connect->clientID = NULL; /* don't want to free this space as it is being used in the clients tree below */ // Set Wireless Node ID if exists if ( wirelessNodeId == NULL) { client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else { client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } } // // client == NULL else /* there is an existing disconnected client */ { /* Reconnect of a disconnected client */ free(client->addr); client->connect_state = 0; client->connected = 0; /* Do not connect until we know the connack has been sent */ // Delete Wireless Node ID if exists in existing client if ( wirelessNodeId == NULL) { if ( client->wirelessNodeId != NULL) free( client->wirelessNodeId ) ; client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else // Replace existing Wireless Node ID with value from current connect packet { if ( client->wirelessNodeId != NULL) free ( client->wirelessNodeId ) ; client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } } // client != NULL client->good = 1; /* good is set to 0 in disconnect, so we need to reset it here */ client->keepAliveInterval = connect->keepAlive; client->cleansession = connect->flags.cleanSession; client->socket = sock; client->addr = malloc(strlen(clientAddr)+1); strcpy(client->addr, clientAddr); TreeAdd(bstate->mqtts_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); if (client->cleansession) MQTTProtocol_removeAllSubscriptions(client->clientID); /* clear any persistent subscriptions */ if (connect->flags.will) { client->connect_state = 1; rc = MQTTSPacket_send_willTopicReq(client); } else { client->connected = 1; rc = MQTTSPacket_send_connack(client, 0); /* send response */ } } else { /* Reconnect of a connected client */ client = (Clients*)(elem->content); if (client->connected) { Log(LOG_INFO, 34, NULL, connect->clientID, clientAddr); if (client->socket != sock) Socket_close(client->socket); } client->socket = sock; client->connected = 0; /* Do not connect until we know the connack has been sent */ client->connect_state = 0; // Delete Wireless Node ID if exists in existing client if ( wirelessNodeId == NULL) { if ( client->wirelessNodeId != NULL) free( client->wirelessNodeId ) ; client->wirelessNodeId = NULL ; client->wirelessNodeIdLen = 0 ; } else // Replace existing Wireless Node ID with value from current connect packet { if ( client->wirelessNodeId != NULL) free ( client->wirelessNodeId ) ; client->wirelessNodeId = malloc((sizeof(uint8_t) * wirelessNodeIdLen)) ; memcpy( client->wirelessNodeId , wirelessNodeId , sizeof(uint8_t) * wirelessNodeIdLen) ; client->wirelessNodeIdLen = wirelessNodeIdLen ; } client->good = 1; if (client->addr != NULL) free(client->addr); client->addr = malloc(strlen(clientAddr)+1); strcpy(client->addr, clientAddr); client->cleansession = connect->flags.cleanSession; if (client->cleansession) { int i; MQTTProtocol_removeAllSubscriptions(client->clientID); /* empty pending message lists */ MQTTProtocol_emptyMessageList(client->outboundMsgs); MQTTProtocol_emptyMessageList(client->inboundMsgs); for (i = 0; i < PRIORITY_MAX; ++i) MQTTProtocol_emptyMessageList(client->queuedMsgs[i]); MQTTProtocol_clearWill(client); } /* registrations are always cleared */ MQTTSProtocol_emptyRegistrationList(client->registrations); /* have to remove and re-add client so it is in the right order for new socket */ if (client->socket != sock) { TreeRemoveNodeIndex(bstate->mqtts_clients, elem, 1); TreeRemoveKeyIndex(bstate->mqtts_clients, &client->socket, 0); client->socket = sock; TreeAdd(bstate->mqtts_clients, client, sizeof(Clients) + strlen(client->clientID)+1 + 3*sizeof(List)); } client->keepAliveInterval = connect->keepAlive; client->pendingRegistration = NULL; #if !defined(NO_BRIDGE) client->pendingSubscription = NULL; #endif if (connect->flags.will) { client->connect_state = 1; rc = MQTTSPacket_send_willTopicReq(client); } else { client->connected = 1; rc = MQTTSPacket_send_connack(client,0); /* send response */ } } if (existingClient) MQTTProtocol_processQueued(client); Log(LOG_INFO, 0, "Client connected to udp port %d from %s (%s)", list->port, client->clientID, clientAddr); MQTTSPacket_free_packet(pack); time( &(client->lastContact) ); exit: FUNC_EXIT_RC(rc); return rc; }
void MQTTSProtocol_timeslice(int sock) { int error; MQTTS_Header* pack = NULL; char *clientAddr = NULL ; Clients* client = NULL; struct sockaddr_in6 from; uint8_t *wirelessNodeId = NULL ; uint8_t wirelessNodeIdLen = 0 ; FUNC_ENTRY; pack = MQTTSPacket_Factory(sock, &clientAddr, (struct sockaddr *)&from, &wirelessNodeId , &wirelessNodeIdLen , &error); if (clientAddr) { // IF FRWDENCAP, append ":[WirelessNodeId in HEX]" to clientAddr if (wirelessNodeId && wirelessNodeIdLen > 0) { char* ptr = &clientAddr[strlen(clientAddr)] ; *(ptr++) = ':' ; *(ptr++) = '[' ; int i ; for (i = 0 ; i < wirelessNodeIdLen ; i++) { ptr += sprintf(ptr, "%02X", wirelessNodeId[i]); } *(ptr++) = ']' ; *ptr = '\0'; } client = Protocol_getclientbyaddr(clientAddr); } #if !defined(NO_BRIDGE) if (client == NULL) client = Protocol_getoutboundclient(sock); #endif if (pack == NULL) { if (error == SOCKET_ERROR || error == UDPSOCKET_INCOMPLETE) { if (client != NULL) { client->good = 0; /* make sure we don't try and send messages to ourselves */ //client->connected = 0; if (error == SOCKET_ERROR) Log(LOG_WARNING, 18, NULL, client->clientID, client->socket, Socket_getpeer(client->socket)); else Log(LOG_WARNING, 19, NULL, client->clientID, client->socket, Socket_getpeer(client->socket)); MQTTProtocol_closeSession(client, 0); } else { if (error == SOCKET_ERROR) Log(LOG_WARNING, 20, NULL, sock, Socket_getpeer(sock)); else Log(LOG_WARNING, 21, NULL, sock, Socket_getpeer(sock)); /*Socket_close(sock);*/ } } } else if (pack->header.type != MQTTS_CONNECT && handle_packets[(int)pack->header.type] == NULL) { Log(LOG_WARNING, 22, NULL, pack->header.type, handle_packets[(int)pack->header.type]); MQTTSPacket_free_packet(pack); } else if (client == NULL && pack->header.type != MQTTS_CONNECT && pack->header.type != MQTTS_ADVERTISE && pack->header.type != MQTTS_SEARCHGW && (pack->header.type != MQTTS_PUBLISH || ((MQTTS_Publish*)pack)->flags.QoS != 3)) { Log(LOG_WARNING, 23, NULL, sock, Socket_getpeer(sock), MQTTSPacket_name(pack->header.type)); MQTTSPacket_free_packet(pack); } else if ( pack->header.type == MQTTS_CONNECT ) { MQTTSProtocol_handleConnects(pack, sock, clientAddr, client, wirelessNodeId , wirelessNodeIdLen) ; } else { (*handle_packets[(int)pack->header.type])(pack, sock, clientAddr, client); /* TODO: * - error handling * - centralise calls to time( &(c->lastContact) ); (currently in each _handle* function */ if (client != NULL && client->connected == 1 && client->good == 1) { printf("Process the MQTTS queue for %x\n", client); MQTTProtocol_processQueued(client); } } FUNC_EXIT; }
/** * 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; }