Skip to content

Add codec to encode/decode GRPC data frame.#414

Merged
mattklein123 merged 16 commits intoenvoyproxy:masterfrom
fengli79:master
Feb 9, 2017
Merged

Add codec to encode/decode GRPC data frame.#414
mattklein123 merged 16 commits intoenvoyproxy:masterfrom
fengli79:master

Conversation

@fengli79
Copy link
Contributor

@fengli79 fengli79 commented Feb 2, 2017

Add codec to encode/decode GRPC data frame.

@PiotrSikora
Copy link
Contributor

Is there any reason why this is written from scratch and not using https://github.com/grpc/grpc?

@mattklein123
Copy link
Member

Per @PiotrSikora it would be very, very, very nice if we could work with the gRPC c++ folks to refactor slightly so that we can consume the generated RPC stubs (codec, etc.) but provide our own transport. I already replicated some stuff for unary calls out of expediency, but now that you are all involved it would be great to fix this for real. Can we at least SWAG what it would take before reimplementing?

@louiscryan
Copy link

@ctiller - Hey Craig! Its probably a good time to start discussing some of the integration points between Envoy and GRPC

In this particular instance WDYT? Would it be easy to factor out the framing code from core? If not then this should probably proceed as is and we have a longer term goal around factoring

@fengli79
Copy link
Contributor Author

fengli79 commented Feb 8, 2017

Any chance to get this submitted? Refactor GRPC c core to reuse the framer is not trivial and won't happen any time soon.
This pull request is to unblock the data path for grpc-web. For the control plane GRPC requests initiated by envoy can be a different topic.

Here's the situation:

  1. for grpc-web, we need a generic client, means the target grpc method is denoted by the request on the wire. Thus no code gen needed.
  2. for grpc request to control plane services, code gen might be helpful, but not a blocker, if code gen is highly desired, you can start to use it anyway, remained part is merely optimization.

@mattklein123
Copy link
Member

@fengli79 I wasn't aware this was ready for review. @RomanDzhabarov can you take a first pass?

@RomanDzhabarov
Copy link
Member

will check this tonight

