parent
241a5ad3cb
commit
49433744ee
28 changed files with 4300 additions and 1 deletions
@ -0,0 +1,87 @@ |
||||
/* Automatically generated nanopb constant definitions */ |
||||
/* Generated by nanopb-0.3.5-dev at Wed Oct 21 14:38:11 2015. */ |
||||
|
||||
#include "load_balancer.pb.h" |
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
|
||||
|
||||
const pb_field_t grpc_lb_v0_Duration_fields[3] = { |
||||
PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Duration, seconds, seconds, 0), |
||||
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Duration, nanos, seconds, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3] = { |
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v0_InitialLoadBalanceRequest_fields), |
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v0_ClientStats_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceRequest, name, name, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_ClientStats_fields[4] = { |
||||
PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, grpc_lb_v0_ClientStats, total_requests, total_requests, 0), |
||||
PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, client_rpc_errors, total_requests, 0), |
||||
PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ClientStats, dropped_requests, client_rpc_errors, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3] = { |
||||
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, grpc_lb_v0_LoadBalanceResponse, initial_response, initial_response, &grpc_lb_v0_InitialLoadBalanceResponse_fields), |
||||
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_LoadBalanceResponse, server_list, initial_response, &grpc_lb_v0_ServerList_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_InitialLoadBalanceResponse, client_config, client_config, 0), |
||||
PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, load_balancer_delegate, client_config, 0), |
||||
PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v0_Duration_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_ServerList_fields[3] = { |
||||
PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, grpc_lb_v0_ServerList, servers, servers, &grpc_lb_v0_Server_fields), |
||||
PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v0_ServerList, expiration_interval, servers, &grpc_lb_v0_Duration_fields), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
const pb_field_t grpc_lb_v0_Server_fields[5] = { |
||||
PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v0_Server, ip_address, ip_address, 0), |
||||
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, port, ip_address, 0), |
||||
PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, load_balance_token, port, 0), |
||||
PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v0_Server, drop_request, load_balance_token, 0), |
||||
PB_LAST_FIELD |
||||
}; |
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */ |
||||
#if !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit |
||||
* field descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v0_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) |
||||
#endif |
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) |
||||
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
|
||||
* compile-time option. You can do that in pb.h or on compiler command line. |
||||
*
|
||||
* The reason you need to do this is that some of your messages contain tag |
||||
* numbers or field sizes that are larger than what can fit in the default |
||||
* 8 bit descriptors. |
||||
*/ |
||||
PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v0_ServerList, servers) < 256 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server) |
||||
#endif |
||||
|
||||
|
@ -0,0 +1,153 @@ |
||||
/* Automatically generated nanopb header */ |
||||
/* Generated by nanopb-0.3.5-dev at Wed Oct 21 14:38:11 2015. */ |
||||
|
||||
#ifndef PB_LOAD_BALANCER_PB_H_INCLUDED |
||||
#define PB_LOAD_BALANCER_PB_H_INCLUDED |
||||
|
||||
#include "src/core/client_config/lb_policies/nanopb/pb.h" |
||||
#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 |
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 30 |
||||
#error Regenerate this file with the current version of nanopb generator. |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Struct definitions */ |
||||
typedef struct _grpc_lb_v0_ClientStats { |
||||
bool has_total_requests; |
||||
int64_t total_requests; |
||||
bool has_client_rpc_errors; |
||||
int64_t client_rpc_errors; |
||||
bool has_dropped_requests; |
||||
int64_t dropped_requests; |
||||
} grpc_lb_v0_ClientStats; |
||||
|
||||
typedef struct _grpc_lb_v0_Duration { |
||||
bool has_seconds; |
||||
int64_t seconds; |
||||
bool has_nanos; |
||||
int32_t nanos; |
||||
} grpc_lb_v0_Duration; |
||||
|
||||
typedef struct _grpc_lb_v0_InitialLoadBalanceRequest { |
||||
bool has_name; |
||||
char name[GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH]; |
||||
} grpc_lb_v0_InitialLoadBalanceRequest; |
||||
|
||||
typedef PB_BYTES_ARRAY_T(64) grpc_lb_v0_Server_load_balance_token_t; |
||||
typedef struct _grpc_lb_v0_Server { |
||||
bool has_ip_address; |
||||
char ip_address[46]; |
||||
bool has_port; |
||||
int32_t port; |
||||
bool has_load_balance_token; |
||||
grpc_lb_v0_Server_load_balance_token_t load_balance_token; |
||||
bool has_drop_request; |
||||
bool drop_request; |
||||
} grpc_lb_v0_Server; |
||||
|
||||
typedef struct _grpc_lb_v0_InitialLoadBalanceResponse { |
||||
bool has_client_config; |
||||
char client_config[64]; |
||||
bool has_load_balancer_delegate; |
||||
char load_balancer_delegate[64]; |
||||
bool has_client_stats_report_interval; |
||||
grpc_lb_v0_Duration client_stats_report_interval; |
||||
} grpc_lb_v0_InitialLoadBalanceResponse; |
||||
|
||||
typedef struct _grpc_lb_v0_LoadBalanceRequest { |
||||
bool has_initial_request; |
||||
grpc_lb_v0_InitialLoadBalanceRequest initial_request; |
||||
bool has_client_stats; |
||||
grpc_lb_v0_ClientStats client_stats; |
||||
} grpc_lb_v0_LoadBalanceRequest; |
||||
|
||||
typedef struct _grpc_lb_v0_ServerList { |
||||
pb_callback_t servers; |
||||
bool has_expiration_interval; |
||||
grpc_lb_v0_Duration expiration_interval; |
||||
} grpc_lb_v0_ServerList; |
||||
|
||||
typedef struct _grpc_lb_v0_LoadBalanceResponse { |
||||
bool has_initial_response; |
||||
grpc_lb_v0_InitialLoadBalanceResponse initial_response; |
||||
bool has_server_list; |
||||
grpc_lb_v0_ServerList server_list; |
||||
} grpc_lb_v0_LoadBalanceResponse; |
||||
|
||||
/* Default values for struct fields */ |
||||
|
||||
/* Initializer values for message structs */ |
||||
#define grpc_lb_v0_Duration_init_default {false, 0, false, 0} |
||||
#define grpc_lb_v0_LoadBalanceRequest_init_default {false, grpc_lb_v0_InitialLoadBalanceRequest_init_default, false, grpc_lb_v0_ClientStats_init_default} |
||||
#define grpc_lb_v0_InitialLoadBalanceRequest_init_default {false, ""} |
||||
#define grpc_lb_v0_ClientStats_init_default {false, 0, false, 0, false, 0} |
||||
#define grpc_lb_v0_LoadBalanceResponse_init_default {false, grpc_lb_v0_InitialLoadBalanceResponse_init_default, false, grpc_lb_v0_ServerList_init_default} |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_init_default {false, "", false, "", false, grpc_lb_v0_Duration_init_default} |
||||
#define grpc_lb_v0_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_default} |
||||
#define grpc_lb_v0_Server_init_default {false, "", false, 0, false, {0, {0}}, false, 0} |
||||
#define grpc_lb_v0_Duration_init_zero {false, 0, false, 0} |
||||
#define grpc_lb_v0_LoadBalanceRequest_init_zero {false, grpc_lb_v0_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v0_ClientStats_init_zero} |
||||
#define grpc_lb_v0_InitialLoadBalanceRequest_init_zero {false, ""} |
||||
#define grpc_lb_v0_ClientStats_init_zero {false, 0, false, 0, false, 0} |
||||
#define grpc_lb_v0_LoadBalanceResponse_init_zero {false, grpc_lb_v0_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v0_ServerList_init_zero} |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_init_zero {false, "", false, "", false, grpc_lb_v0_Duration_init_zero} |
||||
#define grpc_lb_v0_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v0_Duration_init_zero} |
||||
#define grpc_lb_v0_Server_init_zero {false, "", false, 0, false, {0, {0}}, false, 0} |
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */ |
||||
#define grpc_lb_v0_ClientStats_total_requests_tag 1 |
||||
#define grpc_lb_v0_ClientStats_client_rpc_errors_tag 2 |
||||
#define grpc_lb_v0_ClientStats_dropped_requests_tag 3 |
||||
#define grpc_lb_v0_Duration_seconds_tag 1 |
||||
#define grpc_lb_v0_Duration_nanos_tag 2 |
||||
#define grpc_lb_v0_InitialLoadBalanceRequest_name_tag 1 |
||||
#define grpc_lb_v0_Server_ip_address_tag 1 |
||||
#define grpc_lb_v0_Server_port_tag 2 |
||||
#define grpc_lb_v0_Server_load_balance_token_tag 3 |
||||
#define grpc_lb_v0_Server_drop_request_tag 4 |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_client_config_tag 1 |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_load_balancer_delegate_tag 2 |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_client_stats_report_interval_tag 3 |
||||
#define grpc_lb_v0_LoadBalanceRequest_initial_request_tag 1 |
||||
#define grpc_lb_v0_LoadBalanceRequest_client_stats_tag 2 |
||||
#define grpc_lb_v0_ServerList_servers_tag 1 |
||||
#define grpc_lb_v0_ServerList_expiration_interval_tag 3 |
||||
#define grpc_lb_v0_LoadBalanceResponse_initial_response_tag 1 |
||||
#define grpc_lb_v0_LoadBalanceResponse_server_list_tag 2 |
||||
|
||||
/* Struct field encoding specification for nanopb */ |
||||
extern const pb_field_t grpc_lb_v0_Duration_fields[3]; |
||||
extern const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3]; |
||||
extern const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2]; |
||||
extern const pb_field_t grpc_lb_v0_ClientStats_fields[4]; |
||||
extern const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3]; |
||||
extern const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4]; |
||||
extern const pb_field_t grpc_lb_v0_ServerList_fields[3]; |
||||
extern const pb_field_t grpc_lb_v0_Server_fields[5]; |
||||
|
||||
/* Maximum encoded size of messages (where known) */ |
||||
#define grpc_lb_v0_Duration_size 22 |
||||
#define grpc_lb_v0_LoadBalanceRequest_size 169 |
||||
#define grpc_lb_v0_InitialLoadBalanceRequest_size 131 |
||||
#define grpc_lb_v0_ClientStats_size 33 |
||||
#define grpc_lb_v0_LoadBalanceResponse_size (165 + grpc_lb_v0_ServerList_size) |
||||
#define grpc_lb_v0_InitialLoadBalanceResponse_size 156 |
||||
#define grpc_lb_v0_Server_size 127 |
||||
|
||||
/* Message IDs (where set with "msgid" option) */ |
||||
#ifdef PB_MSGID |
||||
|
||||
#define LOAD_BALANCER_MESSAGES \ |
||||
|
||||
|
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,164 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/client_config/lb_policies/load_balancer_api.h" |
||||
#include "src/core/client_config/lb_policies/nanopb/pb_decode.h" |
||||
#include "src/core/client_config/lb_policies/nanopb/pb_encode.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
|
||||
typedef struct decode_serverlist_arg { |
||||
int first_pass; |
||||
int i; |
||||
size_t num_servers; |
||||
grpc_grpclb_server **servers; |
||||
} decode_serverlist_arg; |
||||
|
||||
/* invoked once for every Server in ServerList */ |
||||
static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field, |
||||
void **arg) { |
||||
decode_serverlist_arg *dec_arg = *arg; |
||||
if (dec_arg->first_pass != 0) { /* first pass */ |
||||
grpc_grpclb_server server; |
||||
if (!pb_decode(stream, grpc_lb_v0_Server_fields, &server)) { |
||||
return false; |
||||
} |
||||
dec_arg->num_servers++; |
||||
} else { /* second pass */ |
||||
grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server)); |
||||
GPR_ASSERT(dec_arg->num_servers > 0); |
||||
if (dec_arg->i == 0) { /* first iteration of second pass */ |
||||
dec_arg->servers = |
||||
gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers); |
||||
} |
||||
if (!pb_decode(stream, grpc_lb_v0_Server_fields, server)) { |
||||
return false; |
||||
} |
||||
dec_arg->servers[dec_arg->i++] = server; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) { |
||||
grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request)); |
||||
|
||||
req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */ |
||||
req->has_initial_request = 1; |
||||
req->initial_request.has_name = 1; |
||||
strncpy(req->initial_request.name, lb_service_name, |
||||
GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH); |
||||
return req; |
||||
} |
||||
|
||||
gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { |
||||
size_t encoded_length; |
||||
pb_ostream_t sizestream; |
||||
pb_ostream_t outputstream; |
||||
gpr_slice slice; |
||||
memset(&sizestream, 0, sizeof(pb_ostream_t)); |
||||
pb_encode(&sizestream, grpc_lb_v0_LoadBalanceRequest_fields, request); |
||||
encoded_length = sizestream.bytes_written; |
||||
|
||||
slice = gpr_slice_malloc(encoded_length); |
||||
outputstream = |
||||
pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length); |
||||
GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v0_LoadBalanceRequest_fields, |
||||
request) != 0); |
||||
return slice; |
||||
} |
||||
|
||||
void grpc_grpclb_request_destroy(grpc_grpclb_request *request) { |
||||
gpr_free(request); |
||||
} |
||||
|
||||
grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) { |
||||
bool status; |
||||
pb_istream_t stream = |
||||
pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), |
||||
GPR_SLICE_LENGTH(encoded_response)); |
||||
grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); |
||||
memset(res, 0, sizeof(*res)); |
||||
status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); |
||||
GPR_ASSERT(status == true); |
||||
return res; |
||||
} |
||||
|
||||
grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( |
||||
gpr_slice encoded_response) { |
||||
grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist)); |
||||
bool status; |
||||
decode_serverlist_arg arg; |
||||
pb_istream_t stream = |
||||
pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response), |
||||
GPR_SLICE_LENGTH(encoded_response)); |
||||
pb_istream_t stream_at_start = stream; |
||||
grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response)); |
||||
memset(res, 0, sizeof(*res)); |
||||
memset(&arg, 0, sizeof(decode_serverlist_arg)); |
||||
|
||||
res->server_list.servers.funcs.decode = decode_serverlist; |
||||
res->server_list.servers.arg = &arg; |
||||
arg.first_pass = 1; |
||||
status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res); |
||||
GPR_ASSERT(status == true); |
||||
GPR_ASSERT(arg.num_servers > 0); |
||||
|
||||
arg.first_pass = 0; |
||||
status = |
||||
pb_decode(&stream_at_start, grpc_lb_v0_LoadBalanceResponse_fields, res); |
||||
GPR_ASSERT(status == true); |
||||
GPR_ASSERT(arg.servers != NULL); |
||||
|
||||
sl->num_servers = arg.num_servers; |
||||
sl->servers = arg.servers; |
||||
if (res->server_list.has_expiration_interval) { |
||||
sl->expiration_interval = res->server_list.expiration_interval; |
||||
} |
||||
grpc_grpclb_response_destroy(res); |
||||
return sl; |
||||
} |
||||
|
||||
void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) { |
||||
size_t i; |
||||
for (i = 0; i < serverlist->num_servers; i++) { |
||||
gpr_free(serverlist->servers[i]); |
||||
} |
||||
gpr_free(serverlist->servers); |
||||
gpr_free(serverlist); |
||||
} |
||||
|
||||
void grpc_grpclb_response_destroy(grpc_grpclb_response *response) { |
||||
gpr_free(response); |
||||
} |
@ -0,0 +1,85 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H |
||||
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H |
||||
|
||||
#include <grpc/support/slice_buffer.h> |
||||
|
||||
#include "src/core/client_config/lb_policy_factory.h" |
||||
#include "src/core/client_config/lb_policies/load_balancer.pb.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128 |
||||
|
||||
typedef grpc_lb_v0_LoadBalanceRequest grpc_grpclb_request; |
||||
typedef grpc_lb_v0_LoadBalanceResponse grpc_grpclb_response; |
||||
typedef grpc_lb_v0_Server grpc_grpclb_server; |
||||
typedef grpc_lb_v0_Duration grpc_grpclb_duration; |
||||
typedef struct grpc_grpclb_serverlist { |
||||
grpc_grpclb_server **servers; |
||||
size_t num_servers; |
||||
grpc_grpclb_duration expiration_interval; |
||||
} grpc_grpclb_serverlist; |
||||
|
||||
/** Create a request for a gRPC LB service under \a lb_service_name */ |
||||
grpc_grpclb_request *grpc_grpclb_request_create(const char* lb_service_name); |
||||
|
||||
/** Protocol Buffers v3-encode \a request */ |
||||
gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request* request); |
||||
|
||||
/** Destroy \a request */ |
||||
void grpc_grpclb_request_destroy(grpc_grpclb_request *request); |
||||
|
||||
/** Parse (ie, decode) the bytes in \a encoded_response as a \a
|
||||
* grpc_grpclb_response */ |
||||
grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response); |
||||
|
||||
/** Destroy \a serverlist */ |
||||
void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist); |
||||
|
||||
/** Parse the list of servers from an encoded \a grpc_grpclb_response */ |
||||
grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist( |
||||
gpr_slice encoded_response); |
||||
|
||||
/** Destroy \a response */ |
||||
void grpc_grpclb_response_destroy(grpc_grpclb_response *response); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H */ |
@ -0,0 +1,547 @@ |
||||
/* Common parts of the nanopb library. Most of these are quite low-level
|
||||
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h. |
||||
*/ |
||||
|
||||
#ifndef PB_H_INCLUDED |
||||
#define PB_H_INCLUDED |
||||
|
||||
/*****************************************************************
|
||||
* Nanopb compilation time options. You can change these here by * |
||||
* uncommenting the lines, or on the compiler command line. * |
||||
*****************************************************************/ |
||||
|
||||
/* Enable support for dynamically allocated fields */ |
||||
/* #define PB_ENABLE_MALLOC 1 */ |
||||
|
||||
/* Define this if your CPU architecture is big endian, i.e. it
|
||||
* stores the most-significant byte first. */ |
||||
/* #define __BIG_ENDIAN__ 1 */ |
||||
|
||||
/* Define this if your CPU / compiler combination does not support
|
||||
* unaligned memory access to packed structures. */ |
||||
/* #define PB_NO_PACKED_STRUCTS 1 */ |
||||
|
||||
/* Increase the number of required fields that are tracked.
|
||||
* A compiler warning will tell if you need this. */ |
||||
/* #define PB_MAX_REQUIRED_FIELDS 256 */ |
||||
|
||||
/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ |
||||
/* #define PB_FIELD_16BIT 1 */ |
||||
|
||||
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ |
||||
/* #define PB_FIELD_32BIT 1 */ |
||||
|
||||
/* Disable support for error messages in order to save some code space. */ |
||||
/* #define PB_NO_ERRMSG 1 */ |
||||
|
||||
/* Disable support for custom streams (support only memory buffers). */ |
||||
/* #define PB_BUFFER_ONLY 1 */ |
||||
|
||||
/* Switch back to the old-style callback function signature.
|
||||
* This was the default until nanopb-0.2.1. */ |
||||
/* #define PB_OLD_CALLBACK_STYLE */ |
||||
|
||||
|
||||
/******************************************************************
|
||||
* You usually don't need to change anything below this line. * |
||||
* Feel free to look around and use the defined macros, though. * |
||||
******************************************************************/ |
||||
|
||||
|
||||
/* Version of the nanopb library. Just in case you want to check it in
|
||||
* your own program. */ |
||||
#define NANOPB_VERSION nanopb-0.3.5-dev |
||||
|
||||
/* Include all the system headers needed by nanopb. You will need the
|
||||
* definitions of the following: |
||||
* - strlen, memcpy, memset functions |
||||
* - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t |
||||
* - size_t |
||||
* - bool |
||||
* |
||||
* If you don't have the standard header files, you can instead provide |
||||
* a custom header that defines or includes all this. In that case, |
||||
* define PB_SYSTEM_HEADER to the path of this file. |
||||
*/ |
||||
#ifdef PB_SYSTEM_HEADER |
||||
#include PB_SYSTEM_HEADER |
||||
#else |
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#ifdef PB_ENABLE_MALLOC |
||||
#include <stdlib.h> |
||||
#endif |
||||
#endif |
||||
|
||||
/* Macro for defining packed structures (compiler dependent).
|
||||
* This just reduces memory requirements, but is not required. |
||||
*/ |
||||
#if defined(PB_NO_PACKED_STRUCTS) |
||||
/* Disable struct packing */ |
||||
# define PB_PACKED_STRUCT_START |
||||
# define PB_PACKED_STRUCT_END |
||||
# define pb_packed |
||||
#elif defined(__GNUC__) || defined(__clang__) |
||||
/* For GCC and clang */ |
||||
# define PB_PACKED_STRUCT_START |
||||
# define PB_PACKED_STRUCT_END |
||||
# define pb_packed __attribute__((packed)) |
||||
#elif defined(__ICCARM__) || defined(__CC_ARM) |
||||
/* For IAR ARM and Keil MDK-ARM compilers */ |
||||
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") |
||||
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") |
||||
# define pb_packed |
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1500) |
||||
/* For Microsoft Visual C++ */ |
||||
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) |
||||
# define PB_PACKED_STRUCT_END __pragma(pack(pop)) |
||||
# define pb_packed |
||||
#else |
||||
/* Unknown compiler */ |
||||
# define PB_PACKED_STRUCT_START |
||||
# define PB_PACKED_STRUCT_END |
||||
# define pb_packed |
||||
#endif |
||||
|
||||
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ |
||||
#ifndef PB_UNUSED |
||||
#define PB_UNUSED(x) (void)(x) |
||||
#endif |
||||
|
||||
/* Compile-time assertion, used for checking compatible compilation options.
|
||||
* If this does not work properly on your compiler, use |
||||
* #define PB_NO_STATIC_ASSERT to disable it. |
||||
* |
||||
* But before doing that, check carefully the error message / place where it |
||||
* comes from to see if the error has a real cause. Unfortunately the error |
||||
* message is not always very clear to read, but you can see the reason better |
||||
* in the place where the PB_STATIC_ASSERT macro was called. |
||||
*/ |
||||
#ifndef PB_NO_STATIC_ASSERT |
||||
#ifndef PB_STATIC_ASSERT |
||||
#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; |
||||
#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) |
||||
#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER |
||||
#endif |
||||
#else |
||||
#define PB_STATIC_ASSERT(COND,MSG) |
||||
#endif |
||||
|
||||
/* Number of required fields to keep track of. */ |
||||
#ifndef PB_MAX_REQUIRED_FIELDS |
||||
#define PB_MAX_REQUIRED_FIELDS 64 |
||||
#endif |
||||
|
||||
#if PB_MAX_REQUIRED_FIELDS < 64 |
||||
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). |
||||
#endif |
||||
|
||||
/* List of possible field types. These are used in the autogenerated code.
|
||||
* Least-significant 4 bits tell the scalar type |
||||
* Most-significant 4 bits specify repeated/required/packed etc. |
||||
*/ |
||||
|
||||
typedef uint8_t pb_type_t; |
||||
|
||||
/**** Field data types ****/ |
||||
|
||||
/* Numeric types */ |
||||
#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ |
||||
#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ |
||||
#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ |
||||
#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ |
||||
#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ |
||||
|
||||
/* Marker for last packable field type. */ |
||||
#define PB_LTYPE_LAST_PACKABLE 0x04 |
||||
|
||||
/* Byte array with pre-allocated buffer.
|
||||
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */ |
||||
#define PB_LTYPE_BYTES 0x05 |
||||
|
||||
/* String with pre-allocated buffer.
|
||||
* data_size is the maximum length. */ |
||||
#define PB_LTYPE_STRING 0x06 |
||||
|
||||
/* Submessage
|
||||
* submsg_fields is pointer to field descriptions */ |
||||
#define PB_LTYPE_SUBMESSAGE 0x07 |
||||
|
||||
/* Extension pseudo-field
|
||||
* The field contains a pointer to pb_extension_t */ |
||||
#define PB_LTYPE_EXTENSION 0x08 |
||||
|
||||
/* Number of declared LTYPES */ |
||||
#define PB_LTYPES_COUNT 9 |
||||
#define PB_LTYPE_MASK 0x0F |
||||
|
||||
/**** Field repetition rules ****/ |
||||
|
||||
#define PB_HTYPE_REQUIRED 0x00 |
||||
#define PB_HTYPE_OPTIONAL 0x10 |
||||
#define PB_HTYPE_REPEATED 0x20 |
||||
#define PB_HTYPE_ONEOF 0x30 |
||||
#define PB_HTYPE_MASK 0x30 |
||||
|
||||
/**** Field allocation types ****/ |
||||
|
||||
#define PB_ATYPE_STATIC 0x00 |
||||
#define PB_ATYPE_POINTER 0x80 |
||||
#define PB_ATYPE_CALLBACK 0x40 |
||||
#define PB_ATYPE_MASK 0xC0 |
||||
|
||||
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) |
||||
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) |
||||
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) |
||||
|
||||
/* Data type used for storing sizes of struct fields
|
||||
* and array counts. |
||||
*/ |
||||
#if defined(PB_FIELD_32BIT) |
||||
#define PB_SIZE_MAX ((uint32_t)-1) |
||||
typedef uint32_t pb_size_t; |
||||
typedef int32_t pb_ssize_t; |
||||
#elif defined(PB_FIELD_16BIT) |
||||
#define PB_SIZE_MAX ((uint16_t)-1) |
||||
typedef uint16_t pb_size_t; |
||||
typedef int16_t pb_ssize_t; |
||||
#else |
||||
#define PB_SIZE_MAX ((uint8_t)-1) |
||||
typedef uint8_t pb_size_t; |
||||
typedef int8_t pb_ssize_t; |
||||
#endif |
||||
|
||||
/* This structure is used in auto-generated constants
|
||||
* to specify struct fields. |
||||
* You can change field sizes if you need structures |
||||
* larger than 256 bytes or field tags larger than 256. |
||||
* The compiler should complain if your .proto has such |
||||
* structures. Fix that by defining PB_FIELD_16BIT or |
||||
* PB_FIELD_32BIT. |
||||
*/ |
||||
PB_PACKED_STRUCT_START |
||||
typedef struct pb_field_s pb_field_t; |
||||
struct pb_field_s { |
||||
pb_size_t tag; |
||||
pb_type_t type; |
||||
pb_size_t data_offset; /* Offset of field data, relative to previous field. */ |
||||
pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ |
||||
pb_size_t data_size; /* Data size in bytes for a single item */ |
||||
pb_size_t array_size; /* Maximum number of entries in array */ |
||||
|
||||
/* Field definitions for submessage
|
||||
* OR default value for all other non-array, non-callback types |
||||
* If null, then field will zeroed. */ |
||||
const void *ptr; |
||||
} pb_packed; |
||||
PB_PACKED_STRUCT_END |
||||
|
||||
/* Make sure that the standard integer types are of the expected sizes.
|
||||
* All kinds of things may break otherwise.. atleast all fixed* types. |
||||
* |
||||
* If you get errors here, it probably means that your stdint.h is not |
||||
* correct for your platform. |
||||
*/ |
||||
PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) |
||||
PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) |
||||
|
||||
/* This structure is used for 'bytes' arrays.
|
||||
* It has the number of bytes in the beginning, and after that an array. |
||||
* Note that actual structs used will have a different length of bytes array. |
||||
*/ |
||||
#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; } |
||||
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) |
||||
|
||||
struct pb_bytes_array_s { |
||||
pb_size_t size; |
||||
uint8_t bytes[1]; |
||||
}; |
||||
typedef struct pb_bytes_array_s pb_bytes_array_t; |
||||
|
||||
/* This structure is used for giving the callback function.
|
||||
* It is stored in the message structure and filled in by the method that |
||||
* calls pb_decode. |
||||
* |
||||
* The decoding callback will be given a limited-length stream |
||||
* If the wire type was string, the length is the length of the string. |
||||
* If the wire type was a varint/fixed32/fixed64, the length is the length |
||||
* of the actual value. |
||||
* The function may be called multiple times (especially for repeated types, |
||||
* but also otherwise if the message happens to contain the field multiple |
||||
* times.) |
||||
* |
||||
* The encoding callback will receive the actual output stream. |
||||
* It should write all the data in one call, including the field tag and |
||||
* wire type. It can write multiple fields. |
||||
* |
||||
* The callback can be null if you want to skip a field. |
||||
*/ |
||||
typedef struct pb_istream_s pb_istream_t; |
||||
typedef struct pb_ostream_s pb_ostream_t; |
||||
typedef struct pb_callback_s pb_callback_t; |
||||
struct pb_callback_s { |
||||
#ifdef PB_OLD_CALLBACK_STYLE |
||||
/* Deprecated since nanopb-0.2.1 */ |
||||
union { |
||||
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); |
||||
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); |
||||
} funcs; |
||||
#else |
||||
/* New function signature, which allows modifying arg contents in callback. */ |
||||
union { |
||||
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); |
||||
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); |
||||
} funcs; |
||||
#endif |
||||
|
||||
/* Free arg for use by callback */ |
||||
void *arg; |
||||
}; |
||||
|
||||
/* Wire types. Library user needs these only in encoder callbacks. */ |
||||
typedef enum { |
||||
PB_WT_VARINT = 0, |
||||
PB_WT_64BIT = 1, |
||||
PB_WT_STRING = 2, |
||||
PB_WT_32BIT = 5 |
||||
} pb_wire_type_t; |
||||
|
||||
/* Structure for defining the handling of unknown/extension fields.
|
||||
* Usually the pb_extension_type_t structure is automatically generated, |
||||
* while the pb_extension_t structure is created by the user. However, |
||||
* if you want to catch all unknown fields, you can also create a custom |
||||
* pb_extension_type_t with your own callback. |
||||
*/ |
||||
typedef struct pb_extension_type_s pb_extension_type_t; |
||||
typedef struct pb_extension_s pb_extension_t; |
||||
struct pb_extension_type_s { |
||||
/* Called for each unknown field in the message.
|
||||
* If you handle the field, read off all of its data and return true. |
||||
* If you do not handle the field, do not read anything and return true. |
||||
* If you run into an error, return false. |
||||
* Set to NULL for default handler. |
||||
*/ |
||||
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, |
||||
uint32_t tag, pb_wire_type_t wire_type); |
||||
|
||||
/* Called once after all regular fields have been encoded.
|
||||
* If you have something to write, do so and return true. |
||||
* If you do not have anything to write, just return true. |
||||
* If you run into an error, return false. |
||||
* Set to NULL for default handler. |
||||
*/ |
||||
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); |
||||
|
||||
/* Free field for use by the callback. */ |
||||
const void *arg; |
||||
}; |
||||
|
||||
struct pb_extension_s { |
||||
/* Type describing the extension field. Usually you'll initialize
|
||||
* this to a pointer to the automatically generated structure. */ |
||||
const pb_extension_type_t *type; |
||||
|
||||
/* Destination for the decoded data. This must match the datatype
|
||||
* of the extension field. */ |
||||
void *dest; |
||||
|
||||
/* Pointer to the next extension handler, or NULL.
|
||||
* If this extension does not match a field, the next handler is |
||||
* automatically called. */ |
||||
pb_extension_t *next; |
||||
|
||||
/* The decoder sets this to true if the extension was found.
|
||||
* Ignored for encoding. */ |
||||
bool found; |
||||
}; |
||||
|
||||
/* Memory allocation functions to use. You can define pb_realloc and
|
||||
* pb_free to custom functions if you want. */ |
||||
#ifdef PB_ENABLE_MALLOC |
||||
# ifndef pb_realloc |
||||
# define pb_realloc(ptr, size) realloc(ptr, size) |
||||
# endif |
||||
# ifndef pb_free |
||||
# define pb_free(ptr) free(ptr) |
||||
# endif |
||||
#endif |
||||
|
||||
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ |
||||
#define PB_PROTO_HEADER_VERSION 30 |
||||
|
||||
/* These macros are used to declare pb_field_t's in the constant array. */ |
||||
/* Size of a structure member, in bytes. */ |
||||
#define pb_membersize(st, m) (sizeof ((st*)0)->m) |
||||
/* Number of entries in an array. */ |
||||
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) |
||||
/* Delta from start of one member to the start of another member. */ |
||||
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) |
||||
/* Marks the end of the field list */ |
||||
#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} |
||||
|
||||
/* Macros for filling in the data_offset field */ |
||||
/* data_offset for first field in a message */ |
||||
#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) |
||||
/* data_offset for subsequent fields */ |
||||
#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) |
||||
/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ |
||||
#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ |
||||
? PB_DATAOFFSET_FIRST(st, m1, m2) \
|
||||
: PB_DATAOFFSET_OTHER(st, m1, m2)) |
||||
|
||||
/* Required fields are the simplest. They just have delta (padding) from
|
||||
* previous field end, and the size of the field. Pointer is used for |
||||
* submessages and default values. |
||||
*/ |
||||
#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
|
||||
fd, 0, pb_membersize(st, m), 0, ptr} |
||||
|
||||
/* Optional fields add the delta to the has_ variable. */ |
||||
#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
|
||||
fd, \
|
||||
pb_delta(st, has_ ## m, m), \
|
||||
pb_membersize(st, m), 0, ptr} |
||||
|
||||
/* Repeated fields have a _count field and also the maximum number of entries. */ |
||||
#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
|
||||
fd, \
|
||||
pb_delta(st, m ## _count, m), \
|
||||
pb_membersize(st, m[0]), \
|
||||
pb_arraysize(st, m), ptr} |
||||
|
||||
/* Allocated fields carry the size of the actual data, not the pointer */ |
||||
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
|
||||
fd, 0, pb_membersize(st, m[0]), 0, ptr} |
||||
|
||||
/* Optional fields don't need a has_ variable, as information would be redundant */ |
||||
#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
|
||||
fd, 0, pb_membersize(st, m[0]), 0, ptr} |
||||
|
||||
/* Repeated fields have a _count field and a pointer to array of pointers */ |
||||
#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
|
||||
fd, pb_delta(st, m ## _count, m), \
|
||||
pb_membersize(st, m[0]), 0, ptr} |
||||
|
||||
/* Callbacks are much like required fields except with special datatype. */ |
||||
#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
|
||||
fd, 0, pb_membersize(st, m), 0, ptr} |
||||
|
||||
#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
|
||||
fd, 0, pb_membersize(st, m), 0, ptr} |
||||
|
||||
#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
|
||||
fd, 0, pb_membersize(st, m), 0, ptr} |
||||
|
||||
/* Optional extensions don't have the has_ field, as that would be redundant. */ |
||||
#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
|
||||
0, \
|
||||
0, \
|
||||
pb_membersize(st, m), 0, ptr} |
||||
|
||||
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ |
||||
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) |
||||
|
||||
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ |
||||
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) |
||||
|
||||
/* The mapping from protobuf types to LTYPEs is done using these macros. */ |
||||
#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT |
||||
#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES |
||||
#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 |
||||
#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT |
||||
#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT |
||||
#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 |
||||
#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 |
||||
#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 |
||||
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT |
||||
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT |
||||
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE |
||||
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 |
||||
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 |
||||
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT |
||||
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT |
||||
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING |
||||
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT |
||||
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT |
||||
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION |
||||
|
||||
/* This is the actual macro used in field descriptions.
|
||||
* It takes these arguments: |
||||
* - Field tag number |
||||
* - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64, |
||||
* FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 |
||||
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION |
||||
* - Field rules: REQUIRED, OPTIONAL or REPEATED |
||||
* - Allocation: STATIC or CALLBACK |
||||
* - Placement: FIRST or OTHER, depending on if this is the first field in structure. |
||||
* - Message name |
||||
* - Field name |
||||
* - Previous field name (or field name again for first field) |
||||
* - Pointer to default value or submsg fields. |
||||
*/ |
||||
|
||||
#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ |
||||
PB_ ## rules ## _ ## allocation(tag, message, field, \
|
||||
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
|
||||
PB_LTYPE_MAP_ ## type, ptr) |
||||
|
||||
/* Field description for oneof fields. This requires taking into account the
|
||||
* union name also, that's why a separate set of macros is needed. |
||||
*/ |
||||
#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
|
||||
fd, pb_delta(st, which_ ## u, u.m), \
|
||||
pb_membersize(st, u.m), 0, ptr} |
||||
|
||||
#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ |
||||
{tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
|
||||
fd, pb_delta(st, which_ ## u, u.m), \
|
||||
pb_membersize(st, u.m[0]), 0, ptr} |
||||
|
||||
#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ |
||||
PB_ ## rules ## _ ## allocation(union_name, tag, message, field, \
|
||||
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
|
||||
PB_LTYPE_MAP_ ## type, ptr) |
||||
|
||||
/* These macros are used for giving out error messages.
|
||||
* They are mostly a debugging aid; the main error information |
||||
* is the true/false return value from functions. |
||||
* Some code space can be saved by disabling the error |
||||
* messages if not used. |
||||
* |
||||
* PB_SET_ERROR() sets the error message if none has been set yet. |
||||
* msg must be a constant string literal. |
||||
* PB_GET_ERROR() always returns a pointer to a string. |
||||
* PB_RETURN_ERROR() sets the error and returns false from current |
||||
* function. |
||||
*/ |
||||
#ifdef PB_NO_ERRMSG |
||||
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) |
||||
#define PB_GET_ERROR(stream) "(errmsg disabled)" |
||||
#else |
||||
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) |
||||
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") |
||||
#endif |
||||
|
||||
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false |
||||
|
||||
#endif |
@ -0,0 +1,97 @@ |
||||
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
|
||||
* |
||||
* 2014 Petteri Aimonen <jpa@kapsi.fi> |
||||
*/ |
||||
|
||||
#include "pb_common.h" |
||||
|
||||
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) |
||||
{ |
||||
iter->start = fields; |
||||
iter->pos = fields; |
||||
iter->required_field_index = 0; |
||||
iter->dest_struct = dest_struct; |
||||
iter->pData = (char*)dest_struct + iter->pos->data_offset; |
||||
iter->pSize = (char*)iter->pData + iter->pos->size_offset; |
||||
|
||||
return (iter->pos->tag != 0); |
||||
} |
||||
|
||||
bool pb_field_iter_next(pb_field_iter_t *iter) |
||||
{ |
||||
const pb_field_t *prev_field = iter->pos; |
||||
|
||||
if (prev_field->tag == 0) |
||||
{ |
||||
/* Handle empty message types, where the first field is already the terminator.
|
||||
* In other cases, the iter->pos never points to the terminator. */ |
||||
return false; |
||||
} |
||||
|
||||
iter->pos++; |
||||
|
||||
if (iter->pos->tag == 0) |
||||
{ |
||||
/* Wrapped back to beginning, reinitialize */ |
||||
(void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); |
||||
return false; |
||||
} |
||||
else |
||||
{ |
||||
/* Increment the pointers based on previous field size */ |
||||
size_t prev_size = prev_field->data_size; |
||||
|
||||
if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && |
||||
PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) |
||||
{ |
||||
/* Don't advance pointers inside unions */ |
||||
prev_size = 0; |
||||
iter->pData = (char*)iter->pData - prev_field->data_offset; |
||||
} |
||||
else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && |
||||
PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) |
||||
{ |
||||
/* In static arrays, the data_size tells the size of a single entry and
|
||||
* array_size is the number of entries */ |
||||
prev_size *= prev_field->array_size; |
||||
} |
||||
else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) |
||||
{ |
||||
/* Pointer fields always have a constant size in the main structure.
|
||||
* The data_size only applies to the dynamically allocated area. */ |
||||
prev_size = sizeof(void*); |
||||
} |
||||
|
||||
if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) |
||||
{ |
||||
/* Count the required fields, in order to check their presence in the
|
||||
* decoder. */ |
||||
iter->required_field_index++; |
||||
} |
||||
|
||||
iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; |
||||
iter->pSize = (char*)iter->pData + iter->pos->size_offset; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) |
||||
{ |
||||
const pb_field_t *start = iter->pos; |
||||
|
||||
do { |
||||
if (iter->pos->tag == tag && |
||||
PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) |
||||
{ |
||||
/* Found the wanted field */ |
||||
return true; |
||||
} |
||||
|
||||
(void)pb_field_iter_next(iter); |
||||
} while (iter->pos != start); |
||||
|
||||
/* Searched all the way back to start, and found nothing. */ |
||||
return false; |
||||
} |
||||
|
||||
|
@ -0,0 +1,42 @@ |
||||
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
|
||||
* These functions are rarely needed by applications directly. |
||||
*/ |
||||
|
||||
#ifndef PB_COMMON_H_INCLUDED |
||||
#define PB_COMMON_H_INCLUDED |
||||
|
||||
#include "pb.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Iterator for pb_field_t list */ |
||||
struct pb_field_iter_s { |
||||
const pb_field_t *start; /* Start of the pb_field_t array */ |
||||
const pb_field_t *pos; /* Current position of the iterator */ |
||||
unsigned required_field_index; /* Zero-based index that counts only the required fields */ |
||||
void *dest_struct; /* Pointer to start of the structure */ |
||||
void *pData; /* Pointer to current field value */ |
||||
void *pSize; /* Pointer to count/has field */ |
||||
}; |
||||
typedef struct pb_field_iter_s pb_field_iter_t; |
||||
|
||||
/* Initialize the field iterator structure to beginning.
|
||||
* Returns false if the message type is empty. */ |
||||
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); |
||||
|
||||
/* Advance the iterator to the next field.
|
||||
* Returns false when the iterator wraps back to the first field. */ |
||||
bool pb_field_iter_next(pb_field_iter_t *iter); |
||||
|
||||
/* Advance the iterator until it points at a field with the given tag.
|
||||
* Returns false if no such field exists. */ |
||||
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@ |
||||
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
|
||||
* The main function is pb_decode. You also need an input stream, and the |
||||
* field descriptions created by nanopb_generator.py. |
||||
*/ |
||||
|
||||
#ifndef PB_DECODE_H_INCLUDED |
||||
#define PB_DECODE_H_INCLUDED |
||||
|
||||
#include "pb.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Structure for defining custom input streams. You will need to provide
|
||||
* a callback function to read the bytes from your storage, which can be |
||||
* for example a file or a network socket. |
||||
*
|
||||
* The callback must conform to these rules: |
||||
* |
||||
* 1) Return false on IO errors. This will cause decoding to abort. |
||||
* 2) You can use state to store your own data (e.g. buffer pointer), |
||||
* and rely on pb_read to verify that no-body reads past bytes_left. |
||||
* 3) Your callback may be used with substreams, in which case bytes_left |
||||
* is different than from the main stream. Don't use bytes_left to compute |
||||
* any pointers. |
||||
*/ |
||||
struct pb_istream_s |
||||
{ |
||||
#ifdef PB_BUFFER_ONLY |
||||
/* Callback pointer is not used in buffer-only configuration.
|
||||
* Having an int pointer here allows binary compatibility but |
||||
* gives an error if someone tries to assign callback function. |
||||
*/ |
||||
int *callback; |
||||
#else |
||||
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count); |
||||
#endif |
||||
|
||||
void *state; /* Free field for use by callback implementation */ |
||||
size_t bytes_left; |
||||
|
||||
#ifndef PB_NO_ERRMSG |
||||
const char *errmsg; |
||||
#endif |
||||
}; |
||||
|
||||
/***************************
|
||||
* Main decoding functions * |
||||
***************************/ |
||||
|
||||
/* Decode a single protocol buffers message from input stream into a C structure.
|
||||
* Returns true on success, false on any failure. |
||||
* The actual struct pointed to by dest must match the description in fields. |
||||
* Callback fields of the destination structure must be initialized by caller. |
||||
* All other fields will be initialized by this function. |
||||
* |
||||
* Example usage: |
||||
* MyMessage msg = {}; |
||||
* uint8_t buffer[64]; |
||||
* pb_istream_t stream; |
||||
*
|
||||
* // ... read some data into buffer ...
|
||||
* |
||||
* stream = pb_istream_from_buffer(buffer, count); |
||||
* pb_decode(&stream, MyMessage_fields, &msg); |
||||
*/ |
||||
bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); |
||||
|
||||
/* Same as pb_decode, except does not initialize the destination structure
|
||||
* to default values. This is slightly faster if you need no default values |
||||
* and just do memset(struct, 0, sizeof(struct)) yourself. |
||||
* |
||||
* This can also be used for 'merging' two messages, i.e. update only the |
||||
* fields that exist in the new message. |
||||
* |
||||
* Note: If this function returns with an error, it will not release any |
||||
* dynamically allocated fields. You will need to call pb_release() yourself. |
||||
*/ |
||||
bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); |
||||
|
||||
/* Same as pb_decode, except expects the stream to start with the message size
|
||||
* encoded as varint. Corresponds to parseDelimitedFrom() in Google's |
||||
* protobuf API. |
||||
*/ |
||||
bool pb_decode_delimited(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 |
||||
* pb_decode() returns with an error, the message is already released. |
||||
*/ |
||||
void pb_release(const pb_field_t fields[], void *dest_struct); |
||||
#endif |
||||
|
||||
|
||||
/**************************************
|
||||
* Functions for manipulating streams * |
||||
**************************************/ |
||||
|
||||
/* Create an input stream for reading from a memory buffer.
|
||||
* |
||||
* Alternatively, you can use a custom stream that reads directly from e.g. |
||||
* a file or a network socket. |
||||
*/ |
||||
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize); |
||||
|
||||
/* Function to read from a pb_istream_t. You can use this if you need to
|
||||
* read some custom header data, or to read data in field callbacks. |
||||
*/ |
||||
bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count); |
||||
|
||||
|
||||
/************************************************
|
||||
* Helper functions for writing field callbacks * |
||||
************************************************/ |
||||
|
||||
/* Decode the tag for the next field in the stream. Gives the wire type and
|
||||
* field tag. At end of the message, returns false and sets eof to true. */ |
||||
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); |
||||
|
||||
/* Skip the field payload data, given the wire type. */ |
||||
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); |
||||
|
||||
/* Decode an integer in the varint format. This works for bool, enum, int32,
|
||||
* int64, uint32 and uint64 field types. */ |
||||
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); |
||||
|
||||
/* Decode an integer in the zig-zagged svarint format. This works for sint32
|
||||
* and sint64. */ |
||||
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); |
||||
|
||||
/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
|
||||
* a 4-byte wide C variable. */ |
||||
bool pb_decode_fixed32(pb_istream_t *stream, void *dest); |
||||
|
||||
/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
|
||||
* a 8-byte wide C variable. */ |
||||
bool pb_decode_fixed64(pb_istream_t *stream, void *dest); |
||||
|
||||
/* Make a limited-length substream for reading a PB_WT_STRING field. */ |
||||
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); |
||||
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,690 @@ |
||||
/* pb_encode.c -- encode a protobuf using minimal resources
|
||||
* |
||||
* 2011 Petteri Aimonen <jpa@kapsi.fi> |
||||
*/ |
||||
|
||||
#include "pb.h" |
||||
#include "pb_encode.h" |
||||
#include "pb_common.h" |
||||
|
||||
/* Use the GCC warn_unused_result attribute to check that all return values
|
||||
* are propagated correctly. On other compilers and gcc before 3.4.0 just |
||||
* ignore the annotation. |
||||
*/ |
||||
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) |
||||
#define checkreturn |
||||
#else |
||||
#define checkreturn __attribute__((warn_unused_result)) |
||||
#endif |
||||
|
||||
/**************************************
|
||||
* Declarations internal to this file * |
||||
**************************************/ |
||||
typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; |
||||
|
||||
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); |
||||
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); |
||||
static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); |
||||
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); |
||||
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); |
||||
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); |
||||
|
||||
/* --- Function pointers to field encoders ---
|
||||
* Order in the array must match pb_action_t LTYPE numbering. |
||||
*/ |
||||
static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { |
||||
&pb_enc_varint, |
||||
&pb_enc_uvarint, |
||||
&pb_enc_svarint, |
||||
&pb_enc_fixed32, |
||||
&pb_enc_fixed64, |
||||
|
||||
&pb_enc_bytes, |
||||
&pb_enc_string, |
||||
&pb_enc_submessage, |
||||
NULL /* extensions */ |
||||
}; |
||||
|
||||
/*******************************
|
||||
* pb_ostream_t implementation * |
||||
*******************************/ |
||||
|
||||
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) |
||||
{ |
||||
uint8_t *dest = (uint8_t*)stream->state; |
||||
stream->state = dest + count; |
||||
|
||||
while (count--) |
||||
*dest++ = *buf++; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize) |
||||
{ |
||||
pb_ostream_t stream; |
||||
#ifdef PB_BUFFER_ONLY |
||||
stream.callback = (void*)1; /* Just a marker value */ |
||||
#else |
||||
stream.callback = &buf_write; |
||||
#endif |
||||
stream.state = buf; |
||||
stream.max_size = bufsize; |
||||
stream.bytes_written = 0; |
||||
#ifndef PB_NO_ERRMSG |
||||
stream.errmsg = NULL; |
||||
#endif |
||||
return stream; |
||||
} |
||||
|
||||
bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) |
||||
{ |
||||
if (stream->callback != NULL) |
||||
{ |
||||
if (stream->bytes_written + count > stream->max_size) |
||||
PB_RETURN_ERROR(stream, "stream full"); |
||||
|
||||
#ifdef PB_BUFFER_ONLY |
||||
if (!buf_write(stream, buf, count)) |
||||
PB_RETURN_ERROR(stream, "io error"); |
||||
#else |
||||
if (!stream->callback(stream, buf, count)) |
||||
PB_RETURN_ERROR(stream, "io error"); |
||||
#endif |
||||
} |
||||
|
||||
stream->bytes_written += count; |
||||
return true; |
||||
} |
||||
|
||||
/*************************
|
||||
* Encode a single field * |
||||
*************************/ |
||||
|
||||
/* Encode a static array. Handles the size calculations and possible packing. */ |
||||
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, |
||||
const void *pData, size_t count, pb_encoder_t func) |
||||
{ |
||||
size_t i; |
||||
const void *p; |
||||
size_t size; |
||||
|
||||
if (count == 0) |
||||
return true; |
||||
|
||||
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) |
||||
PB_RETURN_ERROR(stream, "array max size exceeded"); |
||||
|
||||
/* We always pack arrays if the datatype allows it. */ |
||||
if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) |
||||
{ |
||||
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) |
||||
return false; |
||||
|
||||
/* Determine the total size of packed array. */ |
||||
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) |
||||
{ |
||||
size = 4 * count; |
||||
} |
||||
else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) |
||||
{ |
||||
size = 8 * count; |
||||
} |
||||
else |
||||
{
|
||||
pb_ostream_t sizestream = PB_OSTREAM_SIZING; |
||||
p = pData; |
||||
for (i = 0; i < count; i++) |
||||
{ |
||||
if (!func(&sizestream, field, p)) |
||||
return false; |
||||
p = (const char*)p + field->data_size; |
||||
} |
||||
size = sizestream.bytes_written; |
||||
} |
||||
|
||||
if (!pb_encode_varint(stream, (uint64_t)size)) |
||||
return false; |
||||
|
||||
if (stream->callback == NULL) |
||||
return pb_write(stream, NULL, size); /* Just sizing.. */ |
||||
|
||||
/* Write the data */ |
||||
p = pData; |
||||
for (i = 0; i < count; i++) |
||||
{ |
||||
if (!func(stream, field, p)) |
||||
return false; |
||||
p = (const char*)p + field->data_size; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
p = pData; |
||||
for (i = 0; i < count; i++) |
||||
{ |
||||
if (!pb_encode_tag_for_field(stream, field)) |
||||
return false; |
||||
|
||||
/* Normally the data is stored directly in the array entries, but
|
||||
* for pointer-type string and bytes fields, the array entries are |
||||
* actually pointers themselves also. So we have to dereference once |
||||
* more to get to the actual data. */ |
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && |
||||
(PB_LTYPE(field->type) == PB_LTYPE_STRING || |
||||
PB_LTYPE(field->type) == PB_LTYPE_BYTES)) |
||||
{ |
||||
if (!func(stream, field, *(const void* const*)p)) |
||||
return false;
|
||||
} |
||||
else |
||||
{ |
||||
if (!func(stream, field, p)) |
||||
return false; |
||||
} |
||||
p = (const char*)p + field->data_size; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/* Encode a field with static or pointer allocation, i.e. one whose data
|
||||
* is available to the encoder directly. */ |
||||
static bool checkreturn encode_basic_field(pb_ostream_t *stream, |
||||
const pb_field_t *field, const void *pData) |
||||
{ |
||||
pb_encoder_t func; |
||||
const void *pSize; |
||||
bool implicit_has = true; |
||||
|
||||
func = PB_ENCODERS[PB_LTYPE(field->type)]; |
||||
|
||||
if (field->size_offset) |
||||
pSize = (const char*)pData + field->size_offset; |
||||
else |
||||
pSize = &implicit_has; |
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
||||
{ |
||||
/* pData is a pointer to the field, which contains pointer to
|
||||
* the data. If the 2nd pointer is NULL, it is interpreted as if |
||||
* the has_field was false. |
||||
*/ |
||||
|
||||
pData = *(const void* const*)pData; |
||||
implicit_has = (pData != NULL); |
||||
} |
||||
|
||||
switch (PB_HTYPE(field->type)) |
||||
{ |
||||
case PB_HTYPE_REQUIRED: |
||||
if (!pData) |
||||
PB_RETURN_ERROR(stream, "missing required field"); |
||||
if (!pb_encode_tag_for_field(stream, field)) |
||||
return false; |
||||
if (!func(stream, field, pData)) |
||||
return false; |
||||
break; |
||||
|
||||
case PB_HTYPE_OPTIONAL: |
||||
if (*(const bool*)pSize) |
||||
{ |
||||
if (!pb_encode_tag_for_field(stream, field)) |
||||
return false; |
||||
|
||||
if (!func(stream, field, pData)) |
||||
return false; |
||||
} |
||||
break; |
||||
|
||||
case PB_HTYPE_REPEATED: |
||||
if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func)) |
||||
return false; |
||||
break; |
||||
|
||||
case PB_HTYPE_ONEOF: |
||||
if (*(const pb_size_t*)pSize == field->tag) |
||||
{ |
||||
if (!pb_encode_tag_for_field(stream, field)) |
||||
return false; |
||||
|
||||
if (!func(stream, field, pData)) |
||||
return false; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
PB_RETURN_ERROR(stream, "invalid field type"); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/* Encode a field with callback semantics. This means that a user function is
|
||||
* called to provide and encode the actual data. */ |
||||
static bool checkreturn encode_callback_field(pb_ostream_t *stream, |
||||
const pb_field_t *field, const void *pData) |
||||
{ |
||||
const pb_callback_t *callback = (const pb_callback_t*)pData; |
||||
|
||||
#ifdef PB_OLD_CALLBACK_STYLE |
||||
const void *arg = callback->arg; |
||||
#else |
||||
void * const *arg = &(callback->arg); |
||||
#endif |
||||
|
||||
if (callback->funcs.encode != NULL) |
||||
{ |
||||
if (!callback->funcs.encode(stream, field, arg)) |
||||
PB_RETURN_ERROR(stream, "callback error"); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/* Encode a single field of any callback or static type. */ |
||||
static bool checkreturn encode_field(pb_ostream_t *stream, |
||||
const pb_field_t *field, const void *pData) |
||||
{ |
||||
switch (PB_ATYPE(field->type)) |
||||
{ |
||||
case PB_ATYPE_STATIC: |
||||
case PB_ATYPE_POINTER: |
||||
return encode_basic_field(stream, field, pData); |
||||
|
||||
case PB_ATYPE_CALLBACK: |
||||
return encode_callback_field(stream, field, pData); |
||||
|
||||
default: |
||||
PB_RETURN_ERROR(stream, "invalid field type"); |
||||
} |
||||
} |
||||
|
||||
/* Default handler for extension fields. Expects to have a pb_field_t
|
||||
* pointer in the extension->type->arg field. */ |
||||
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, |
||||
const pb_extension_t *extension) |
||||
{ |
||||
const pb_field_t *field = (const pb_field_t*)extension->type->arg; |
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
||||
{ |
||||
/* For pointer extensions, the pointer is stored directly
|
||||
* in the extension structure. This avoids having an extra |
||||
* indirection. */ |
||||
return encode_field(stream, field, &extension->dest); |
||||
} |
||||
else |
||||
{ |
||||
return encode_field(stream, field, extension->dest); |
||||
} |
||||
} |
||||
|
||||
/* Walk through all the registered extensions and give them a chance
|
||||
* to encode themselves. */ |
||||
static bool checkreturn encode_extension_field(pb_ostream_t *stream, |
||||
const pb_field_t *field, const void *pData) |
||||
{ |
||||
const pb_extension_t *extension = *(const pb_extension_t* const *)pData; |
||||
PB_UNUSED(field); |
||||
|
||||
while (extension) |
||||
{ |
||||
bool status; |
||||
if (extension->type->encode) |
||||
status = extension->type->encode(stream, extension); |
||||
else |
||||
status = default_extension_encoder(stream, extension); |
||||
|
||||
if (!status) |
||||
return false; |
||||
|
||||
extension = extension->next; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/*********************
|
||||
* Encode all fields * |
||||
*********************/ |
||||
|
||||
static void *remove_const(const void *p) |
||||
{ |
||||
/* Note: this casts away const, in order to use the common field iterator
|
||||
* logic for both encoding and decoding. */ |
||||
union { |
||||
void *p1; |
||||
const void *p2; |
||||
} t; |
||||
t.p2 = p; |
||||
return t.p1; |
||||
} |
||||
|
||||
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) |
||||
{ |
||||
pb_field_iter_t iter; |
||||
if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct))) |
||||
return true; /* Empty message type */ |
||||
|
||||
do { |
||||
if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) |
||||
{ |
||||
/* Special case for the extension field placeholder */ |
||||
if (!encode_extension_field(stream, iter.pos, iter.pData)) |
||||
return false; |
||||
} |
||||
else |
||||
{ |
||||
/* Regular field */ |
||||
if (!encode_field(stream, iter.pos, iter.pData)) |
||||
return false; |
||||
} |
||||
} while (pb_field_iter_next(&iter)); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) |
||||
{ |
||||
return pb_encode_submessage(stream, fields, src_struct); |
||||
} |
||||
|
||||
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) |
||||
{ |
||||
pb_ostream_t stream = PB_OSTREAM_SIZING; |
||||
|
||||
if (!pb_encode(&stream, fields, src_struct)) |
||||
return false; |
||||
|
||||
*size = stream.bytes_written; |
||||
return true; |
||||
} |
||||
|
||||
/********************
|
||||
* Helper functions * |
||||
********************/ |
||||
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) |
||||
{ |
||||
uint8_t buffer[10]; |
||||
size_t i = 0; |
||||
|
||||
if (value == 0) |
||||
return pb_write(stream, (uint8_t*)&value, 1); |
||||
|
||||
while (value) |
||||
{ |
||||
buffer[i] = (uint8_t)((value & 0x7F) | 0x80); |
||||
value >>= 7; |
||||
i++; |
||||
} |
||||
buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ |
||||
|
||||
return pb_write(stream, buffer, i); |
||||
} |
||||
|
||||
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) |
||||
{ |
||||
uint64_t zigzagged; |
||||
if (value < 0) |
||||
zigzagged = ~((uint64_t)value << 1); |
||||
else |
||||
zigzagged = (uint64_t)value << 1; |
||||
|
||||
return pb_encode_varint(stream, zigzagged); |
||||
} |
||||
|
||||
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) |
||||
{ |
||||
#ifdef __BIG_ENDIAN__ |
||||
const uint8_t *bytes = value; |
||||
uint8_t lebytes[4]; |
||||
lebytes[0] = bytes[3]; |
||||
lebytes[1] = bytes[2]; |
||||
lebytes[2] = bytes[1]; |
||||
lebytes[3] = bytes[0]; |
||||
return pb_write(stream, lebytes, 4); |
||||
#else |
||||
return pb_write(stream, (const uint8_t*)value, 4); |
||||
#endif |
||||
} |
||||
|
||||
bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) |
||||
{ |
||||
#ifdef __BIG_ENDIAN__ |
||||
const uint8_t *bytes = value; |
||||
uint8_t lebytes[8]; |
||||
lebytes[0] = bytes[7]; |
||||
lebytes[1] = bytes[6]; |
||||
lebytes[2] = bytes[5]; |
||||
lebytes[3] = bytes[4]; |
||||
lebytes[4] = bytes[3]; |
||||
lebytes[5] = bytes[2]; |
||||
lebytes[6] = bytes[1]; |
||||
lebytes[7] = bytes[0]; |
||||
return pb_write(stream, lebytes, 8); |
||||
#else |
||||
return pb_write(stream, (const uint8_t*)value, 8); |
||||
#endif |
||||
} |
||||
|
||||
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) |
||||
{ |
||||
uint64_t tag = ((uint64_t)field_number << 3) | wiretype; |
||||
return pb_encode_varint(stream, tag); |
||||
} |
||||
|
||||
bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) |
||||
{ |
||||
pb_wire_type_t wiretype; |
||||
switch (PB_LTYPE(field->type)) |
||||
{ |
||||
case PB_LTYPE_VARINT: |
||||
case PB_LTYPE_UVARINT: |
||||
case PB_LTYPE_SVARINT: |
||||
wiretype = PB_WT_VARINT; |
||||
break; |
||||
|
||||
case PB_LTYPE_FIXED32: |
||||
wiretype = PB_WT_32BIT; |
||||
break; |
||||
|
||||
case PB_LTYPE_FIXED64: |
||||
wiretype = PB_WT_64BIT; |
||||
break; |
||||
|
||||
case PB_LTYPE_BYTES: |
||||
case PB_LTYPE_STRING: |
||||
case PB_LTYPE_SUBMESSAGE: |
||||
wiretype = PB_WT_STRING; |
||||
break; |
||||
|
||||
default: |
||||
PB_RETURN_ERROR(stream, "invalid field type"); |
||||
} |
||||
|
||||
return pb_encode_tag(stream, wiretype, field->tag); |
||||
} |
||||
|
||||
bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) |
||||
{ |
||||
if (!pb_encode_varint(stream, (uint64_t)size)) |
||||
return false; |
||||
|
||||
return pb_write(stream, buffer, size); |
||||
} |
||||
|
||||
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) |
||||
{ |
||||
/* First calculate the message size using a non-writing substream. */ |
||||
pb_ostream_t substream = PB_OSTREAM_SIZING; |
||||
size_t size; |
||||
bool status; |
||||
|
||||
if (!pb_encode(&substream, fields, src_struct)) |
||||
{ |
||||
#ifndef PB_NO_ERRMSG |
||||
stream->errmsg = substream.errmsg; |
||||
#endif |
||||
return false; |
||||
} |
||||
|
||||
size = substream.bytes_written; |
||||
|
||||
if (!pb_encode_varint(stream, (uint64_t)size)) |
||||
return false; |
||||
|
||||
if (stream->callback == NULL) |
||||
return pb_write(stream, NULL, size); /* Just sizing */ |
||||
|
||||
if (stream->bytes_written + size > stream->max_size) |
||||
PB_RETURN_ERROR(stream, "stream full"); |
||||
|
||||
/* Use a substream to verify that a callback doesn't write more than
|
||||
* what it did the first time. */ |
||||
substream.callback = stream->callback; |
||||
substream.state = stream->state; |
||||
substream.max_size = size; |
||||
substream.bytes_written = 0; |
||||
#ifndef PB_NO_ERRMSG |
||||
substream.errmsg = NULL; |
||||
#endif |
||||
|
||||
status = pb_encode(&substream, fields, src_struct); |
||||
|
||||
stream->bytes_written += substream.bytes_written; |
||||
stream->state = substream.state; |
||||
#ifndef PB_NO_ERRMSG |
||||
stream->errmsg = substream.errmsg; |
||||
#endif |
||||
|
||||
if (substream.bytes_written != size) |
||||
PB_RETURN_ERROR(stream, "submsg size changed"); |
||||
|
||||
return status; |
||||
} |
||||
|
||||
/* Field encoders */ |
||||
|
||||
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
int64_t value = 0; |
||||
|
||||
/* Cases 1 and 2 are for compilers that have smaller types for bool
|
||||
* or enums, and for int_size option. */ |
||||
switch (field->data_size) |
||||
{ |
||||
case 1: value = *(const int8_t*)src; break; |
||||
case 2: value = *(const int16_t*)src; break; |
||||
case 4: value = *(const int32_t*)src; break; |
||||
case 8: value = *(const int64_t*)src; break; |
||||
default: PB_RETURN_ERROR(stream, "invalid data_size"); |
||||
} |
||||
|
||||
return pb_encode_varint(stream, (uint64_t)value); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
uint64_t value = 0; |
||||
|
||||
switch (field->data_size) |
||||
{ |
||||
case 1: value = *(const uint8_t*)src; break; |
||||
case 2: value = *(const uint16_t*)src; break; |
||||
case 4: value = *(const uint32_t*)src; break; |
||||
case 8: value = *(const uint64_t*)src; break; |
||||
default: PB_RETURN_ERROR(stream, "invalid data_size"); |
||||
} |
||||
|
||||
return pb_encode_varint(stream, value); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
int64_t value = 0; |
||||
|
||||
switch (field->data_size) |
||||
{ |
||||
case 1: value = *(const int8_t*)src; break; |
||||
case 2: value = *(const int16_t*)src; break; |
||||
case 4: value = *(const int32_t*)src; break; |
||||
case 8: value = *(const int64_t*)src; break; |
||||
default: PB_RETURN_ERROR(stream, "invalid data_size"); |
||||
} |
||||
|
||||
return pb_encode_svarint(stream, value); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
PB_UNUSED(field); |
||||
return pb_encode_fixed64(stream, src); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
PB_UNUSED(field); |
||||
return pb_encode_fixed32(stream, src); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; |
||||
|
||||
if (src == NULL) |
||||
{ |
||||
/* Threat null pointer as an empty bytes field */ |
||||
return pb_encode_string(stream, NULL, 0); |
||||
} |
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && |
||||
PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) |
||||
{ |
||||
PB_RETURN_ERROR(stream, "bytes size exceeded"); |
||||
} |
||||
|
||||
return pb_encode_string(stream, bytes->bytes, bytes->size); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
size_t size = 0; |
||||
size_t max_size = field->data_size; |
||||
const char *p = (const char*)src; |
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) |
||||
max_size = (size_t)-1; |
||||
|
||||
if (src == NULL) |
||||
{ |
||||
size = 0; /* Threat null pointer as an empty string */ |
||||
} |
||||
else |
||||
{ |
||||
/* strnlen() is not always available, so just use a loop */ |
||||
while (size < max_size && *p != '\0') |
||||
{ |
||||
size++; |
||||
p++; |
||||
} |
||||
} |
||||
|
||||
return pb_encode_string(stream, (const uint8_t*)src, size); |
||||
} |
||||
|
||||
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) |
||||
{ |
||||
if (field->ptr == NULL) |
||||
PB_RETURN_ERROR(stream, "invalid field descriptor"); |
||||
|
||||
return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); |
||||
} |
||||
|
@ -0,0 +1,154 @@ |
||||
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
|
||||
* The main function is pb_encode. You also need an output stream, and the |
||||
* field descriptions created by nanopb_generator.py. |
||||
*/ |
||||
|
||||
#ifndef PB_ENCODE_H_INCLUDED |
||||
#define PB_ENCODE_H_INCLUDED |
||||
|
||||
#include "pb.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Structure for defining custom output streams. You will need to provide
|
||||
* a callback function to write the bytes to your storage, which can be |
||||
* for example a file or a network socket. |
||||
* |
||||
* The callback must conform to these rules: |
||||
* |
||||
* 1) Return false on IO errors. This will cause encoding to abort. |
||||
* 2) You can use state to store your own data (e.g. buffer pointer). |
||||
* 3) pb_write will update bytes_written after your callback runs. |
||||
* 4) Substreams will modify max_size and bytes_written. Don't use them |
||||
* to calculate any pointers. |
||||
*/ |
||||
struct pb_ostream_s |
||||
{ |
||||
#ifdef PB_BUFFER_ONLY |
||||
/* Callback pointer is not used in buffer-only configuration.
|
||||
* Having an int pointer here allows binary compatibility but |
||||
* gives an error if someone tries to assign callback function. |
||||
* Also, NULL pointer marks a 'sizing stream' that does not |
||||
* write anything. |
||||
*/ |
||||
int *callback; |
||||
#else |
||||
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count); |
||||
#endif |
||||
void *state; /* Free field for use by callback implementation. */ |
||||
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ |
||||
size_t bytes_written; /* Number of bytes written so far. */ |
||||
|
||||
#ifndef PB_NO_ERRMSG |
||||
const char *errmsg; |
||||
#endif |
||||
}; |
||||
|
||||
/***************************
|
||||
* Main encoding functions * |
||||
***************************/ |
||||
|
||||
/* Encode a single protocol buffers message from C structure into a stream.
|
||||
* Returns true on success, false on any failure. |
||||
* The actual struct pointed to by src_struct must match the description in fields. |
||||
* All required fields in the struct are assumed to have been filled in. |
||||
* |
||||
* Example usage: |
||||
* MyMessage msg = {}; |
||||
* uint8_t buffer[64]; |
||||
* pb_ostream_t stream; |
||||
* |
||||
* msg.field1 = 42; |
||||
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); |
||||
* pb_encode(&stream, MyMessage_fields, &msg); |
||||
*/ |
||||
bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); |
||||
|
||||
/* Same as pb_encode, but prepends the length of the message as a varint.
|
||||
* Corresponds to writeDelimitedTo() in Google's protobuf API. |
||||
*/ |
||||
bool pb_encode_delimited(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); |
||||
|
||||
/**************************************
|
||||
* Functions for manipulating streams * |
||||
**************************************/ |
||||
|
||||
/* Create an output stream for writing into a memory buffer.
|
||||
* The number of bytes written can be found in stream.bytes_written after |
||||
* encoding the message. |
||||
* |
||||
* Alternatively, you can use a custom stream that writes directly to e.g. |
||||
* a file or a network socket. |
||||
*/ |
||||
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize); |
||||
|
||||
/* Pseudo-stream for measuring the size of a message without actually storing
|
||||
* the encoded data. |
||||
*
|
||||
* Example usage: |
||||
* MyMessage msg = {}; |
||||
* pb_ostream_t stream = PB_OSTREAM_SIZING; |
||||
* pb_encode(&stream, MyMessage_fields, &msg); |
||||
* printf("Message size is %d\n", stream.bytes_written); |
||||
*/ |
||||
#ifndef PB_NO_ERRMSG |
||||
#define PB_OSTREAM_SIZING {0,0,0,0,0} |
||||
#else |
||||
#define PB_OSTREAM_SIZING {0,0,0,0} |
||||
#endif |
||||
|
||||
/* Function to write into a pb_ostream_t stream. You can use this if you need
|
||||
* to append or prepend some custom headers to the message. |
||||
*/ |
||||
bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); |
||||
|
||||
|
||||
/************************************************
|
||||
* Helper functions for writing field callbacks * |
||||
************************************************/ |
||||
|
||||
/* Encode field header based on type and field number defined in the field
|
||||
* structure. Call this from the callback before writing out field contents. */ |
||||
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); |
||||
|
||||
/* Encode field header by manually specifing wire type. You need to use this
|
||||
* if you want to write out packed arrays from a callback field. */ |
||||
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); |
||||
|
||||
/* Encode an integer in the varint format.
|
||||
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */ |
||||
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); |
||||
|
||||
/* Encode an integer in the zig-zagged svarint format.
|
||||
* This works for sint32 and sint64. */ |
||||
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); |
||||
|
||||
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ |
||||
bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size); |
||||
|
||||
/* Encode a fixed32, sfixed32 or float value.
|
||||
* You need to pass a pointer to a 4-byte wide C variable. */ |
||||
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); |
||||
|
||||
/* Encode a fixed64, sfixed64 or double value.
|
||||
* You need to pass a pointer to a 8-byte wide C variable. */ |
||||
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); |
||||
|
||||
/* Encode a submessage field.
|
||||
* You need to pass the pb_field_t array and pointer to struct, just like |
||||
* with pb_encode(). This internally encodes the submessage twice, first to |
||||
* calculate message size and then to actually write it out. |
||||
*/ |
||||
bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,5 @@ |
||||
grpc.lb.v0.InitialLoadBalanceRequest.name max_size:128 |
||||
grpc.lb.v0.InitialLoadBalanceResponse.client_config max_size:64 |
||||
grpc.lb.v0.InitialLoadBalanceResponse.load_balancer_delegate max_size:64 |
||||
grpc.lb.v0.Server.ip_address max_size:46 |
||||
grpc.lb.v0.Server.load_balance_token max_size:64 |
@ -0,0 +1,115 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package grpc.lb.v0; |
||||
|
||||
message Duration { |
||||
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000 |
||||
// to +315,576,000,000 inclusive. |
||||
int64 seconds = 1; |
||||
|
||||
// Signed fractions of a second at nanosecond resolution of the span |
||||
// of time. Durations less than one second are represented with a 0 |
||||
// `seconds` field and a positive or negative `nanos` field. For durations |
||||
// of one second or more, a non-zero value for the `nanos` field must be |
||||
// of the same sign as the `seconds` field. Must be from -999,999,999 |
||||
// to +999,999,999 inclusive. |
||||
int32 nanos = 2; |
||||
} |
||||
|
||||
service LoadBalancer { |
||||
// Bidirectional rpc to get a list of servers. |
||||
rpc BalanceLoad(stream LoadBalanceRequest) |
||||
returns (stream LoadBalanceResponse); |
||||
} |
||||
|
||||
message LoadBalanceRequest { |
||||
oneof load_balance_request_type { |
||||
// This message should be sent on the first request to the load balancer. |
||||
InitialLoadBalanceRequest initial_request = 1; |
||||
|
||||
// The client stats should be periodically reported to the load balancer |
||||
// based on the duration defined in the InitialLoadBalanceResponse. |
||||
ClientStats client_stats = 2; |
||||
} |
||||
} |
||||
|
||||
message InitialLoadBalanceRequest { |
||||
// Name of load balanced service (IE, service.grpc.gslb.google.com) |
||||
string name = 1; |
||||
} |
||||
|
||||
// Contains client level statistics that are useful to load balancing. Each |
||||
// count should be reset to zero after reporting the stats. |
||||
message ClientStats { |
||||
// The total number of requests sent by the client since the last report. |
||||
int64 total_requests = 1; |
||||
|
||||
// The number of client rpc errors since the last report. |
||||
int64 client_rpc_errors = 2; |
||||
|
||||
// The number of dropped requests since the last report. |
||||
int64 dropped_requests = 3; |
||||
} |
||||
|
||||
message LoadBalanceResponse { |
||||
oneof load_balance_response_type { |
||||
// This message should be sent on the first response to the client. |
||||
InitialLoadBalanceResponse initial_response = 1; |
||||
|
||||
// Contains the list of servers selected by the load balancer. The client |
||||
// should send requests to these servers in the specified order. |
||||
ServerList server_list = 2; |
||||
} |
||||
} |
||||
|
||||
message InitialLoadBalanceResponse { |
||||
oneof initial_response_type { |
||||
// Contains gRPC config options like RPC deadline or flow control. |
||||
// TODO(yetianx): Change to ClientConfig after it is defined. |
||||
string client_config = 1; |
||||
|
||||
// This is an application layer redirect that indicates the client should |
||||
// use the specified server for load balancing. When this field is set in |
||||
// the response, the client should open a separate connection to the |
||||
// load_balancer_delegate and call the BalanceLoad method. |
||||
string load_balancer_delegate = 2; |
||||
} |
||||
|
||||
// This interval defines how often the client should send the client stats |
||||
// to the load balancer. Stats should only be reported when the duration is |
||||
// positive. |
||||
Duration client_stats_report_interval = 3; |
||||
} |
||||
|
||||
message ServerList { |
||||
// Contains a list of servers selected by the load balancer. The list will |
||||
// be updated when server resolutions change or as needed to balance load |
||||
// across more servers. The client should consume the server list in order |
||||
// unless instructed otherwise via the client_config. |
||||
repeated Server servers = 1; |
||||
|
||||
// Indicates the amount of time that the client should consider this server |
||||
// list as valid. It may be considered stale after waiting this interval of |
||||
// time after receiving the list. If the interval is not positive, the |
||||
// client can assume the list is valid until the next list is received. |
||||
Duration expiration_interval = 3; |
||||
} |
||||
|
||||
message Server { |
||||
// A resolved address and port for the server. The IP address string may |
||||
// either be an IPv4 or IPv6 address. |
||||
string ip_address = 1; |
||||
int32 port = 2; |
||||
|
||||
// An opaque token that is passed from the client to the server in metadata. |
||||
// The server may expect this token to indicate that the request from the |
||||
// client was load balanced. |
||||
// TODO(yetianx): Not used right now, and will be used after implementing |
||||
// load report. |
||||
bytes load_balance_token = 3; |
||||
|
||||
// Indicates whether this particular request should be dropped by the client |
||||
// when this server is chosen from the list. |
||||
bool drop_request = 4; |
||||
} |
@ -0,0 +1,132 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <gtest/gtest.h> |
||||
#include <string> |
||||
|
||||
#include "src/core/client_config/lb_policies/load_balancer_api.h" |
||||
#include "src/core/client_config/lb_policies/protos/load_balancer.pb.h" |
||||
|
||||
namespace grpc { |
||||
namespace { |
||||
|
||||
using grpc::lb::v0::LoadBalanceRequest; |
||||
using grpc::lb::v0::LoadBalanceResponse; |
||||
|
||||
class GrpclbTest : public ::testing::Test {}; |
||||
|
||||
TEST_F(GrpclbTest, CreateRequest) { |
||||
const std::string service_name = "AServiceName"; |
||||
LoadBalanceRequest request; |
||||
grpc_grpclb_request* c_req = grpc_grpclb_request_create(service_name.c_str()); |
||||
gpr_slice slice = grpc_grpclb_request_encode(c_req); |
||||
const int num_bytes_written = GPR_SLICE_LENGTH(slice); |
||||
EXPECT_GT(num_bytes_written, 0); |
||||
request.ParseFromArray(GPR_SLICE_START_PTR(slice), num_bytes_written); |
||||
EXPECT_EQ(request.initial_request().name(), service_name); |
||||
gpr_slice_unref(slice); |
||||
grpc_grpclb_request_destroy(c_req); |
||||
} |
||||
|
||||
TEST_F(GrpclbTest, ParseResponse) { |
||||
LoadBalanceResponse response; |
||||
const std::string client_config_str = "I'm a client config"; |
||||
auto* initial_response = response.mutable_initial_response(); |
||||
initial_response->set_client_config(client_config_str); |
||||
auto* client_stats_report_interval = |
||||
initial_response->mutable_client_stats_report_interval(); |
||||
client_stats_report_interval->set_seconds(123); |
||||
client_stats_report_interval->set_nanos(456); |
||||
|
||||
const std::string encoded_response = response.SerializeAsString(); |
||||
gpr_slice encoded_slice = gpr_slice_from_copied_string(encoded_response.c_str()); |
||||
grpc_grpclb_response* c_response = |
||||
grpc_grpclb_response_parse(encoded_slice); |
||||
EXPECT_TRUE(c_response->has_initial_response); |
||||
EXPECT_TRUE(c_response->initial_response.has_client_config); |
||||
EXPECT_FALSE(c_response->initial_response.has_load_balancer_delegate); |
||||
EXPECT_TRUE(strcmp(c_response->initial_response.client_config, |
||||
client_config_str.c_str()) == 0); |
||||
EXPECT_EQ(c_response->initial_response.client_stats_report_interval.seconds, |
||||
123); |
||||
EXPECT_EQ(c_response->initial_response.client_stats_report_interval.nanos, |
||||
456); |
||||
gpr_slice_unref(encoded_slice); |
||||
grpc_grpclb_response_destroy(c_response); |
||||
} |
||||
|
||||
TEST_F(GrpclbTest, ParseResponseServerList) { |
||||
LoadBalanceResponse response; |
||||
auto* serverlist = response.mutable_server_list(); |
||||
auto* server = serverlist->add_servers(); |
||||
server->set_ip_address("127.0.0.1"); |
||||
server->set_port(12345); |
||||
server->set_drop_request(true); |
||||
server = response.mutable_server_list()->add_servers(); |
||||
server->set_ip_address("10.0.0.1"); |
||||
server->set_port(54321); |
||||
server->set_drop_request(false); |
||||
auto* expiration_interval = serverlist->mutable_expiration_interval(); |
||||
expiration_interval->set_seconds(888); |
||||
expiration_interval->set_nanos(999); |
||||
|
||||
const std::string encoded_response = response.SerializeAsString(); |
||||
gpr_slice encoded_slice = gpr_slice_from_copied_string(encoded_response.c_str()); |
||||
grpc_grpclb_serverlist *c_serverlist = |
||||
grpc_grpclb_response_parse_serverlist(encoded_slice); |
||||
ASSERT_EQ(c_serverlist->num_servers, 2ul); |
||||
EXPECT_TRUE(c_serverlist->servers[0]->has_ip_address); |
||||
EXPECT_TRUE(strcmp(c_serverlist->servers[0]->ip_address, "127.0.0.1") == 0); |
||||
EXPECT_EQ(c_serverlist->servers[0]->port, 12345); |
||||
EXPECT_TRUE(c_serverlist->servers[0]->drop_request); |
||||
EXPECT_TRUE(c_serverlist->servers[1]->has_ip_address); |
||||
EXPECT_TRUE(strcmp(c_serverlist->servers[1]->ip_address, "10.0.0.1") == 0); |
||||
EXPECT_EQ(c_serverlist->servers[1]->port, 54321); |
||||
EXPECT_FALSE(c_serverlist->servers[1]->drop_request); |
||||
|
||||
EXPECT_TRUE(c_serverlist->expiration_interval.has_seconds); |
||||
EXPECT_EQ(c_serverlist->expiration_interval.seconds, 888); |
||||
EXPECT_TRUE(c_serverlist->expiration_interval.has_nanos); |
||||
EXPECT_EQ(c_serverlist->expiration_interval.nanos, 999); |
||||
|
||||
gpr_slice_unref(encoded_slice); |
||||
grpc_grpclb_destroy_serverlist(c_serverlist); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace grpc
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
@ -0,0 +1,191 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\1.0.2.3.props')" /> |
||||
<ItemGroup Label="ProjectConfigurations"> |
||||
<ProjectConfiguration Include="Debug|Win32"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>Win32</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Debug|x64"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|Win32"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>Win32</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|x64"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>x64</Platform> |
||||
</ProjectConfiguration> |
||||
</ItemGroup> |
||||
<PropertyGroup Label="Globals"> |
||||
<ProjectGuid>{990AF023-17D7-8DBF-EB6E-14C7C016C77E}</ProjectGuid> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration"> |
||||
<PlatformToolset>v100</PlatformToolset> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration"> |
||||
<PlatformToolset>v110</PlatformToolset> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration"> |
||||
<PlatformToolset>v120</PlatformToolset> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<CharacterSet>Unicode</CharacterSet> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> |
||||
<ConfigurationType>Application</ConfigurationType> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
<CharacterSet>Unicode</CharacterSet> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
<ImportGroup Label="ExtensionSettings"> |
||||
</ImportGroup> |
||||
<ImportGroup Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="..\..\..\..\vsprojects\cpptest.props" /> |
||||
<Import Project="..\..\..\..\vsprojects\global.props" /> |
||||
<Import Project="..\..\..\..\vsprojects\openssl.props" /> |
||||
<Import Project="..\..\..\..\vsprojects\protobuf.props" /> |
||||
<Import Project="..\..\..\..\vsprojects\winsock.props" /> |
||||
<Import Project="..\..\..\..\vsprojects\zlib.props" /> |
||||
</ImportGroup> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> |
||||
<TargetName>grpclb_api_test</TargetName> |
||||
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> |
||||
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib> |
||||
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'"> |
||||
<TargetName>grpclb_api_test</TargetName> |
||||
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> |
||||
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib> |
||||
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
<ClCompile> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<Optimization>Disabled</Optimization> |
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
||||
<TreatWarningAsError>true</TreatWarningAsError> |
||||
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<ClCompile> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<Optimization>Disabled</Optimization> |
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
||||
<TreatWarningAsError>true</TreatWarningAsError> |
||||
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
<ClCompile> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<Optimization>MaxSpeed</Optimization> |
||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
||||
<TreatWarningAsError>true</TreatWarningAsError> |
||||
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
<OptimizeReferences>true</OptimizeReferences> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<ClCompile> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<Optimization>MaxSpeed</Optimization> |
||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
||||
<TreatWarningAsError>true</TreatWarningAsError> |
||||
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Console</SubSystem> |
||||
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
<OptimizeReferences>true</OptimizeReferences> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="..\..\..\..\src\core\client_config\lb_policies\protos\load_balancer.pb.cc"> |
||||
</ClCompile> |
||||
<ClInclude Include="..\..\..\..\src\core\client_config\lb_policies\protos\load_balancer.pb.h"> |
||||
</ClInclude> |
||||
<ClCompile Include="..\..\..\..\src\core\client_config\lb_policies\protos\load_balancer.grpc.pb.cc"> |
||||
</ClCompile> |
||||
<ClInclude Include="..\..\..\..\src\core\client_config\lb_policies\protos\load_balancer.grpc.pb.h"> |
||||
</ClInclude> |
||||
<ClCompile Include="..\..\..\..\test\cpp\grpclb\grpclb_api_test.cc"> |
||||
</ClCompile> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj"> |
||||
<Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj"> |
||||
<Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\..\..\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj"> |
||||
<Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<None Include="packages.config" /> |
||||
</ItemGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
<ImportGroup Label="ExtensionTargets"> |
||||
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> |
||||
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> |
||||
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> |
||||
<Import Project="..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets" Condition="Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> |
||||
</ImportGroup> |
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> |
||||
<PropertyGroup> |
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> |
||||
</PropertyGroup> |
||||
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\native\grpc.dependencies.zlib.redist.targets')" /> |
||||
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.9\build\native\grpc.dependencies.zlib.targets')" /> |
||||
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.2.3\build\native\grpc.dependencies.openssl.redist.targets')" /> |
||||
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.props')" /> |
||||
<Error Condition="!Exists('..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\vsprojects\packages\grpc.dependencies.openssl.1.0.2.3\build\native\grpc.dependencies.openssl.targets')" /> |
||||
</Target> |
||||
</Project> |
||||
|
@ -0,0 +1,39 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
||||
<ClCompile Include="..\..\..\..\src\core\client_config\lb_policies\protos\load_balancer.proto"> |
||||
<Filter>src\core\client_config\lb_policies\protos</Filter> |
||||
</ClCompile> |
||||
<ClCompile Include="..\..\..\..\test\cpp\grpclb\grpclb_api_test.cc"> |
||||
<Filter>test\cpp\grpclb</Filter> |
||||
</ClCompile> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<Filter Include="src"> |
||||
<UniqueIdentifier>{a31d21fb-c6ab-75ce-43dc-7d6f506765e6}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="src\core"> |
||||
<UniqueIdentifier>{1ac58546-6910-9066-c5c0-fe8db59c641f}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="src\core\client_config"> |
||||
<UniqueIdentifier>{9b998f5c-bc1b-9fc5-d21b-368485aac585}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="src\core\client_config\lb_policies"> |
||||
<UniqueIdentifier>{bb3a28b9-b005-fd49-9cc3-8ee9552226c1}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="src\core\client_config\lb_policies\protos"> |
||||
<UniqueIdentifier>{575e696e-0560-7b28-8e83-f8d1fa3cc9f7}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="test"> |
||||
<UniqueIdentifier>{64736e1d-eb77-664f-34ab-6cf41263d3d8}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="test\cpp"> |
||||
<UniqueIdentifier>{c86e9cb1-bed4-3697-40f2-9ecff6297fa5}</UniqueIdentifier> |
||||
</Filter> |
||||
<Filter Include="test\cpp\grpclb"> |
||||
<UniqueIdentifier>{6b5ba83a-6cf2-5a7b-0ab8-62de31882705}</UniqueIdentifier> |
||||
</Filter> |
||||
</ItemGroup> |
||||
</Project> |
||||
|
Loading…
Reference in new issue