/** * Copy and store message data for retries * @param publish the publication data * @param mm - pointer to the message data to store * @param qos the MQTT QoS to use * @param retained boolean - whether to set the MQTT retained flag * @return pointer to the message data stored */ Messages* MQTTProtocol_createMessage(Publish* publish, Messages **mm, int qos, int retained) { Messages* m = malloc(sizeof(Messages)); FUNC_ENTRY; m->len = sizeof(Messages); if (*mm == NULL || (*mm)->publish == NULL) { int len1; *mm = m; m->publish = MQTTProtocol_storePublication(publish, &len1); m->len += len1; } else { ++(((*mm)->publish)->refcount); m->publish = (*mm)->publish; } m->msgid = publish->msgId; m->qos = qos; m->retain = retained; time(&(m->lastTouch)); if (qos == 2) m->nextMessageType = PUBREC; FUNC_EXIT; return m; }
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; }
static void MQTTProtocol_storeQoS0(Clients* pubclient, Publish* publish) { int len; pending_write* pw = NULL; FUNC_ENTRY; /* store the publication until the write is finished */ pw = malloc(sizeof(pending_write)); Log(TRACE_MIN, 12, NULL); pw->p = MQTTProtocol_storePublication(publish, &len); pw->socket = pubclient->net.socket; ListAppend(&(state.pending_writes), pw, sizeof(pending_write)+len); /* we don't copy QoS 0 messages unless we have to, so now we have to tell the socket buffer where the saved copy is */ if (SocketBuffer_updateWrite(pw->socket, pw->p->topic, pw->p->payload) == NULL) Log(LOG_SEVERE, 0, "Error updating write"); 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; }