/** * Decode a BFCP message from a buffer * * @param msgp Pointer to allocated and decoded BFCP message * @param mb Mbuf to decode from * @param src Source network address (optional) * * @return 0 if success, otherwise errorcode */ int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb, const struct sa *src) { struct bfcp_msg *msg; size_t start, extra; int err; if (!msgp || !mb) return EINVAL; start = mb->pos; msg = mem_zalloc(sizeof(*msg), destructor); if (!msg) return ENOMEM; err = bfcp_hdr_decode(mb, &msg->hdr); if (err) { mb->pos = start; goto out; } extra = mbuf_get_left(mb) - 4*msg->hdr.len; while (mbuf_get_left(mb) - extra >= ATTR_HDR_SIZE) { struct bfcp_attr *attr; err = bfcp_attr_decode(&attr, mb); if (err) break; list_append(&msg->attrl, &attr->le, attr); } if (src) msg->src = *src; out: if (err) mem_deref(msg); else *msgp = msg; return err; }
int build_msg_fragments( std::vector<mbuf_t*> &fragBufs, mbuf_t *msgBuf, size_t maxMsgSize ) { assert(kHeaderWithFragSize < maxMsgSize); int err = 0; size_t bufSize = msgBuf->end; if (bufSize < maxMsgSize) { fragBufs.push_back(msgBuf); mem_ref(msgBuf); } else { size_t start = msgBuf->pos; size_t payloadSize = bufSize - kHeaderSize; size_t maxFragPayloadSize = (maxMsgSize - kHeaderWithFragSize) & ~0x3; size_t fragmentCount = (payloadSize + maxFragPayloadSize - 1) / maxFragPayloadSize; std::vector<mbuf_t*> bufs; bufs.reserve(fragmentCount); bfcp_hdr_t header; err = bfcp_hdr_decode(&header, msgBuf); assert(!err); assert(!header.f); size_t remainPayloadSize = payloadSize; for (size_t i = 0; i < fragmentCount; ++i) { mbuf_t *buf = mbuf_alloc(maxMsgSize); if (!buf) { err = ENOMEM; break; } bufs.push_back(buf); header.f = 1; header.fragoffset = i * maxFragPayloadSize / 4; size_t actualPayloadSize = (std::min)(maxFragPayloadSize, remainPayloadSize); header.fraglen = actualPayloadSize / 4; remainPayloadSize -= actualPayloadSize; err = bfcp_hdr_encode(buf, &header); if (err) break; mbuf_write_mem(buf, msgBuf->buf + msgBuf->pos, actualPayloadSize); msgBuf->pos += actualPayloadSize; } if (err) { for (auto buf : bufs) { mem_deref(buf); } } else { assert(msgBuf->pos == msgBuf->end); msgBuf->pos = start; fragBufs.insert(fragBufs.end(), bufs.begin(), bufs.end()); } } return err; }