int WdtSocket::readWithTimeout(char *buf, int nbyte, int timeoutMs, bool tryFull) { WDT_CHECK_GT(nbyte, 0); if (readErrorCode_ != OK && readErrorCode_ != WDT_TIMEOUT) { WLOG(ERROR) << "Socket read failed before, not trying to read again " << port_; return -1; } readErrorCode_ = OK; int numRead = 0; readEncryptionSettingsOnce(timeoutMs); if (supportUnencryptedPeer_ && readErrorCode_ == UNEXPECTED_CMD_ERROR) { WLOG(WARNING) << "Turning off encryption since the other side does not support " "encryption " << port_; readErrorCode_ = OK; buf[0] = buf_[0]; numRead = 1; // also turn off encryption encryptionParams_.erase(); } else if (readErrorCode_ != OK) { return -1; } if (nbyte == numRead) { return nbyte; } bool encrypt = encryptionParams_.isSet(); int ret = readInternal(buf + numRead, nbyte - numRead, timeoutMs, tryFull); if (ret >= 0) { numRead += ret; } else { return (numRead > 0 ? numRead : -1); } if (!encrypt) { return numRead; } int numDecrypted = 0; if (ctxSaveOffset_ >= 0) { if (ctxSaveOffset_ <= numRead) { if (!decryptor_.decrypt(buf, ctxSaveOffset_, buf)) { readErrorCode_ = ENCRYPTION_ERROR; return -1; } decryptor_.saveContext(); numDecrypted = ctxSaveOffset_; ctxSaveOffset_ = CTX_SAVED; } else { ctxSaveOffset_ -= numRead; } } // have to decrypt data if (!decryptor_.decrypt((buf + numDecrypted), (numRead - numDecrypted), (buf + numDecrypted))) { readErrorCode_ = ENCRYPTION_ERROR; return -1; } return numRead; }
int WdtSocket::write(char *buf, int nbyte, bool retry) { WDT_CHECK_GT(nbyte, 0); if (writeErrorCode_ != OK) { LOG(ERROR) << "Socket write failed before, not trying to write again " << port_; return -1; } writeEncryptionSettingsOnce(); if (writeErrorCode_ != OK) { return -1; } bool encrypt = encryptionParams_.isSet(); if (encrypt && !encryptor_.encrypt((uint8_t *)buf, nbyte, (uint8_t *)buf)) { writeErrorCode_ = ENCRYPTION_ERROR; return -1; } int written = writeInternal(buf, nbyte, options_.write_timeout_millis, retry); if (written != nbyte) { LOG(ERROR) << "Socket write failure " << written << " " << nbyte; writeErrorCode_ = SOCKET_WRITE_ERROR; } return written; }
SenderState SenderThread::processVersionMismatch() { WTLOG(INFO) << "entered PROCESS_VERSION_MISMATCH state "; WDT_CHECK(threadStats_.getLocalErrorCode() == ABORT); auto negotiationStatus = wdtParent_->getNegotiationStatus(); WDT_CHECK_NE(negotiationStatus, V_MISMATCH_FAILED) << "Thread should have ended in case of version mismatch"; if (negotiationStatus == V_MISMATCH_RESOLVED) { WTLOG(WARNING) << "Protocol version already negotiated, but " "transfer still aborted due to version mismatch"; return END; } WDT_CHECK_EQ(negotiationStatus, V_MISMATCH_WAIT); // Need a barrier here to make sure all the negotiated protocol versions // have been collected auto barrier = controller_->getBarrier(VERSION_MISMATCH_BARRIER); barrier->execute(); WTVLOG(1) << "cleared the protocol version barrier"; auto execFunnel = controller_->getFunnel(VERSION_MISMATCH_FUNNEL); while (true) { auto status = execFunnel->getStatus(); switch (status) { case FUNNEL_START: { WTLOG(INFO) << "started the funnel for version mismatch"; wdtParent_->setProtoNegotiationStatus(V_MISMATCH_FAILED); if (transferHistoryController_->handleVersionMismatch() != OK) { execFunnel->notifySuccess(); return END; } int negotiatedProtocol = 0; for (int threadProtocolVersion : wdtParent_->getNegotiatedProtocols()) { if (threadProtocolVersion > 0) { if (negotiatedProtocol > 0 && negotiatedProtocol != threadProtocolVersion) { WTLOG(ERROR) << "Different threads negotiated different protocols " << negotiatedProtocol << " " << threadProtocolVersion; execFunnel->notifySuccess(); return END; } negotiatedProtocol = threadProtocolVersion; } } WDT_CHECK_GT(negotiatedProtocol, 0); WLOG_IF(INFO, negotiatedProtocol != threadProtocolVersion_) << *this << " Changing protocol version to " << negotiatedProtocol << ", previous version " << threadProtocolVersion_; wdtParent_->setProtocolVersion(negotiatedProtocol); threadProtocolVersion_ = wdtParent_->getProtocolVersion(); setFooterType(); threadStats_.setRemoteErrorCode(OK); wdtParent_->setProtoNegotiationStatus(V_MISMATCH_RESOLVED); wdtParent_->clearAbort(); execFunnel->notifySuccess(); return CONNECT; } case FUNNEL_PROGRESS: { execFunnel->wait(); break; } case FUNNEL_END: { negotiationStatus = wdtParent_->getNegotiationStatus(); WDT_CHECK_NE(negotiationStatus, V_MISMATCH_WAIT); if (negotiationStatus == V_MISMATCH_FAILED) { return END; } if (negotiationStatus == V_MISMATCH_RESOLVED) { threadProtocolVersion_ = wdtParent_->getProtocolVersion(); threadStats_.setRemoteErrorCode(OK); return CONNECT; } } } } }