you can allocate a big memory buffer on heap and remember the content 
length of the already received data in buffer,
every time when alloc_buf_cb is triggered, give the pointer that points to 
the end of the content to uv_buf.
In Read callback, check the content length against the value of the frame 
header

#define THRIFT_FRAME_MAX_LEN 65536
#define THRIFT_FRAME_HEADER_LEN 4
class ThriftFrame
{
public:
  char buf_[THRIFT_FRAME_MAX_LEN] = {0};

  char *data_buf_ = buf_ + THRIFT_FRAME_HEADER_LEN;
  size_t content_len_ = 0;
};

// uv_alloc_cb alloc buffer for receiving data in a frame.
// if frame is already allocated, receive data at the end of frame buffer
void AllocBufForFrameCB(uv_handle_t* handle, size_t suggested_size, 
uv_buf_t* buf) {
  UvContext *ctx = (UvContext *) handle->data;
  ThriftFrame *frame;

  unordered_map<uv_stream_t *, ThriftFrame *>::const_iterator it = 
ctx->stream_frame_map.find((uv_stream_t *)handle);
  if (it == ctx->stream_frame_map.end() || it->second == NULL) {
    // allocate a new frame
    frame = new ThriftFrame;
    ctx->stream_frame_map[(uv_stream_t *)handle] = frame;
  } else {
    // a frame is already allocated, use the partically filled frame
    frame = it->second;
  }

  buf->base = frame->data_buf_ + frame->content_len_;

  int frame_len = *(int *)frame->buf_;

  buf->len = frame_len ? frame_len - frame->content_len_:
             THRIFT_FRAME_MAX_LEN - THRIFT_FRAME_HEADER_LEN - 
frame->content_len_;
}

// uv_read_cb  Read Call back for parsing raw data to thrift frame
// It might be called multiple times to receive a compelte thrift frame
// On receival of a complete thrift frame, this call back function will call
// ProcessThriftFrame() to process the received frame
void ProcessIncomingRawDataCB(uv_stream_t *stream, ssize_t nread, const 
uv_buf_t *buf) {
  UvContext *ctx = (UvContext *) stream->data;
  ThriftFrame *frame = ctx->stream_frame_map[stream];

  if (nread <= 0) {
    LOG(ERROR) << "Read error: " << uv_err_name(nread);

    LOG(INFO) << "Connection to client ("
    << UvIPUtil::get_sock_host_from_uv_tcp_t((uv_tcp_t *)stream) << " <=> "
    <<") closed. ";

    // close stream
    uv_close((uv_handle_t*) stream, NULL);

    // release memory allocated for receiving frame
    delete ctx->stream_frame_map[stream];
    ctx->stream_frame_map.erase(stream);
  } else if (nread > 0) {
    frame->content_len_ += nread;

    // check if frame has complete data
    int frame_len = *(int *)frame->buf_;
    if (frame_len == frame->content_len_ - THRIFT_FRAME_HEADER_LEN) {
      DLOG(INFO) << "Received a complete frame, frame length:" << frame_len;
      UvConnection *connection = 
ctx->client_stream_to_connection_map[stream];
      ProcessThriftMessage(connection, frame);
    }
  }
}

On Sunday, December 8, 2013 at 11:03:50 AM UTC-8, Thiago Arruda wrote:
>
> Hi
>
> I'm writing a small program that reads messages from a stream. Before each 
> message, an integer will arrive specifying the size of the following 
> message.
>
> I understand libuv will call my own function to allocate buffers with a 
> suggested size, but since I know the size of the incoming message, I think 
> it makes more sense to use that as the buffer size(Please correct if my 
> assumption is wrong, I'm not an expert C programmer).
>
> What would be the 'pretty' way to handle this in libuv? I would rather not 
> use global variables to store the size of the next message.
>
> Thiago
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/libuv.
For more options, visit https://groups.google.com/d/optout.

Reply via email to