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; }
/** * Free allocated storage for a various packet tyoes * @param pack pointer to the suback packet structure */ void MQTTPacket_free_packet(MQTTPacket* pack) { FUNC_ENTRY; if (pack->header.bits.type == PUBLISH) MQTTPacket_freePublish((Publish*)pack); /*else if (pack->header.type == SUBSCRIBE) MQTTPacket_freeSubscribe((Subscribe*)pack, 1); else if (pack->header.type == UNSUBSCRIBE) MQTTPacket_freeUnsubscribe((Unsubscribe*)pack);*/ else free(pack); FUNC_EXIT; }
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; }
/** * 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; }
/** * Restores the persisted records to the outbound and inbound message queues of the * client. * @param client the client as ::Clients. * @return 0 if success, #MQTTCLIENT_PERSISTENCE_ERROR otherwise. */ int MQTTPersistence_restore(Clients *c) { int rc = 0; char **msgkeys = NULL, *buffer = NULL; int nkeys, buflen; int i = 0; int msgs_sent = 0; int msgs_rcvd = 0; FUNC_ENTRY; if (c->persistence && (rc = c->persistence->pkeys(c->phandle, &msgkeys, &nkeys)) == 0) { while (rc == 0 && i < nkeys) { if (strncmp(msgkeys[i], PERSISTENCE_COMMAND_KEY, strlen(PERSISTENCE_COMMAND_KEY)) == 0) ; else if (strncmp(msgkeys[i], PERSISTENCE_QUEUE_KEY, strlen(PERSISTENCE_QUEUE_KEY)) == 0) ; else if ((rc = c->persistence->pget(c->phandle, msgkeys[i], &buffer, &buflen)) == 0) { MQTTPacket* pack = MQTTPersistence_restorePacket(buffer, buflen); if ( pack != NULL ) { if ( strstr(msgkeys[i],PERSISTENCE_PUBLISH_RECEIVED) != NULL ) { Publish* publish = (Publish*)pack; Messages* msg = NULL; msg = MQTTProtocol_createMessage(publish, &msg, publish->header.bits.qos, publish->header.bits.retain); msg->nextMessageType = PUBREL; /* order does not matter for persisted received messages */ ListAppend(c->inboundMsgs, msg, msg->len); publish->topic = NULL; MQTTPacket_freePublish(publish); msgs_rcvd++; } else if ( strstr(msgkeys[i],PERSISTENCE_PUBLISH_SENT) != NULL ) { Publish* publish = (Publish*)pack; Messages* msg = NULL; char *key = malloc(MESSAGE_FILENAME_LENGTH + 1); sprintf(key, "%s%d", PERSISTENCE_PUBREL, publish->msgId); msg = MQTTProtocol_createMessage(publish, &msg, publish->header.bits.qos, publish->header.bits.retain); if ( c->persistence->pcontainskey(c->phandle, key) == 0 ) /* PUBLISH Qo2 and PUBREL sent */ msg->nextMessageType = PUBCOMP; /* else: PUBLISH QoS1, or PUBLISH QoS2 and PUBREL not sent */ /* retry at the first opportunity */ msg->lastTouch = 0; MQTTPersistence_insertInOrder(c->outboundMsgs, msg, msg->len); publish->topic = NULL; MQTTPacket_freePublish(publish); free(key); msgs_sent++; } else if ( strstr(msgkeys[i],PERSISTENCE_PUBREL) != NULL ) { /* orphaned PUBRELs ? */ Pubrel* pubrel = (Pubrel*)pack; char *key = malloc(MESSAGE_FILENAME_LENGTH + 1); sprintf(key, "%s%d", PERSISTENCE_PUBLISH_SENT, pubrel->msgId); if ( c->persistence->pcontainskey(c->phandle, key) != 0 ) rc = c->persistence->premove(c->phandle, msgkeys[i]); free(pubrel); free(key); } } else /* pack == NULL -> bad persisted record */ rc = c->persistence->premove(c->phandle, msgkeys[i]); } if (buffer) { free(buffer); buffer = NULL; } if (msgkeys[i]) free(msgkeys[i]); i++; } if (msgkeys) free(msgkeys); } Log(TRACE_MINIMUM, -1, "%d sent messages and %d received messages restored for client %s\n", msgs_sent, msgs_rcvd, c->clientID); MQTTPersistence_wrapMsgID(c); FUNC_EXIT_RC(rc); return rc; }