diff options
author | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2017-09-16 13:40:57 +0300 |
---|---|---|
committer | Petteri Aimonen <jpa@git.mail.kapsi.fi> | 2017-09-16 13:40:57 +0300 |
commit | e21e78c67cbd6566fe9d8368eeaf3298ae22b75d (patch) | |
tree | cb2a44a3a93b3d6b9fb049219adcf6dcd003235c | |
parent | 03a7f76ef6df8ecfdf493c732a67a8e2f687bb90 (diff) |
Add pb_en/decode_nullterminated() (part of #278)
Nanopb has traditionally supported messages to be terminated with a zero tag.
However, this is not really standard protobuf behaviour, so it makes sense
to separate it into a different function. Because it is a breaking change,
it will happen in 0.4.0 release. But I add the functions here early so that
new code can start using them now.
Also changed the network_server example to use en/decode_delimited(), which
is the more common protobuf method of simple message framing.
-rw-r--r-- | examples/network_server/client.c | 8 | ||||
-rw-r--r-- | examples/network_server/server.c | 8 | ||||
-rw-r--r-- | pb_decode.c | 6 | ||||
-rw-r--r-- | pb_decode.h | 7 | ||||
-rw-r--r-- | pb_encode.c | 10 | ||||
-rw-r--r-- | pb_encode.h | 6 |
6 files changed, 37 insertions, 8 deletions
diff --git a/examples/network_server/client.c b/examples/network_server/client.c index 00f6dab..ca0c68e 100644 --- a/examples/network_server/client.c +++ b/examples/network_server/client.c @@ -49,7 +49,6 @@ bool listdir(int fd, char *path) { ListFilesRequest request = {}; pb_ostream_t output = pb_ostream_from_socket(fd); - uint8_t zero = 0; /* In our protocol, path is optional. If it is not given, * the server will list the root directory. */ @@ -71,14 +70,11 @@ bool listdir(int fd, char *path) /* Encode the request. It is written to the socket immediately * through our custom stream. */ - if (!pb_encode(&output, ListFilesRequest_fields, &request)) + if (!pb_encode_delimited(&output, ListFilesRequest_fields, &request)) { fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output)); return false; } - - /* We signal the end of request with a 0 tag. */ - pb_write(&output, &zero, 1); } /* Read back the response from server */ @@ -90,7 +86,7 @@ bool listdir(int fd, char *path) * filenames as they arrive. */ response.file.funcs.decode = &printfile_callback; - if (!pb_decode(&input, ListFilesResponse_fields, &response)) + if (!pb_decode_delimited(&input, ListFilesResponse_fields, &response)) { fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input)); return false; diff --git a/examples/network_server/server.c b/examples/network_server/server.c index 46a5f38..f500dcd 100644 --- a/examples/network_server/server.c +++ b/examples/network_server/server.c @@ -50,6 +50,10 @@ bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * cons return false; } + /* Because the main program uses pb_encode_delimited(), this callback will be + * called twice. Rewind the directory for the next call. */ + rewinddir(dir); + return true; } @@ -66,7 +70,7 @@ void handle_connection(int connfd) ListFilesRequest request = {}; pb_istream_t input = pb_istream_from_socket(connfd); - if (!pb_decode(&input, ListFilesRequest_fields, &request)) + if (!pb_decode_delimited(&input, ListFilesRequest_fields, &request)) { printf("Decode failed: %s\n", PB_GET_ERROR(&input)); return; @@ -98,7 +102,7 @@ void handle_connection(int connfd) response.file.arg = directory; } - if (!pb_encode(&output, ListFilesResponse_fields, &response)) + if (!pb_encode_delimited(&output, ListFilesResponse_fields, &response)) { printf("Encoding failed: %s\n", PB_GET_ERROR(&output)); } diff --git a/pb_decode.c b/pb_decode.c index 4a65758..391d463 100644 --- a/pb_decode.c +++ b/pb_decode.c @@ -1032,6 +1032,12 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * return status; } +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); +} + #ifdef PB_ENABLE_MALLOC /* Given an oneof field, if there has already been a field inside this oneof, * release it before overwriting with a different one. */ diff --git a/pb_decode.h b/pb_decode.h index 4fe7995..d51ce39 100644 --- a/pb_decode.h +++ b/pb_decode.h @@ -85,6 +85,13 @@ bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *des */ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); +/* Same as pb_decode, except allows the message to be terminated with a null byte. + * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour + * is not supported in most other protobuf implementations, so pb_decode_delimited() + * is a better option for compatibility. + */ +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + #ifdef PB_ENABLE_MALLOC /* Release any allocated pointer fields. If you use dynamic allocation, you should * call this for any successfully decoded message when you are done with it. If diff --git a/pb_encode.c b/pb_encode.c index 2ff8f1d..e957d42 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -511,6 +511,16 @@ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const return pb_encode_submessage(stream, fields, src_struct); } +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_byte_t zero = 0; + + if (!pb_encode(stream, fields, src_struct)) + return false; + + return pb_write(stream, &zero, 1); +} + bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) { pb_ostream_t stream = PB_OSTREAM_SIZING; diff --git a/pb_encode.h b/pb_encode.h index d18a72d..8bf78dd 100644 --- a/pb_encode.h +++ b/pb_encode.h @@ -71,6 +71,12 @@ bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_ */ bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); +/* Same as pb_encode, but appends a null byte to the message for termination. + * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() + * is a better option for compatibility. + */ +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + /* Encode the message to get the size of the encoded data, but do not store * the data. */ bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); |