| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| #include "qpid/amqp/Sasl.h" |
| #include "qpid/amqp/Decoder.h" |
| #include "qpid/amqp/Descriptor.h" |
| #include "qpid/amqp/Encoder.h" |
| #include "qpid/log/Statement.h" |
| #include "qpid/framing/Buffer.h" |
| #include "qpid/framing/ProtocolVersion.h" |
| #include "qpid/framing/ProtocolInitiation.h" |
| #include <string.h> |
| |
| namespace qpid { |
| namespace amqp { |
| |
| Sasl::Sasl(const std::string& i) : id(i), buffer(2*512/*AMQP 1.0's MAX_MIN_FRAME_SIZE - is this enough though?*/), encoder(&buffer[0], buffer.size()) {} |
| Sasl::~Sasl() {} |
| |
| void* Sasl::startFrame() |
| { |
| //write sasl frame header, leaving 4 bytes for total size |
| char* start = encoder.skip(4); |
| encoder.write((uint8_t) 0x02);//data offset |
| encoder.write((uint8_t) 0x01);//frame type |
| encoder.write((uint16_t) 0x0000);//ignored |
| return start; |
| } |
| |
| void Sasl::endFrame(void* frame) |
| { |
| //now backfill the frame size |
| char* start = (char*) frame; |
| char* current = &buffer[encoder.getPosition()]; |
| uint32_t frameSize = current - start; |
| Encoder backfill(start, 4); |
| backfill.write(frameSize); |
| QPID_LOG(trace, "Completed encoding of frame of " << frameSize << " bytes"); |
| } |
| |
| |
| std::size_t Sasl::read(const char* data, size_t available) |
| { |
| size_t consumed = 0; |
| while (available - consumed > 4/*framesize*/) { |
| Decoder decoder(data+consumed, available-consumed); |
| //read frame-header |
| uint32_t frameSize = decoder.readUInt(); |
| if (frameSize > decoder.getSize()) break;//don't have all the data for this frame yet |
| |
| QPID_LOG(trace, "Reading SASL frame of size " << frameSize); |
| decoder.resetSize(frameSize); |
| uint8_t dataOffset = decoder.readUByte(); |
| uint8_t frameType = decoder.readUByte(); |
| if (frameType != 0x01) { |
| QPID_LOG(error, "Expected SASL frame; got type " << frameType); |
| } |
| uint16_t ignored = decoder.readUShort(); |
| if (ignored) { |
| QPID_LOG(info, "Got non null bytes at end of SASL frame header"); |
| } |
| |
| //body is at offset 4*dataOffset from the start |
| size_t skip = dataOffset*4 - 8; |
| if (skip) { |
| QPID_LOG(info, "Offset for sasl frame was not as expected"); |
| decoder.advance(skip); |
| } |
| decoder.read(*this); |
| consumed += decoder.getPosition(); |
| } |
| return consumed; |
| } |
| |
| std::size_t Sasl::write(char* data, size_t size) |
| { |
| size_t available = encoder.getPosition(); |
| if (available) { |
| size_t encoded = available > size ? size : available; |
| ::memcpy(data, &buffer[0], encoded); |
| size_t remainder = encoder.getPosition() - encoded; |
| if (remainder) { |
| //shuffle |
| ::memcpy(&buffer[0], &buffer[size], remainder); |
| } |
| encoder.resetPosition(remainder); |
| return encoded; |
| } else { |
| return 0; |
| } |
| } |
| |
| std::size_t Sasl::readProtocolHeader(const char* buffer, std::size_t size) |
| { |
| framing::ProtocolInitiation pi(qpid::framing::ProtocolVersion(1,0,qpid::framing::ProtocolVersion::SASL)); |
| if (size >= pi.encodedSize()) { |
| qpid::framing::Buffer out(const_cast<char*>(buffer), size); |
| pi.decode(out); |
| QPID_LOG_CAT(debug, protocol, id << " read protocol header: " << pi); |
| return pi.encodedSize(); |
| } else { |
| return 0; |
| } |
| } |
| std::size_t Sasl::writeProtocolHeader(char* buffer, std::size_t size) |
| { |
| framing::ProtocolInitiation pi(qpid::framing::ProtocolVersion(1,0,qpid::framing::ProtocolVersion::SASL)); |
| if (size >= pi.encodedSize()) { |
| QPID_LOG_CAT(debug, protocol, id << " writing protocol header: " << pi); |
| qpid::framing::Buffer out(buffer, size); |
| pi.encode(out); |
| return pi.encodedSize(); |
| } else { |
| QPID_LOG_CAT(warning, protocol, id << " insufficient buffer for protocol header: " << size) |
| return 0; |
| } |
| } |
| |
| }} // namespace qpid::amqp |