const ConstSocketRef & AbstractReflectSession :: GetSessionWriteSelectSocket() const { const DataIORef & dio = GetDataIO(); return dio() ? dio()->GetWriteSelectSocket() : GetNullSocket(); }
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 PlainTextMessageIOGateway :: DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes) { TCHECKPOINT; int32 ret = 0; const int tempBufSize = 2048; char buf[tempBufSize]; int32 bytesRead = GetDataIO()()->Read(buf, muscleMin(maxBytes, (uint32)(sizeof(buf)-1))); if (bytesRead < 0) { FlushInput(receiver); return -1; } if (bytesRead > 0) { uint32 filteredBytesRead = bytesRead; FilterInputBuffer(buf, filteredBytesRead, sizeof(buf)-1); ret += filteredBytesRead; buf[filteredBytesRead] = '\0'; MessageRef inMsg; // demand-allocated int32 beginAt = 0; for (uint32 i=0; i<filteredBytesRead; i++) { char nextChar = buf[i]; if ((nextChar == '\r')||(nextChar == '\n')) { buf[i] = '\0'; // terminate the string here if ((nextChar == '\r')||(_prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &buf[beginAt]); beginAt = i+1; } _prevCharWasCarriageReturn = (nextChar == '\r'); } if (beginAt < (int32)filteredBytesRead) { if (_flushPartialIncomingLines) inMsg = AddIncomingText(inMsg, &buf[beginAt]); else _incomingText += &buf[beginAt]; } if (inMsg()) receiver.CallMessageReceivedFromGateway(inMsg); } return ret; }
int32 PacketTunnelIOGateway :: DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes) { if (_inputPacketBuffer.SetNumBytes(_maxTransferUnit, false) != B_NO_ERROR) return -1; bool firstTime = true; uint32 totalBytesRead = 0; while((totalBytesRead < maxBytes)&&((firstTime)||(IsSuggestedTimeSliceExpired() == false))) { firstTime = false; int32 bytesRead = GetDataIO()()->Read(_inputPacketBuffer.GetBuffer(), _inputPacketBuffer.GetNumBytes()); //printf(" READ " INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes\n", bytesRead, _inputPacketBuffer.GetNumBytes()); if (bytesRead > 0) { totalBytesRead += bytesRead; IPAddressAndPort fromIAP; const PacketDataIO * packetIO = dynamic_cast<PacketDataIO *>(GetDataIO()()); if (packetIO) fromIAP = packetIO->GetSourceOfLastReadPacket(); const uint8 * p = (const uint8 *) _inputPacketBuffer.GetBuffer(); if ((_allowMiscData)&&((bytesRead < (int32)FRAGMENT_HEADER_SIZE)||(((uint32)B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(p))) != _magic))) { // If we're allowed to handle miscellaneous data, we'll just pass it on through verbatim ByteBuffer temp; temp.AdoptBuffer(bytesRead, const_cast<uint8 *>(p)); HandleIncomingMessage(receiver, ByteBufferRef(&temp, false), fromIAP); (void) temp.ReleaseBuffer(); } else { const uint8 * invalidByte = p+bytesRead; while(invalidByte-p >= (int32)FRAGMENT_HEADER_SIZE) { const uint32 magic = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[0*sizeof(uint32)])); const uint32 sexID = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[1*sizeof(uint32)])); const uint32 messageID = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[2*sizeof(uint32)])); const uint32 offset = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[3*sizeof(uint32)])); const uint32 chunkSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[4*sizeof(uint32)])); const uint32 totalSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[5*sizeof(uint32)])); //printf(" PARSE magic=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " sex=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " messageID=" UINT32_FORMAT_SPEC " offset=" UINT32_FORMAT_SPEC " chunkSize=" UINT32_FORMAT_SPEC " totalSize=" UINT32_FORMAT_SPEC "\n", magic, _magic, sexID, _sexID, messageID, offset, chunkSize, totalSize); p += FRAGMENT_HEADER_SIZE; if ((magic == _magic)&&((_sexID == 0)||(_sexID != sexID))&&((invalidByte-p >= (int32)chunkSize)&&(totalSize <= _maxIncomingMessageSize))) { ReceiveState * rs = _receiveStates.Get(fromIAP); if (rs == NULL) { if (offset == 0) rs = _receiveStates.PutAndGet(fromIAP, ReceiveState(messageID)); if (rs) { rs->_buf = GetByteBufferFromPool(totalSize); if (rs->_buf() == NULL) { _receiveStates.Remove(fromIAP); rs = NULL; } } } if (rs) { if ((offset == 0)||(messageID != rs->_messageID)) { // A new message... start receiving it (but only if we are starting at the beginning) rs->_messageID = messageID; rs->_offset = 0; rs->_buf()->SetNumBytes(totalSize, false); } uint32 rsSize = rs->_buf()->GetNumBytes(); //printf(" CHECK: offset=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " %s\n", offset, rs->_offset, (offset==rs->_offset)?"":"DISCONTINUITY!!!"); if ((messageID == rs->_messageID)&&(totalSize == rsSize)&&(offset == rs->_offset)&&(offset+chunkSize <= rsSize)) { memcpy(rs->_buf()->GetBuffer()+offset, p, chunkSize); rs->_offset += chunkSize; if (rs->_offset == rsSize) { HandleIncomingMessage(receiver, rs->_buf, fromIAP); rs->_offset = 0; rs->_buf()->Clear(rsSize > MAX_CACHE_SIZE); } } else { LogTime(MUSCLE_LOG_DEBUG, "Unknown fragment (" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ") received from %s, ignoring it.\n", messageID, offset, chunkSize, totalSize, fromIAP.ToString()()); rs->_offset = 0; rs->_buf()->Clear(rsSize > MAX_CACHE_SIZE); } } p += chunkSize; } else break; } } } else if (bytesRead < 0) return -1; else break; } return totalBytesRead; }
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; }
int32 PlainTextMessageIOGateway :: DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes) { TCHECKPOINT; int32 ret = 0; const int tempBufSize = 2048; char buf[tempBufSize]; const uint32 mtuSize = GetMaximumPacketSize(); if (mtuSize > 0) { // Packet-IO implementation char * pbuf = buf; int pbufSize = tempBufSize; ByteBufferRef bigBuf; if (mtuSize > tempBufSize) { // Just in case our MTU size is too big for our on-stack buffer bigBuf = GetByteBufferFromPool(mtuSize); if (bigBuf()) { pbuf = (char *) bigBuf()->GetBuffer(); pbufSize = bigBuf()->GetNumBytes(); } } while(true) { IPAddressAndPort sourceIAP; const int32 bytesRead = GetPacketDataIO()->ReadFrom(pbuf, muscleMin(maxBytes, (uint32)(pbufSize-1)), sourceIAP); if (bytesRead < 0) return (ret > 0) ? ret : -1; else if (bytesRead > 0) { uint32 filteredBytesRead = bytesRead; FilterInputBuffer(pbuf, filteredBytesRead, pbufSize-1); ret += filteredBytesRead; pbuf[filteredBytesRead] = '\0'; bool prevCharWasCarriageReturn = false; // deliberately a local var, since UDP packets should be independent of each other MessageRef inMsg; // demand-allocated int32 beginAt = 0; for (uint32 i=0; i<filteredBytesRead; i++) { char nextChar = pbuf[i]; if ((nextChar == '\r')||(nextChar == '\n')) { pbuf[i] = '\0'; // terminate the string here if ((nextChar == '\r')||(prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]); beginAt = i+1; } prevCharWasCarriageReturn = (nextChar == '\r'); } if (beginAt < (int32)filteredBytesRead) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]); if (inMsg()) { (void) inMsg()->AddFlat(PR_NAME_PACKET_REMOTE_LOCATION, sourceIAP); receiver.CallMessageReceivedFromGateway(inMsg); inMsg.Reset(); } ret += bytesRead; } else return ret; } } else { // Stream-IO implementation const int32 bytesRead = GetDataIO()()->Read(buf, muscleMin(maxBytes, (uint32)(sizeof(buf)-1))); if (bytesRead < 0) { FlushInput(receiver); return -1; } if (bytesRead > 0) { uint32 filteredBytesRead = bytesRead; FilterInputBuffer(buf, filteredBytesRead, sizeof(buf)-1); ret += filteredBytesRead; buf[filteredBytesRead] = '\0'; MessageRef inMsg; // demand-allocated int32 beginAt = 0; for (uint32 i=0; i<filteredBytesRead; i++) { char nextChar = buf[i]; if ((nextChar == '\r')||(nextChar == '\n')) { buf[i] = '\0'; // terminate the string here if ((nextChar == '\r')||(_prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &buf[beginAt]); beginAt = i+1; } _prevCharWasCarriageReturn = (nextChar == '\r'); } if (beginAt < (int32)filteredBytesRead) { if (_flushPartialIncomingLines) inMsg = AddIncomingText(inMsg, &buf[beginAt]); else _incomingText += &buf[beginAt]; } if (inMsg()) receiver.CallMessageReceivedFromGateway(inMsg); } } return ret; }