int32 PlainTextMessageIOGateway :: DoOutputImplementation(uint32 maxBytes) { if (GetMaximumPacketSize() > 0) { // For the packet-based implementation, we will send one packet per outgoing Message // It'll be up to the user to make sure not to put too much text in one Message uint32 totalNumBytesSent = 0; MessageRef nextMsg; while((totalNumBytesSent < maxBytes)&&(GetOutgoingMessageQueue().RemoveHead(nextMsg) == B_NO_ERROR)) { uint32 outBufLen = 1; // 1 for the one extra NUL byte at the end of all the strings (per String::Flatten(), below) const String * nextStr; for (uint32 i=0; nextMsg()->FindString(PR_NAME_TEXT_LINE, i, &nextStr) == B_NO_ERROR; i++) outBufLen += (nextStr->Length() + _eolString.Length()); ByteBufferRef outBuf = GetByteBufferFromPool(outBufLen); if (outBuf()) { uint8 * b = outBuf()->GetBuffer(); for (uint32 i=0; nextMsg()->FindString(PR_NAME_TEXT_LINE, i, &nextStr) == B_NO_ERROR; i++) { nextStr->Flatten(b); b += nextStr->Length(); // Advance by Length() instead of FlattenedSize() _eolString.Flatten(b); b += _eolString.Length(); // to avoid NUL bytes inside our outBuf } const uint8 * outBytes = outBuf()->GetBuffer(); const uint32 numBytesToSend = outBuf()->GetNumBytes()-1; // don't sent the NUL terminator byte; receivers shouldn't rely on it anyway PacketDataIO * pdio = GetPacketDataIO(); // guaranteed non-NULL IPAddressAndPort packetDest; const int32 numBytesSent = (nextMsg()->FindFlat(PR_NAME_PACKET_REMOTE_LOCATION, packetDest) == B_NO_ERROR) ? pdio->WriteTo(outBytes, numBytesToSend, packetDest) : pdio->Write( outBytes, numBytesToSend); if (numBytesSent > 0) totalNumBytesSent += numBytesSent; else if (numBytesSent < 0) return (totalNumBytesSent > 0) ? totalNumBytesSent : -1; else { (void) GetOutgoingMessageQueue().AddHead(nextMsg); // roll back -- we'll try again later to send it, maybe break; } } else break; } return totalNumBytesSent; } else return DoOutputImplementationAux(maxBytes, 0); // stream-based implementation is here }
int32 PlainTextMessageIOGateway :: DoOutputImplementation(uint32 maxBytes) { TCHECKPOINT; const Message * msg = _currentSendingMessage(); if (msg == NULL) { // try to get the next message from our queue (void) GetOutgoingMessageQueue().RemoveHead(_currentSendingMessage); msg = _currentSendingMessage(); _currentSendLineIndex = _currentSendOffset = -1; } if (msg) { if ((_currentSendOffset < 0)||(_currentSendOffset >= (int32)_currentSendText.Length())) { // Try to get the next line of text from our message if (msg->FindString(PR_NAME_TEXT_LINE, ++_currentSendLineIndex, _currentSendText) == B_NO_ERROR) { _currentSendOffset = 0; _currentSendText += _eolString; } else { _currentSendingMessage.Reset(); // no more text available? Go to the next message then. return DoOutputImplementation(maxBytes); } } if ((msg)&&(_currentSendOffset >= 0)&&(_currentSendOffset < (int32)_currentSendText.Length())) { // Send as much as we can of the current text line const char * bytes = _currentSendText.Cstr() + _currentSendOffset; int32 bytesWritten = GetDataIO()()->Write(bytes, muscleMin(_currentSendText.Length()-_currentSendOffset, maxBytes)); if (bytesWritten < 0) return -1; else if (bytesWritten > 0) { _currentSendOffset += bytesWritten; int32 subRet = DoOutputImplementation(maxBytes-bytesWritten); return (subRet >= 0) ? subRet+bytesWritten : -1; } } } return 0; }
int32 PacketTunnelIOGateway :: DoOutputImplementation(uint32 maxBytes) { if (_outputPacketBuffer.SetNumBytes(_maxTransferUnit, false) != B_NO_ERROR) return -1; uint32 totalBytesWritten = 0; bool firstTime = true; while((totalBytesWritten < maxBytes)&&((firstTime)||(IsSuggestedTimeSliceExpired() == false))) { firstTime = false; // Step 1: Add as much data to our output packet buffer as we can fit into it while((_outputPacketSize+FRAGMENT_HEADER_SIZE < _maxTransferUnit)&&(HasBytesToOutput())) { // Demand-create the next send-buffer if (_currentOutputBuffer() == NULL) { MessageRef msg; if (GetOutgoingMessageQueue().RemoveHead(msg) == B_NO_ERROR) { _currentOutputBufferOffset = 0; _currentOutputBuffer.Reset(); if (_slaveGateway()) { DataIORef oldIO = _slaveGateway()->GetDataIO(); // save slave gateway's old state // Get the slave gateway to generate its output into our ByteBuffer _fakeSendBuffer.SetNumBytes(0, false); _fakeSendIO.Seek(0, SeekableDataIO::IO_SEEK_SET); _slaveGateway()->SetDataIO(DataIORef(&_fakeSendIO, false)); _slaveGateway()->AddOutgoingMessage(msg); while(_slaveGateway()->DoOutput() > 0) {/* empty */} _slaveGateway()->SetDataIO(oldIO); // restore slave gateway's old state _currentOutputBuffer.SetRef(&_fakeSendBuffer, false); } else if (_fakeSendBuffer.SetNumBytes(msg()->FlattenedSize(), false) == B_NO_ERROR) { // Default algorithm: Just flatten the Message into the buffer msg()->Flatten(_fakeSendBuffer.GetBuffer()); _currentOutputBuffer.SetRef(&_fakeSendBuffer, false); } } } if (_currentOutputBuffer() == NULL) break; // oops, out of mem? uint32 sbSize = _currentOutputBuffer()->GetNumBytes(); uint32 dataBytesToSend = muscleMin(_maxTransferUnit-(_outputPacketSize+FRAGMENT_HEADER_SIZE), sbSize-_currentOutputBufferOffset); uint8 * p = _outputPacketBuffer.GetBuffer()+_outputPacketSize; muscleCopyOut(&p[0*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_magic)); // a well-known magic number, for sanity checking muscleCopyOut(&p[1*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_sexID)); // source exclusion ID muscleCopyOut(&p[2*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_sendMessageIDCounter)); // message ID tag so the receiver can track what belongs where muscleCopyOut(&p[3*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_currentOutputBufferOffset)); // start offset (within its message) for this sub-chunk muscleCopyOut(&p[4*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(dataBytesToSend)); // size of this sub-chunk muscleCopyOut(&p[5*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(sbSize)); // total size of this message //printf("CREATING PACKET magic=" UINT32_FORMAT_SPEC " msgID=" UINT32_FORMAT_SPEC " offset=" UINT32_FORMAT_SPEC " chunkSize=" UINT32_FORMAT_SPEC " totalSize=" UINT32_FORMAT_SPEC "\n", _magic, _sendMessageIDCounter, _currentOutputBufferOffset, dataBytesToSend, sbSize); memcpy(p+FRAGMENT_HEADER_SIZE, _currentOutputBuffer()->GetBuffer()+_currentOutputBufferOffset, dataBytesToSend); _outputPacketSize += (FRAGMENT_HEADER_SIZE+dataBytesToSend); _currentOutputBufferOffset += dataBytesToSend; if (_currentOutputBufferOffset == sbSize) { _currentOutputBuffer.Reset(); _fakeSendBuffer.Clear(_fakeSendBuffer.GetNumBytes() > MAX_CACHE_SIZE); // don't keep too much memory around! _sendMessageIDCounter++; } } // Step 2: If we have a non-empty packet to send, send it! if (_outputPacketSize > 0) { // If bytesWritten is set to zero, we just hold this buffer until our next call. int32 bytesWritten = GetDataIO()()->Write(_outputPacketBuffer.GetBuffer(), _outputPacketSize); //printf("WROTE " INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes %s\n", bytesWritten, _outputPacketSize, (bytesWritten==(int32)_outputPacketSize)?"":"******** SHORT ***********"); if (bytesWritten > 0) { if (bytesWritten != (int32)_outputPacketSize) LogTime(MUSCLE_LOG_ERROR, "PacketTunnelIOGateway::DoOutput(): Short write! (" INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes)\n", bytesWritten, _outputPacketSize); _outputPacketBuffer.Clear(); _outputPacketSize = 0; totalBytesWritten += bytesWritten; } else if (bytesWritten == 0) break; // no more space to write, for now else return -1; } else break; // nothing more to do! } return totalBytesWritten; }
bool PlainTextMessageIOGateway :: HasBytesToOutput() const { return ((_currentSendingMessage() != NULL)||(GetOutgoingMessageQueue().HasItems())); }