/** * Continue an outstanding write for a particular socket * @param socket that socket * @return completion code */ int Socket_continueWrite(int socket) { int rc = 0; pending_writes* pw; unsigned long curbuflen = 0L, /* cumulative total of buffer lengths */ bytes; int curbuf = -1, i; iobuf iovecs1[5]; FUNC_ENTRY; pw = SocketBuffer_getWrite(socket); #if defined(OPENSSL) if (pw->ssl) { rc = SSLSocket_continueWrite(pw); goto exit; } #endif for (i = 0; i < pw->count; ++i) { if (pw->bytes <= curbuflen) { /* if previously written length is less than the buffer we are currently looking at, add the whole buffer */ iovecs1[++curbuf].iov_len = pw->iovecs[i].iov_len; iovecs1[curbuf].iov_base = pw->iovecs[i].iov_base; } else if (pw->bytes < curbuflen + pw->iovecs[i].iov_len) { /* if previously written length is in the middle of the buffer we are currently looking at, add some of the buffer */ int offset = pw->bytes - curbuflen; iovecs1[++curbuf].iov_len = pw->iovecs[i].iov_len - offset; iovecs1[curbuf].iov_base = pw->iovecs[i].iov_base + offset; break; } curbuflen += pw->iovecs[i].iov_len; } if ((rc = Socket_writev(socket, iovecs1, curbuf+1, &bytes)) != SOCKET_ERROR) { pw->bytes += bytes; if ((rc = (pw->bytes == pw->total))) { /* topic and payload buffers are freed elsewhere, when all references to them have been removed */ free(pw->iovecs[0].iov_base); free(pw->iovecs[1].iov_base); if (pw->count == 5) free(pw->iovecs[3].iov_base); Log(TRACE_MIN, -1, "ContinueWrite: partial write now complete for socket %d", socket); } else Log(TRACE_MIN, -1, "ContinueWrite wrote +%lu bytes on socket %d", bytes, socket); } #if defined(OPENSSL) exit: #endif FUNC_EXIT_RC(rc); return rc; }
int MQTTClient_publish(MQTTClient handle, const char* topicName, int payloadlen, void* payload, int qos, int retained, MQTTClient_deliveryToken* deliveryToken) { int rc = MQTTCLIENT_SUCCESS; MQTTClients* m = handle; Messages* msg = NULL; Publish* p = NULL; int blocked = 0; int msgid = 0; FUNC_ENTRY; Thread_lock_mutex(mqttclient_mutex); if (m == NULL || m->c == NULL) rc = MQTTCLIENT_FAILURE; else if (m->c->connected == 0) rc = MQTTCLIENT_DISCONNECTED; else if (!UTF8_validateString(topicName)) rc = MQTTCLIENT_BAD_UTF8_STRING; if (rc != MQTTCLIENT_SUCCESS) goto exit; /* If outbound queue is full, block until it is not */ while (m->c->outboundMsgs->count >= m->c->maxInflightMessages || Socket_noPendingWrites(m->c->net.socket) == 0) /* wait until the socket is free of large packets being written */ { if (blocked == 0) { blocked = 1; Log(TRACE_MIN, -1, "Blocking publish on queue full for client %s", m->c->clientID); } Thread_unlock_mutex(mqttclient_mutex); MQTTClient_yield(); Thread_lock_mutex(mqttclient_mutex); if (m->c->connected == 0) { rc = MQTTCLIENT_FAILURE; goto exit; } } if (blocked == 1) Log(TRACE_MIN, -1, "Resuming publish now queue not full for client %s", m->c->clientID); if (qos > 0 && (msgid = MQTTProtocol_assignMsgId(m->c)) == 0) { /* this should never happen as we've waited for spaces in the queue */ rc = MQTTCLIENT_MAX_MESSAGES_INFLIGHT; goto exit; } p = malloc(sizeof(Publish)); p->payload = payload; p->payloadlen = payloadlen; p->topic = (char*)topicName; p->msgId = msgid; rc = MQTTProtocol_startPublish(m->c, p, qos, retained, &msg); /* If the packet was partially written to the socket, wait for it to complete. * However, if the client is disconnected during this time and qos is not 0, still return success, as * the packet has already been written to persistence and assigned a message id so will * be sent when the client next connects. */ if (rc == TCPSOCKET_INTERRUPTED) { while (m->c->connected == 1 && SocketBuffer_getWrite(m->c->net.socket)) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_yield(); Thread_lock_mutex(mqttclient_mutex); } rc = (qos > 0 || m->c->connected == 1) ? MQTTCLIENT_SUCCESS : MQTTCLIENT_FAILURE; } if (deliveryToken && qos > 0) *deliveryToken = msg->msgid; free(p); if (rc == SOCKET_ERROR) { Thread_unlock_mutex(mqttclient_mutex); MQTTClient_disconnect_internal(handle, 0); Thread_lock_mutex(mqttclient_mutex); /* Return success for qos > 0 as the send will be retried automatically */ rc = (qos > 0) ? MQTTCLIENT_SUCCESS : MQTTCLIENT_FAILURE; } exit: Thread_unlock_mutex(mqttclient_mutex); FUNC_EXIT_RC(rc); return rc; }