int32 PacketizedProxyDataIO :: Write(const void * buffer, uint32 size) { if (size > _maxTransferUnit) { LogTime(MUSCLE_LOG_ERROR, "PacketizedProxyDataIO: Error, tried to send packet with size " UINT32_FORMAT_SPEC ", max transfer unit is set to " UINT32_FORMAT_SPEC "\n", size, _maxTransferUnit); return -1; } // Only accept more data if we are done sending the data we already have buffered up bool tryAgainAfter = false; int32 ret = 0; if (HasBufferedOutput()) tryAgainAfter = true; else { // No data buffered? _outputBufferBytesSent = 0; if (_outputBuffer.SetNumBytes(sizeof(uint32)+size, false) != B_NO_ERROR) return 0; muscleCopyOut(_outputBuffer.GetBuffer(), B_HOST_TO_LENDIAN_INT32(size)); memcpy(_outputBuffer.GetBuffer()+sizeof(uint32), buffer, size); ret = size; } if (WriteBufferedOutputAux() != B_NO_ERROR) return -1; return ((tryAgainAfter)&&(HasBufferedOutput() == false)) ? Write(buffer, size) : ret; }
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; }