// @param input supplies the binary octets wrapped in a GRPC data frame.
// @param input supplies the buffer to store the decoded data.
// @return bool whether the decoding success.
bool Decode(Buffer::Instance& input, std::vector<Frame>* output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually in envoy we pass by ref in this case (less to deal with null checks, alloc/dealloc/etc).


// Decodes the given buffer with GRPC data frame.
// @param input supplies the binary octets wrapped in a GRPC data frame.
// @param input supplies the buffer to store the decoded data.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix param name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// @param flags supplies the GRPC data frame flags.
// @param length supplies the GRPC data frame length.
// @param output the buffer to store the encoded data, it's size must be 5.
void NewFrame(uint8_t flags, uint64_t length, uint8_t* output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using std::array<uint8_t, 5>? (would be good to enforce size 5 requirement here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bool Decode(Buffer::Instance& input, std::vector<Frame>* output);

private:
// Wiring format of GRPC data frame header:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also put a link to official docs if any for this format?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// @param flags supplies the GRPC data frame flags.
// @param length supplies the GRPC data frame length.
// @param output the buffer to store the encoded data, it's size must be 5.
void NewFrame(uint8_t flags, uint64_t length, uint8_t* output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newFrame

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// @param input supplies the binary octets wrapped in a GRPC data frame.
// @param input supplies the buffer to store the decoded data.
// @return bool whether the decoding success.
bool Decode(Buffer::Instance& input, std::vector<Frame>* output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decode(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

struct Frame {
uint8_t flags;
uint32_t length;
Buffer::Instance* data;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buffer::InstancePtr

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Change to use Buffer::IntancePtr.
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few nits otherwise looks good

@@ -0,0 +1,78 @@
#pragma once

#include <array>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

del or add to precompiled header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

enum class CompressionAlgorithm { None, Gzip };

struct Frame {
uint8_t flags;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ postfix for members (.e.g, flags_)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it needed for public struct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have been doing this for public structs so to be consistent I would change it. (I don't really care that much about this but might as well be consistent).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// Creates a new GRPC data frame with the given flags and length.
// @param flags supplies the GRPC data frame flags.
// @param length supplies the GRPC data frame length.
// @param output the buffer to store the encoded data, it's size must be 5.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... data. Its size must be 5."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// Decodes the given buffer with GRPC data frame.
// @param input supplies the binary octets wrapped in a GRPC data frame.
// @param output supplies the buffer to store the decoded data.
// @return bool whether the decoding success.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... succeeded or not."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool decode(Buffer::Instance& input, std::vector<Frame>& output);

private:
// Wiring format (http://www.grpc.io/docs/guides/wire.html) of GRPC data frame
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Wire format ..."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

//
// A fixed header consists of five bytes.
// The first byte is the Flag. The last one "C" bit indicates if the message
// is compressed or not (0 is uncompressed, 1 is compressed). The rest seven
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other seven

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// A fixed header consists of five bytes.
// The first byte is the Flag. The last one "C" bit indicates if the message
// is compressed or not (0 is uncompressed, 1 is compressed). The rest seven
// "R" bits is reserved for future use.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are reserved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -0,0 +1,115 @@
#include <array>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

del or add to precompiled header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


#include "common/buffer/buffer_impl.h"
#include "common/grpc/codec.h"
#include "test/generated/helloworld.pb.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: newline before this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

EXPECT_EQ("hello", result.name());
}
}
} // Grpc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: newline before this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

output.push_back(std::move(frame_));
frame_.flags = 0;
frame_.length = 0;
frame_.data.reset();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not think there is a need to .reset() here as ownership was transferred to the frame in output

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, done.


std::vector<Frame> frames;
Decoder decoder;
decoder.decode(buffer, frames);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EXPECT_TRUE and in the case below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@RomanDzhabarov
Copy link
Member

LGTM, one comment left

}
}
}
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to check state_ to see if the input was a partial GRPC frame? (e.g. frame length = 100 but only 10 bytes in input buffer.
Also add a test for that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test added.
You don't need to check the state_. If grpc call get aborted when decoding, you should be able to know that from the HTTP2 layer, as the stream will be reset. Any intermediate state and buffer can be discarded. The workflow would be keep feeding data to the decoder as they arrive and check if there's one or more complete frame get decoded.

@mattklein123
Copy link
Member

@fengli79 one other thing came to mind when I read @lizan comment. You aren't draining the buffer anywhere. I'm not sure if this is intentional, but either way I think some changes are needed:

  1. If you intend for the caller to drain the buffer, you should change decode() to take a const Buffer::Instance&, and document that decode consumes all bytes if it returns true. Then the caller can drain.
  2. Have decode() drain the buffer itself, and document that it will drain all data, and add tests to this effect.

@fengli79
Copy link
Contributor Author

fengli79 commented Feb 9, 2017 via email

@fengli79
Copy link
Contributor Author

fengli79 commented Feb 9, 2017 via email

@mattklein123
Copy link
Member

OK that's fine. Then just make the param const and document that all bytes are consumed if it's not already documented.

Change the CodecTest to GrpcCodecTest.
@fengli79
Copy link
Contributor Author

fengli79 commented Feb 9, 2017

@mattklein123 With a second think, I change it to drain the inputs when decoding succeeded. Also change the CodecTest to GrpcCodecTest to avoid naming conflicts with other tests.

@mattklein123
Copy link
Member

@fengli79 looks good. I forgot that you need to sign CLA. Can you ACK back when done and I will merge.

@fengli79
Copy link
Contributor Author

fengli79 commented Feb 9, 2017 via email

@mattklein123 mattklein123 merged commit f44e437 into envoyproxy:master Feb 9, 2017
rshriram added a commit to rshriram/envoy that referenced this pull request Oct 30, 2018
rshriram added a commit to rshriram/envoy that referenced this pull request Oct 30, 2018
* Revert "envoy sha update (envoyproxy#414)"

This reverts commit ebb5ef1.

* Revert "Fix mixer forward attribute bug. (envoyproxy#412)"

This reverts commit 4f07917.
rshriram pushed a commit to rshriram/envoy that referenced this pull request Oct 30, 2018
Automatic merge from submit-queue.

[DO NOT MERGE] Auto PR to update dependencies of mixerclient

This PR will be merged automatically once checks are successful.
```release-note
none
```
wolfguoliang pushed a commit to wolfguoliang/envoy that referenced this pull request Jan 23, 2021
….rst (envoyproxy#414)

* zh-translation:docs/root/configuration/observability/access_log/usage.rst

* zh-translation:docs/root/configuration/observability/access_log/usage.rst

* zh-translation:docs/root/configuration/observability/access_log/usage.rst

* zh-translation:docs/root/configuration/observability/access_log/usage.rst

Co-authored-by: 包仁义 <renyi.bao@yiducloud.cn>
mathetake added a commit that referenced this pull request Mar 3, 2026
**Commit Message**

This fixes the latest chart's image tag which previously was set to
v0.0.0-latest. This fixes the helm-package recipe and now it points to
:latest.

**Related Issues/PRs (if applicable)**

Follow up on #395

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants