Compare commits

..

3 Commits

Author SHA1 Message Date
zhwaaaaaa 378861e9c9 fix big message cause cpu 100% bug. #18 2025-04-25 20:34:27 +08:00
zhwaaaaaa 4542817ed2 nanopb upgrade 0.4.9. cluster script specified. weight. max_fails fails_timeout 2024-12-14 19:53:06 +08:00
zhwaaaaaa db782d97eb fix openresty patch dir. update readme. 2024-12-10 22:54:16 +08:00
27 changed files with 2939 additions and 1707 deletions

View File

@ -1,4 +1,5 @@
--- ---
SortIncludes: Never
Language: Cpp Language: Cpp
BasedOnStyle: Google BasedOnStyle: Google

12
.vscode/launch.json vendored
View File

@ -5,16 +5,12 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "(lldb) Launch", "type": "lldb",
"type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/cmake-build-debug/nginx_nacos", "name": "Launch",
"program": "${workspaceRoot}/cmake-build-debug/nginx_nacos",
"args": [], "args": [],
"stopAtEntry": false, "cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}/cmake-build-debug",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "cmake build" "preLaunchTask": "cmake build"
} }
] ]

30
.vscode/tasks.json vendored
View File

@ -5,29 +5,45 @@
}, },
"tasks": [ "tasks": [
{ {
"type": "shell",
"label": "cmake", "label": "cmake",
"command": "cmake", "command": "cmake",
"args": [ "args": [
"-DCMAKE_BUILD_TYPE=Debug",
".." ".."
] ]
}, },
{ {
"label": "make", "label": "make",
"group": {
"kind": "build",
"isDefault": true
},
"command": "make", "command": "make",
"args": ["nginx_nacos"] "args": [
"-j",
"4"
]
}, },
{ {
"label": "cmake build", "label": "cmake build",
"dependsOn": [ "dependsOn": [
"mkdir",
"cmake", "cmake",
"make" "make"
] ]
},
{
"type": "process",
"command": "/usr/bin/env",
"args": [
"CC=clang",
"CFLAGS=-g -Wall",
"make",
"${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"group": {
"kind": "build",
"isDefault": true
},
"label": "makelldb: selected file"
} }
] ]
} }

View File

@ -70,6 +70,10 @@ set(NGX_C_FILES nginx/src/core/nginx.c
nginx/src/os/unix/ngx_user.c nginx/src/os/unix/ngx_user.c
nginx/src/os/unix/ngx_dlopen.c nginx/src/os/unix/ngx_dlopen.c
nginx/src/os/unix/ngx_process_cycle.c nginx/src/os/unix/ngx_process_cycle.c
nginx/src/os/unix/ngx_linux_init.c
nginx/src/event/modules/ngx_epoll_module.c
nginx/src/os/unix/ngx_linux_sendfile_chain.c
nginx/src/core/ngx_bpf.c
nginx/src/event/ngx_event_openssl.c nginx/src/event/ngx_event_openssl.c
nginx/src/event/ngx_event_openssl_stapling.c nginx/src/event/ngx_event_openssl_stapling.c
nginx/src/core/ngx_regex.c nginx/src/core/ngx_regex.c
@ -85,6 +89,8 @@ set(NGX_C_FILES nginx/src/core/nginx.c
nginx/src/http/ngx_http_upstream.c nginx/src/http/ngx_http_upstream.c
nginx/src/http/ngx_http_upstream_round_robin.c nginx/src/http/ngx_http_upstream_round_robin.c
nginx/src/http/ngx_http_file_cache.c nginx/src/http/ngx_http_file_cache.c
nginx/src/http/ngx_http_huff_decode.c
nginx/src/http/ngx_http_huff_encode.c
nginx/src/http/ngx_http_write_filter_module.c nginx/src/http/ngx_http_write_filter_module.c
nginx/src/http/ngx_http_header_filter_module.c nginx/src/http/ngx_http_header_filter_module.c
nginx/src/http/modules/ngx_http_chunked_filter_module.c nginx/src/http/modules/ngx_http_chunked_filter_module.c
@ -101,8 +107,6 @@ set(NGX_C_FILES nginx/src/core/nginx.c
nginx/src/http/v2/ngx_http_v2.c nginx/src/http/v2/ngx_http_v2.c
nginx/src/http/v2/ngx_http_v2_table.c nginx/src/http/v2/ngx_http_v2_table.c
nginx/src/http/v2/ngx_http_v2_encode.c nginx/src/http/v2/ngx_http_v2_encode.c
nginx/src/http/v2/ngx_http_v2_huff_decode.c
nginx/src/http/v2/ngx_http_v2_huff_encode.c
nginx/src/http/v2/ngx_http_v2_module.c nginx/src/http/v2/ngx_http_v2_module.c
nginx/src/http/modules/ngx_http_static_module.c nginx/src/http/modules/ngx_http_static_module.c
nginx/src/http/modules/ngx_http_autoindex_module.c nginx/src/http/modules/ngx_http_autoindex_module.c

View File

@ -82,9 +82,6 @@ cd nginx-1.15.2 && patch -p1 < ../nginx-nacos-upstream/patch/nginx.patch
```bash ```bash
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev
```
```bash
./configure --add-module=../nginx-nacos-upstream/modules/auxiliary --add-module=../nginx-nacos-upstream/modules/nacos --with-http_ssl_module --with-http_v2_module && make ./configure --add-module=../nginx-nacos-upstream/modules/auxiliary --add-module=../nginx-nacos-upstream/modules/nacos --with-http_ssl_module --with-http_v2_module && make
``` ```
@ -94,18 +91,18 @@ cd nginx-1.15.2 && patch -p1 < ../nginx-nacos-upstream/patch/nginx.patch
wget https://openresty.org/download/openresty-1.25.3.2.tar.gz wget https://openresty.org/download/openresty-1.25.3.2.tar.gz
tar zxvf openresty-1.25.3.2.tar.gz tar zxvf openresty-1.25.3.2.tar.gz
``` ```
- 下载本项目源代码 nginx-nacos-upstream .本项目对 nginx 源代码有少量修改,所以需要 打上 patch - 下载本项目源代码 nginx-nacos-upstream .本项目对 nginx 源代码有少量修改,所以需要 打上 patch. 注意这里使用的是openresty.patch 并且进入 bundle 下的 nginx 目录执行
```bash ```bash
cd openresty-1.25.3.2 && patch -p1 < ../nginx-nacos-upstream/patch/openresty.patch cd openresty-1.25.3.2/bundle/nginx-1.25.3 && patch -p1 < ../../../nginx-nacos-upstream/patch/openresty.patch
``` ```
- build nginx. ubuntu 下安装方式为 - build nginx. ubuntu 下安装方式为
```bash ```bash
cd ../..
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev
``` ./configure --add-module=../nginx-nacos-upstream/modules/auxiliary --add-module=../nginx-nacos-upstream/modules/nacos
make
```bash
./configure --add-module=../nginx-nacos-upstream/modules/auxiliary --add-module=../nginx-nacos-upstream/modules/nacos && make
``` ```
### 原理 ### 原理
@ -177,9 +174,9 @@ service_namespace "public";
``` ```
#### cache_dir #### cache_dir
nacos 的文件 缓存目录,下次启动 会优先从 这个目录读取数据,加快启动时间,否则从 http 地址拉取。"/"结尾 nacos 的文件 缓存目录,下次启动 会优先从 这个目录读取数据,加快启动时间,否则从 http 地址拉取。保证该目录 nobody 用户可读写
``` ```
cache_dir nacos_cache/; cache_dir nacos_cache;
``` ```
@ -229,10 +226,23 @@ upstream backend {
# server 127.0.0.1:8080; # server 127.0.0.1:8080;
# 如果provider使用的springservice_name 要和 spring.application.name一致 # 如果provider使用的springservice_name 要和 spring.application.name一致
# 不知道 provider 端怎么写请参考 https://github.com/zhwaaaaaa/springmvc-nacos-registry # 不知道 provider 端怎么写请参考 https://github.com/zhwaaaaaa/springmvc-nacos-registry
nacos_subscribe_service service_name=springmvc-nacos-demo group=DEFAULT_GROUP; # weight * nacos_weight 是 nginx 的权重默认1 max_fails=1 fail_timeout 对应 nginx 的server 配置
nacos_subscribe_service service_name=springmvc-nacos-demo group=DEFAULT_GROUP weight=1 max_fails=1 fail_timeout=10s;
} }
``` ```
### nacos_use_cluster
如果指定,则对应使用 cluster ip. 支持变量和字面量组合. 不指定,则使用所有集群 ip
```
set $cluster "DEFAULT";
upstream backend {
nacos_subscribe_service service_name=springmvc-nacos-demo group=DEFAULT_GROUP weight=1 max_fails=1 fail_timeout=10s;
nacos_use_cluster $cluster;
}
```
### nacos_config_var ### nacos_config_var
订阅 nacos 的配置nginx把它写到 http 变量中。这个配置项可以出现在 http server location if {} 块中。 订阅 nacos 的配置nginx把它写到 http 变量中。这个配置项可以出现在 http server location if {} 块中。
``` ```

View File

@ -18,7 +18,7 @@ patch -p1 < ../patch/nginx.patch
--with-http_ssl_module \ --with-http_ssl_module \
--add-module=../modules/auxiliary \ --add-module=../modules/auxiliary \
--add-module=../modules/nacos \ --add-module=../modules/nacos \
--prefix=.. \ --prefix= \
--conf-path=conf/my.conf \ --conf-path=conf/my.conf \
--error-log-path=objs/logs/error.log \ --error-log-path=objs/logs/error.log \
--pid-path=objs/logs/nginx.pid \ --pid-path=objs/logs/nginx.pid \

View File

@ -14,16 +14,16 @@ events {
} }
nacos { nacos {
server_list localhost:8848; # nacos 服务器列表,空格隔开 server_list 127.0.0.1:8848; # nacos 服务器列表,空格隔开
grpc_server_list localhost:9848; # nacos grpc服务器列表空格隔开 grpc_server_list 127.0.0.1:9848; # nacos grpc服务器列表空格隔开
#udp_port 19999; #udp 端口号 #udp_port 19999; #udp 端口号
#udp_ip 127.0.0.1; #udp ip 地址。 #udp_ip 127.0.0.1; #udp ip 地址。
#udp_bind 0.0.0.0:19999; # 绑定udp 地址 #udp_bind 0.0.0.0:19999; # 绑定udp 地址
# username "nacos"; username "nacos";
# password "nacos"; password "nacos";
error_log cmake-build-debug/logs/nacos.log info; error_log objs/logs/nacos.log info;
default_group DEFAULT_GROUP; # 默认的nacos group name default_group DEFAULT_GROUP; # 默认的nacos group name
cache_dir cmake-build-debug/nacos/; cache_dir objs/nacos/;
} }
http { http {
include mime.types; include mime.types;
@ -39,26 +39,21 @@ http {
#gzip on; #gzip on;
upstream s { upstream s {
nacos_subscribe_service service_name=springmvc-nacos-demo; # data_id 要和 spring.application.name一致 nacos_subscribe_service service_name=springmvc-nacos-demo weight=100 max_fails=1 fail_timeout=10s; # service_name 要和 spring.application.name一致
nacos_use_cluster DEFAULT;
keepalive 300; keepalive 300;
} }
nacos_config_var $n_var data_id=ccccdddddd group=DEFAULT_GROUP md5_var=$dd default=123456; nacos_config_var $n_var data_id=tt.server.route.json group=stg1 md5_var=$dd default=123456;
server { server {
listen 9999 default_server; listen 9999 default_server;
proxy_set_header Connection ""; proxy_set_header Connection "";
proxy_http_version 1.1; proxy_http_version 1.1;
location ^~ / { location ^~ / {
add_header X-Var-Nacos "$n_var" always;
proxy_pass http://s; proxy_pass http://s;
} }
nacos_config_var $n_bb data_id=aaabbbbccc;
location ^~ /echo { location ^~ /echo {
nacos_config_var $n_var data_id=ccdd; return 200 "hear ....n_var: $n_var ... ....dd: $dd";
add_header X-Var-Nacos "$n_var";
return 200 "hear ....n_var: $n_var ... n_bb: $n_bb ....dd: $dd";
} }
} }
} }

10
generate_proto.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
set -e
mkdir -p objs
cd objs
curl -sSL https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.9-linux-x86.tar.gz -o nanopb.tar.gz
tar zxvf nanopb.tar.gz
mv nanopb-0.4.9-linux-x86 nanopb
python3 nanopb/generator/nanopb_generator.py backup.proto nacos_grpc_service.proto -I ../modules/nacos

View File

@ -1,34 +1,18 @@
/* Automatically generated nanopb constant definitions */ /* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.9.8 at Fri Aug 9 21:47:15 2024. */ /* Generated by nanopb-0.4.9 */
#include "backup.pb.h" #include "backup.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
PB_BIND(Config, Config, AUTO)
const pb_field_t Config_fields[4] = { PB_BIND(Instance, Instance, AUTO)
PB_FIELD( 1, UINT64 , SINGULAR, STATIC , FIRST, Config, version, version, 0),
PB_FIELD( 2, STRING , SINGULAR, CALLBACK, OTHER, Config, content, version, 0),
PB_FIELD( 3, STRING , SINGULAR, CALLBACK, OTHER, Config, md5, content, 0), PB_BIND(Service, Service, AUTO)
PB_LAST_FIELD
};
const pb_field_t Instance_fields[4] = {
PB_FIELD( 1, STRING , SINGULAR, CALLBACK, FIRST, Instance, host, host, 0),
PB_FIELD( 2, INT32 , SINGULAR, STATIC , OTHER, Instance, port, host, 0),
PB_FIELD( 3, INT32 , SINGULAR, STATIC , OTHER, Instance, weight, port, 0),
PB_LAST_FIELD
};
const pb_field_t Service_fields[3] = {
PB_FIELD( 1, UINT64 , SINGULAR, STATIC , FIRST, Service, version, version, 0),
PB_FIELD( 2, MESSAGE , REPEATED, CALLBACK, OTHER, Service, instances, version, &Instance_fields),
PB_LAST_FIELD
};
/* @@protoc_insertion_point(eof) */

View File

@ -1,48 +1,44 @@
/* Automatically generated nanopb header */ /* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.8 at Fri Aug 9 21:47:15 2024. */ /* Generated by nanopb-0.4.9 */
#ifndef PB_BACKUP_PB_H_INCLUDED #ifndef PB_BACKUP_PB_H_INCLUDED
#define PB_BACKUP_PB_H_INCLUDED #define PB_BACKUP_PB_H_INCLUDED
#include <pb/pb.h> #include <pb/pb.h>
/* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 40
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */ /* Struct definitions */
typedef struct _Config { typedef struct _Config {
uint64_t version; uint64_t version;
pb_callback_t content; pb_callback_t content;
pb_callback_t md5; pb_callback_t md5;
/* @@protoc_insertion_point(struct:Config) */
} Config; } Config;
typedef struct _Instance { typedef struct _Instance {
pb_callback_t host; pb_callback_t host;
int32_t port; int32_t port;
int32_t weight; int32_t weight;
/* @@protoc_insertion_point(struct:Instance) */ pb_callback_t cluster;
} Instance; } Instance;
typedef struct _Service { typedef struct _Service {
uint64_t version; uint64_t version;
pb_callback_t instances; pb_callback_t instances;
/* @@protoc_insertion_point(struct:Service) */
} Service; } Service;
/* Default values for struct fields */
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define Config_init_default {0, {{NULL}, NULL}, {{NULL}, NULL}} #define Config_init_default {0, {{NULL}, NULL}, {{NULL}, NULL}}
#define Instance_init_default {{{NULL}, NULL}, 0, 0} #define Instance_init_default {{{NULL}, NULL}, 0, 0, {{NULL}, NULL}}
#define Service_init_default {0, {{NULL}, NULL}} #define Service_init_default {0, {{NULL}, NULL}}
#define Config_init_zero {0, {{NULL}, NULL}, {{NULL}, NULL}} #define Config_init_zero {0, {{NULL}, NULL}, {{NULL}, NULL}}
#define Instance_init_zero {{{NULL}, NULL}, 0, 0} #define Instance_init_zero {{{NULL}, NULL}, 0, 0, {{NULL}, NULL}}
#define Service_init_zero {0, {{NULL}, NULL}} #define Service_init_zero {0, {{NULL}, NULL}}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
@ -52,30 +48,49 @@ typedef struct _Service {
#define Instance_host_tag 1 #define Instance_host_tag 1
#define Instance_port_tag 2 #define Instance_port_tag 2
#define Instance_weight_tag 3 #define Instance_weight_tag 3
#define Instance_cluster_tag 4
#define Service_version_tag 1 #define Service_version_tag 1
#define Service_instances_tag 2 #define Service_instances_tag 2
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
extern const pb_field_t Config_fields[4]; #define Config_FIELDLIST(X, a) \
extern const pb_field_t Instance_fields[4]; X(a, STATIC, SINGULAR, UINT64, version, 1) \
extern const pb_field_t Service_fields[3]; X(a, CALLBACK, SINGULAR, STRING, content, 2) \
X(a, CALLBACK, SINGULAR, STRING, md5, 3)
#define Config_CALLBACK pb_default_field_callback
#define Config_DEFAULT NULL
#define Instance_FIELDLIST(X, a) \
X(a, CALLBACK, SINGULAR, STRING, host, 1) \
X(a, STATIC, SINGULAR, INT32, port, 2) \
X(a, STATIC, SINGULAR, INT32, weight, 3) \
X(a, CALLBACK, SINGULAR, STRING, cluster, 4)
#define Instance_CALLBACK pb_default_field_callback
#define Instance_DEFAULT NULL
#define Service_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT64, version, 1) \
X(a, CALLBACK, REPEATED, MESSAGE, instances, 2)
#define Service_CALLBACK pb_default_field_callback
#define Service_DEFAULT NULL
#define Service_instances_MSGTYPE Instance
extern const pb_msgdesc_t Config_msg;
extern const pb_msgdesc_t Instance_msg;
extern const pb_msgdesc_t Service_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Config_fields &Config_msg
#define Instance_fields &Instance_msg
#define Service_fields &Service_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
/* Config_size depends on runtime parameters */ /* Config_size depends on runtime parameters */
/* Instance_size depends on runtime parameters */ /* Instance_size depends on runtime parameters */
/* Service_size depends on runtime parameters */ /* Service_size depends on runtime parameters */
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define BACKUP_MESSAGES \
#endif
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
/* @@protoc_insertion_point(eof) */
#endif #endif

View File

@ -10,6 +10,7 @@ message Instance {
string host = 1; string host = 1;
int32 port = 2; int32 port = 2;
int32 weight = 3; int32 weight = 3;
string cluster = 4;
} }
message Service { message Service {

View File

@ -1,73 +1,21 @@
/* Automatically generated nanopb constant definitions */ /* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.9.10 at Mon Jun 3 14:49:02 2024. */ /* Generated by nanopb-0.4.9 */
#include "nacos_grpc_service.pb.h" #include "nacos_grpc_service.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
/** PB_BIND(Any, Any, AUTO)
* #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)
*/
const pb_field_t google_protobuf_Any_fields[3] = { PB_BIND(Metadata, Metadata, AUTO)
PB_FIELD( 1, STRING , SINGULAR, CALLBACK, FIRST, google_protobuf_Any, type_url, type_url, 0),
PB_FIELD( 2, BYTES , SINGULAR, CALLBACK, OTHER, google_protobuf_Any, value, type_url, 0),
PB_LAST_FIELD
};
const pb_field_t Metadata_HeadersEntry_fields[3] = { PB_BIND(Metadata_HeadersEntry, Metadata_HeadersEntry, AUTO)
PB_FIELD( 1, STRING , SINGULAR, CALLBACK, FIRST, Metadata_HeadersEntry, key, key, 0),
PB_FIELD( 2, STRING , SINGULAR, CALLBACK, OTHER, Metadata_HeadersEntry, value, key, 0),
PB_LAST_FIELD
};
const pb_field_t Metadata_fields[4] = {
PB_FIELD( 3, STRING , SINGULAR, CALLBACK, FIRST, Metadata, type, type, 0),
// PB_SINGULAR_CALLBACK(3, Metadata, type, PB_DATAOFFSET_FIRST(Metadata, type, type), PB_LTYPE_MAP_STRING, 0),
PB_FIELD( 7, MESSAGE , REPEATED, CALLBACK, OTHER, Metadata, headers, type, &Metadata_HeadersEntry_fields),
PB_FIELD( 8, STRING , SINGULAR, CALLBACK, OTHER, Metadata, clientIp, headers, 0),
PB_LAST_FIELD
};
const pb_field_t Payload_fields[3] = { PB_BIND(Payload, Payload, AUTO)
PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , FIRST, Payload, metadata, metadata, &Metadata_fields),
// PB_SINGULAR_STATIC(2, Payload,metadata, PB_DATAOFFSET_FIRST(Payload, metadata, metadata), PB_LTYPE_MAP_MESSAGE, &Metadata_fields),
PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, Payload, body, metadata, &google_protobuf_Any_fields),
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(Payload, metadata) < 65536 && pb_membersize(Payload, body) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Metadata_Metadata_HeadersEntry_Payload)
#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(Payload, metadata) < 256 && pb_membersize(Payload, body) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Metadata_Metadata_HeadersEntry_Payload)
#endif
/* @@protoc_insertion_point(eof) */

View File

@ -1,106 +1,112 @@
/* Automatically generated nanopb header */ /* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.10 at Mon Jun 3 14:49:02 2024. */ /* Generated by nanopb-0.4.9 */
#ifndef PB_NACOS_GRPC_SERVICE_PB_H_INCLUDED #ifndef PB_NACOS_GRPC_SERVICE_PB_H_INCLUDED
#define PB_NACOS_GRPC_SERVICE_PB_H_INCLUDED #define PB_NACOS_GRPC_SERVICE_PB_H_INCLUDED
#include <pb/pb.h> #include <pb/pb.h>
/* @@protoc_insertion_point(includes) */ #if PB_PROTO_HEADER_VERSION != 40
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
/* Struct definitions */
typedef struct _Any {
pb_callback_t type_url;
pb_callback_t value;
} Any;
typedef struct _Metadata {
pb_callback_t type;
pb_callback_t headers;
pb_callback_t clientIp;
} Metadata;
typedef struct _Metadata_HeadersEntry {
pb_callback_t key;
pb_callback_t value;
} Metadata_HeadersEntry;
typedef struct _Payload {
bool has_metadata;
Metadata metadata;
bool has_body;
Any body;
} Payload;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Struct definitions */
typedef struct google_protobuf_Any {
pb_callback_t type_url;
pb_callback_t value;
/* @@protoc_insertion_point(struct:google_protobuf_Any) */
} google_protobuf_Any;
/* Default values for struct fields */
/* Initializer values for message structs */
#define google_protobuf_Any_init_default \
{ \
{{NULL}, NULL}, { {NULL}, NULL } \
}
#define google_protobuf_Any_init_zero \
{ \
{{NULL}, NULL}, { {NULL}, NULL } \
}
/* Field tags (for use in manual encoding/decoding) */
#define google_protobuf_Any_type_url_tag 1
#define google_protobuf_Any_value_tag 2
/* Struct field encoding specification for nanopb */
extern const pb_field_t google_protobuf_Any_fields[3];
/* Struct definitions */
typedef struct Metadata {
pb_callback_t type;
pb_callback_t headers;
pb_callback_t clientIp;
/* @@protoc_insertion_point(struct:Metadata) */
} Metadata;
typedef struct Metadata_HeadersEntry {
pb_callback_t key;
pb_callback_t value;
/* @@protoc_insertion_point(struct:Metadata_HeadersEntry) */
} Metadata_HeadersEntry;
typedef struct Payload {
Metadata metadata;
google_protobuf_Any body;
/* @@protoc_insertion_point(struct:Payload) */
} Payload;
/* Default values for struct fields */
/* Initializer values for message structs */ /* Initializer values for message structs */
#define Any_init_default {{{NULL}, NULL}, {{NULL}, NULL}}
#define Metadata_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} #define Metadata_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
#define Metadata_HeadersEntry_init_default {{{NULL}, NULL}, {{NULL}, NULL}} #define Metadata_HeadersEntry_init_default {{{NULL}, NULL}, {{NULL}, NULL}}
#define Payload_init_default {Metadata_init_default, google_protobuf_Any_init_default} #define Payload_init_default {false, Metadata_init_default, false, Any_init_default}
#define Any_init_zero {{{NULL}, NULL}, {{NULL}, NULL}}
#define Metadata_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}} #define Metadata_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
#define Metadata_HeadersEntry_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} #define Metadata_HeadersEntry_init_zero {{{NULL}, NULL}, {{NULL}, NULL}}
#define Payload_init_zero {Metadata_init_zero, google_protobuf_Any_init_zero} #define Payload_init_zero {false, Metadata_init_zero, false, Any_init_zero}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define Any_type_url_tag 1
#define Any_value_tag 2
#define Metadata_type_tag 3 #define Metadata_type_tag 3
#define Metadata_clientIp_tag 8
#define Metadata_headers_tag 7 #define Metadata_headers_tag 7
#define Metadata_clientIp_tag 8
#define Metadata_HeadersEntry_key_tag 1 #define Metadata_HeadersEntry_key_tag 1
#define Metadata_HeadersEntry_value_tag 2 #define Metadata_HeadersEntry_value_tag 2
#define Payload_metadata_tag 2 #define Payload_metadata_tag 2
#define Payload_body_tag 3 #define Payload_body_tag 3
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
extern const pb_field_t Metadata_fields[4]; #define Any_FIELDLIST(X, a) \
extern const pb_field_t Metadata_HeadersEntry_fields[3]; X(a, CALLBACK, SINGULAR, STRING, type_url, 1) \
extern const pb_field_t Payload_fields[3]; X(a, CALLBACK, SINGULAR, BYTES, value, 2)
#define Any_CALLBACK pb_default_field_callback
#define Any_DEFAULT NULL
#define Metadata_FIELDLIST(X, a) \
X(a, CALLBACK, SINGULAR, STRING, type, 3) \
X(a, CALLBACK, REPEATED, MESSAGE, headers, 7) \
X(a, CALLBACK, SINGULAR, STRING, clientIp, 8)
#define Metadata_CALLBACK pb_default_field_callback
#define Metadata_DEFAULT NULL
#define Metadata_headers_MSGTYPE Metadata_HeadersEntry
#define Metadata_HeadersEntry_FIELDLIST(X, a) \
X(a, CALLBACK, SINGULAR, STRING, key, 1) \
X(a, CALLBACK, SINGULAR, STRING, value, 2)
#define Metadata_HeadersEntry_CALLBACK pb_default_field_callback
#define Metadata_HeadersEntry_DEFAULT NULL
#define Payload_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, metadata, 2) \
X(a, STATIC, OPTIONAL, MESSAGE, body, 3)
#define Payload_CALLBACK NULL
#define Payload_DEFAULT NULL
#define Payload_metadata_MSGTYPE Metadata
#define Payload_body_MSGTYPE Any
extern const pb_msgdesc_t Any_msg;
extern const pb_msgdesc_t Metadata_msg;
extern const pb_msgdesc_t Metadata_HeadersEntry_msg;
extern const pb_msgdesc_t Payload_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Any_fields &Any_msg
#define Metadata_fields &Metadata_msg
#define Metadata_HeadersEntry_fields &Metadata_HeadersEntry_msg
#define Payload_fields &Payload_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
/* Any_size depends on runtime parameters */
/* Metadata_size depends on runtime parameters */ /* Metadata_size depends on runtime parameters */
/* Metadata_HeadersEntry_size depends on runtime parameters */ /* Metadata_HeadersEntry_size depends on runtime parameters */
/* Payload_size depends on runtime parameters */ /* Payload_size depends on runtime parameters */
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define NACOS_GRPC_SERVICE_MESSAGES \
#endif
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
/* @@protoc_insertion_point(eof) */
#endif #endif

View File

@ -0,0 +1,37 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.alibaba.nacos.api.grpc.auto";
message Any {
string type_url = 1;
bytes value = 2;
}
message Metadata {
string type = 3;
string clientIp = 8;
map<string, string> headers = 7;
}
message Payload {
Metadata metadata = 2;
Any body = 3;
}

View File

@ -13,6 +13,12 @@ typedef struct {
ngx_http_upstream_init_pt original_init_upstream; ngx_http_upstream_init_pt original_init_upstream;
ngx_str_t data_id; ngx_str_t data_id;
ngx_str_t group; ngx_str_t group;
ngx_uint_t weight;
ngx_uint_t max_fails;
time_t fail_timeout;
ngx_str_t cluster;
ngx_array_t *cluster_lengths;
ngx_array_t *cluster_values;
} ngx_http_nacos_srv_conf_t; } ngx_http_nacos_srv_conf_t;
typedef struct { typedef struct {
@ -21,7 +27,10 @@ typedef struct {
ngx_nacos_key_t *key; ngx_nacos_key_t *key;
ngx_uint_t version; ngx_uint_t version;
ngx_nacos_service_addrs_t addrs; ngx_nacos_service_addrs_t addrs;
ngx_http_upstream_srv_conf_t *us; ngx_flag_t use_cluster;
ngx_http_upstream_srv_conf_t *origin;
ngx_http_upstream_srv_conf_t *us; // no cluster
ngx_array_t *clustered_us; // ngx_http_upstream_srv_conf_t
} ngx_http_nacos_peers_t; } ngx_http_nacos_peers_t;
typedef struct { typedef struct {
@ -41,14 +50,17 @@ static void *ngx_http_nacos_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_conf_nacos_use_cluster(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_nacos_init_upstream(ngx_conf_t *cf, static ngx_int_t ngx_http_nacos_init_upstream(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us); ngx_http_upstream_srv_conf_t *us);
static ngx_int_t ngx_http_nacos_init_peers(ngx_http_request_t *r, static ngx_int_t ngx_http_nacos_init_peers(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us); ngx_http_upstream_srv_conf_t *us);
static ngx_int_t ngx_http_nacos_create_new_us(ngx_http_nacos_peers_t *new_peers, static ngx_http_upstream_srv_conf_t *ngx_http_nacos_select_upstream(
ngx_http_upstream_srv_conf_t *us); ngx_http_nacos_peers_t *peers, ngx_str_t *cluster);
static ngx_http_nacos_peers_t *ngx_http_get_nacos_peers( static ngx_http_nacos_peers_t *ngx_http_get_nacos_peers(
ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us); ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us);
@ -83,8 +95,11 @@ static ngx_http_module_t ngx_http_nacos_module_ctx = {
}; };
static ngx_command_t cmds[] = { static ngx_command_t cmds[] = {
{ngx_string("nacos_subscribe_service"), NGX_HTTP_UPS_CONF | NGX_CONF_TAKE12, {ngx_string("nacos_subscribe_service"),
ngx_http_conf_use_nacos_address, NGX_HTTP_SRV_CONF_OFFSET, 0, NULL}, NGX_HTTP_UPS_CONF | NGX_CONF_1MORE, ngx_http_conf_use_nacos_address,
NGX_HTTP_SRV_CONF_OFFSET, 0, NULL},
{ngx_string("nacos_use_cluster"), NGX_HTTP_UPS_CONF | NGX_CONF_TAKE1,
ngx_http_conf_nacos_use_cluster, NGX_HTTP_SRV_CONF_OFFSET, 0, NULL},
ngx_null_command}; ngx_null_command};
ngx_module_t ngx_http_nacos_upstream_module = {NGX_MODULE_V1, ngx_module_t ngx_http_nacos_upstream_module = {NGX_MODULE_V1,
@ -103,20 +118,29 @@ ngx_module_t ngx_http_nacos_upstream_module = {NGX_MODULE_V1,
static void *ngx_http_nacos_create_srv_conf(ngx_conf_t *cf) { static void *ngx_http_nacos_create_srv_conf(ngx_conf_t *cf) {
return ngx_pcalloc(cf->pool, sizeof(ngx_http_nacos_srv_conf_t)); return ngx_pcalloc(cf->pool, sizeof(ngx_http_nacos_srv_conf_t));
} }
static ngx_int_t ngx_http_nacos_add_server(ngx_http_nacos_peers_t *peers,
ngx_http_nacos_srv_conf_t *nscf,
ngx_pool_t *temp_pool);
static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf) { void *conf) {
ngx_http_nacos_srv_conf_t *nlcf = conf; ngx_http_nacos_srv_conf_t *nlcf = conf;
ngx_uint_t i; ngx_uint_t i;
ngx_uint_t n = cf->args->nelts; ngx_uint_t n = cf->args->nelts;
ngx_str_t *value = cf->args->elts; ngx_str_t *value = cf->args->elts, s;
ngx_nacos_sub_t tmp; ngx_nacos_sub_t tmp;
ngx_nacos_main_conf_t *mf; ngx_nacos_main_conf_t *mf;
ngx_int_t weight, max_fails;
time_t fail_timeout;
if (nlcf->uscf) { if (nlcf->uscf) {
return "is duplicate"; return "is duplicate";
} }
weight = 1;
max_fails = 1;
fail_timeout = 10;
ngx_memzero(&tmp, sizeof(tmp)); ngx_memzero(&tmp, sizeof(tmp));
for (i = 1; i < n; ++i) { for (i = 1; i < n; ++i) {
@ -131,6 +155,62 @@ static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd,
tmp.group.len = value[i].len - 6; tmp.group.len = value[i].len - 6;
continue; continue;
} }
if (value[i].len > 7 && ngx_strncmp(value[i].data, "weight=", 7) == 0) {
weight = ngx_atoi(value[i].data + 7, value[i].len - 7);
if (weight <= 0) {
ngx_conf_log_error(
NGX_LOG_EMERG, cf, 0,
"weight= must be number: invalid parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
continue;
}
if (value[i].len > 10 &&
ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
max_fails = ngx_atoi(value[i].data + 10, value[i].len - 10);
if (max_fails < 0) {
ngx_conf_log_error(
NGX_LOG_EMERG, cf, 0,
"max_fails= must be number: invalid parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
continue;
}
if (value[i].len > 10 &&
ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
max_fails = ngx_atoi(value[i].data + 10, value[i].len - 10);
if (max_fails < 0) {
ngx_conf_log_error(
NGX_LOG_EMERG, cf, 0,
"max_fails= must be number: invalid parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
continue;
}
if (value[i].len > 13 &&
ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
s.len = value[i].len - 13;
s.data = &value[i].data[13];
fail_timeout = ngx_parse_time(&s, 1);
if (fail_timeout == (time_t) NGX_ERROR) {
ngx_conf_log_error(
NGX_LOG_EMERG, cf, 0,
"fail_timeout= must be time: invalid parameter \"%V\"",
&value[i]);
return NGX_CONF_ERROR;
}
continue;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
&value[i]); &value[i]);
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
@ -143,6 +223,10 @@ static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd,
nlcf->data_id = tmp.data_id; nlcf->data_id = tmp.data_id;
nlcf->group = tmp.group; nlcf->group = tmp.group;
nlcf->weight = weight;
nlcf->max_fails = max_fails;
nlcf->fail_timeout = fail_timeout;
nlcf->uscf = nlcf->uscf =
ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
nlcf->original_init_upstream = nlcf->uscf->peer.init_upstream; nlcf->original_init_upstream = nlcf->uscf->peer.init_upstream;
@ -161,6 +245,40 @@ static char *ngx_http_conf_use_nacos_address(ngx_conf_t *cf, ngx_command_t *cmd,
return NGX_CONF_OK; return NGX_CONF_OK;
} }
static char *ngx_http_conf_nacos_use_cluster(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf) {
ngx_uint_t n;
ngx_http_script_compile_t sc;
ngx_str_t *value;
ngx_http_nacos_srv_conf_t *nscf = conf;
if (nscf->cluster_lengths != NULL || nscf->cluster.len > 0) {
return "is duplicate";
}
value = cf->args->elts;
nscf->cluster = value[1];
n = ngx_http_script_variables_count(&nscf->cluster);
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.variables = n;
if (n) {
sc.cf = cf;
sc.source = &nscf->cluster;
sc.lengths = &nscf->cluster_lengths;
sc.values = &nscf->cluster_values;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
u_char *ngx_http_nacos_log_handler(ngx_log_t *log, u_char *buf, size_t len) { u_char *ngx_http_nacos_log_handler(ngx_log_t *log, u_char *buf, size_t len) {
ngx_http_nacos_peers_t *peers; ngx_http_nacos_peers_t *peers;
u_char *p = buf; u_char *p = buf;
@ -175,12 +293,14 @@ u_char *ngx_http_nacos_log_handler(ngx_log_t *log, u_char *buf, size_t len) {
return p; return p;
} }
static ngx_http_nacos_peers_t *ngx_http_nacos_create_peers(ngx_log_t *log) { static ngx_http_nacos_peers_t *ngx_http_nacos_create_peers(
ngx_log_t *log, ngx_flag_t clustered,
ngx_http_upstream_srv_conf_t *origin) {
ngx_pool_t *pool; ngx_pool_t *pool;
ngx_http_nacos_peers_t *peers; ngx_http_nacos_peers_t *peers;
ngx_log_t *new_log; ngx_log_t *new_log;
pool = ngx_create_pool(1024, log); pool = ngx_create_pool(2048, log);
if (pool == NULL) { if (pool == NULL) {
return NULL; return NULL;
} }
@ -203,6 +323,8 @@ static ngx_http_nacos_peers_t *ngx_http_nacos_create_peers(ngx_log_t *log) {
new_log->handler = ngx_http_nacos_log_handler; new_log->handler = ngx_http_nacos_log_handler;
new_log->action = "nacos update addrs"; new_log->action = "nacos update addrs";
peers->origin = origin;
peers->use_cluster = clustered;
peers->pool = pool; peers->pool = pool;
peers->ref = 1; peers->ref = 1;
if (ngx_array_init(&peers->addrs.addrs, peers->pool, 16, if (ngx_array_init(&peers->addrs.addrs, peers->pool, 16,
@ -213,13 +335,15 @@ static ngx_http_nacos_peers_t *ngx_http_nacos_create_peers(ngx_log_t *log) {
return peers; return peers;
} }
static ngx_int_t ngx_http_nacos_add_server(ngx_http_nacos_peers_t *peers) { static ngx_int_t ngx_http_nacos_add_server(ngx_http_nacos_peers_t *peers,
ngx_http_nacos_srv_conf_t *nscf,
ngx_pool_t *temp_pool) {
ngx_http_upstream_server_t *server; ngx_http_upstream_server_t *server;
ngx_http_upstream_srv_conf_t *us; ngx_http_upstream_srv_conf_t *us;
ngx_nacos_service_addr_t *adr; ngx_nacos_service_addr_t *adr;
ngx_uint_t i, n; ngx_uint_t i, n;
ngx_url_t u; ngx_url_t u;
us = peers->us; ngx_conf_t cf;
n = peers->addrs.addrs.nelts; n = peers->addrs.addrs.nelts;
adr = peers->addrs.addrs.elts; adr = peers->addrs.addrs.elts;
@ -230,6 +354,12 @@ static ngx_int_t ngx_http_nacos_add_server(ngx_http_nacos_peers_t *peers) {
if (ngx_parse_url(peers->pool, &u) != NGX_OK) { if (ngx_parse_url(peers->pool, &u) != NGX_OK) {
continue; continue;
} }
us = ngx_http_nacos_select_upstream(peers, &adr->cluster);
if (us == NULL) {
return NGX_ERROR;
}
server = ngx_array_push(us->servers); server = ngx_array_push(us->servers);
if (server == NULL) { if (server == NULL) {
return NGX_ERROR; return NGX_ERROR;
@ -238,7 +368,34 @@ static ngx_int_t ngx_http_nacos_add_server(ngx_http_nacos_peers_t *peers) {
server->addrs = u.addrs; server->addrs = u.addrs;
server->naddrs = u.naddrs; server->naddrs = u.naddrs;
server->name = u.url; server->name = u.url;
server->weight = adr[i].weight; server->weight =
(ngx_uint_t) (adr[i].weight / 0.01 * (double) nscf->weight);
server->max_fails = nscf->max_fails;
server->fail_timeout = nscf->fail_timeout;
}
if (peers->addrs.addrs.nelts > 0) {
if (peers->us) {
memset(&cf, 0, sizeof(cf));
cf.pool = peers->pool;
cf.temp_pool = temp_pool;
cf.log = temp_pool->log;
if (nscf->original_init_upstream(&cf, peers->us) != NGX_OK) {
return NGX_ERROR;
}
} else {
us = peers->clustered_us->elts;
n = peers->clustered_us->nelts;
for (i = 0; i < n; ++i) {
memset(&cf, 0, sizeof(cf));
cf.pool = peers->pool;
cf.temp_pool = temp_pool;
cf.log = temp_pool->log;
if (nscf->original_init_upstream(&cf, us + i) != NGX_OK) {
return NGX_ERROR;
}
}
}
} }
return NGX_OK; return NGX_OK;
} }
@ -249,19 +406,15 @@ static ngx_int_t ngx_http_nacos_init_upstream(
ngx_pool_t *pool; ngx_pool_t *pool;
ngx_http_nacos_peers_t *peers; ngx_http_nacos_peers_t *peers;
ngx_http_nacos_srv_conf_t *ncf; ngx_http_nacos_srv_conf_t *ncf;
ngx_conf_t new_cf;
ncf = ngx_http_conf_upstream_srv_conf(us, ngx_http_nacos_upstream_module); ncf = ngx_http_conf_upstream_srv_conf(us, ngx_http_nacos_upstream_module);
peers = ngx_http_nacos_create_peers(cf->log);
peers = ngx_http_nacos_create_peers(cf->log, ncf->cluster.len > 0, us);
if (peers == NULL) { if (peers == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
pool = peers->pool; pool = peers->pool;
if (ngx_http_nacos_create_new_us(peers, us) != NGX_OK) {
ngx_destroy_pool(pool);
return NGX_ERROR;
}
sub.key_ptr = &peers->key; sub.key_ptr = &peers->key;
sub.data_id = ncf->data_id; sub.data_id = ncf->data_id;
@ -283,49 +436,89 @@ static ngx_int_t ngx_http_nacos_init_upstream(
return NGX_ERROR; return NGX_ERROR;
} }
if (ngx_http_nacos_add_server(peers) != NGX_OK) { if (ngx_http_nacos_add_server(peers, ncf, cf->temp_pool) != NGX_OK) {
ngx_destroy_pool(pool); ngx_destroy_pool(pool);
return NGX_ERROR; return NGX_ERROR;
} }
if (peers->addrs.addrs.nelts > 0) {
new_cf = *cf;
new_cf.pool = pool;
new_cf.log = pool->log;
if (ncf->original_init_upstream(&new_cf, peers->us) != NGX_OK) {
ngx_destroy_pool(pool);
return NGX_ERROR;
}
}
us->peer.init = ngx_http_nacos_init_peers; us->peer.init = ngx_http_nacos_init_peers;
us->peer.data = peers; us->peer.data = peers;
return NGX_OK; return NGX_OK;
} }
static ngx_int_t ngx_http_nacos_create_new_us( static ngx_http_upstream_srv_conf_t *ngx_http_nacos_select_upstream(
ngx_http_nacos_peers_t *new_peers, ngx_http_upstream_srv_conf_t *us) { ngx_http_nacos_peers_t *peers, ngx_str_t *cluster) {
ngx_http_upstream_srv_conf_t *new_us; ngx_http_upstream_srv_conf_t *us;
ngx_uint_t i, n;
new_us = ngx_palloc(new_peers->pool, sizeof(*new_us)); if (!peers->use_cluster) {
if (new_us == NULL) { us = peers->us;
return NGX_ERROR; if (us == NULL) {
us = ngx_palloc(peers->pool, sizeof(*us));
if (us == NULL) {
return NULL;
} }
*new_us = *us; *us = *peers->origin;
new_us->servers = ngx_array_create(new_peers->pool, 16, us->servers = ngx_array_create(peers->pool, 16,
sizeof(ngx_http_upstream_server_t)); sizeof(ngx_http_upstream_server_t));
if (new_us->servers == NULL) { if (us->servers == NULL) {
return NGX_ERROR; return NULL;
} }
new_peers->us = new_us; peers->us = us;
return NGX_OK; ngx_str_set(&us->host, "nacos-no-cluster");
}
} else {
if (peers->clustered_us == NULL) {
peers->clustered_us = ngx_array_create(peers->pool, 4, sizeof(*us));
if (peers->clustered_us == NULL) {
return NULL;
}
}
us = peers->clustered_us->elts;
n = peers->clustered_us->nelts;
if (n > 0) {
for (i = 0; i < n; ++i) {
if (us[i].host.len == cluster->len &&
ngx_strncmp(us[i].host.data, cluster->data, cluster->len) ==
0) {
return us + i;
}
}
}
us = ngx_array_push(peers->clustered_us);
if (us == NULL) {
return NULL;
}
*us = *peers->origin;
us->servers = ngx_array_create(peers->pool, 16,
sizeof(ngx_http_upstream_server_t));
if (us->servers == NULL) {
return NULL;
}
us->host.len = cluster->len;
us->host.data = ngx_palloc(peers->pool, cluster->len + 1);
if (us->host.data == NULL) {
return NULL;
}
ngx_memcpy(us->host.data, cluster->data, cluster->len);
us->host.data[cluster->len] = 0;
}
return us;
} }
static ngx_int_t ngx_http_nacos_init_peers(ngx_http_request_t *r, static ngx_int_t ngx_http_nacos_init_peers(ngx_http_request_t *r,
ngx_http_upstream_srv_conf_t *us) { ngx_http_upstream_srv_conf_t *us) {
ngx_http_nacos_peers_t *peers; ngx_http_nacos_peers_t *peers;
ngx_http_nacos_rrp_t *rrp; ngx_http_nacos_rrp_t *rrp;
ngx_http_upstream_srv_conf_t *selected_us, *uc;
ngx_str_t cluster;
ngx_http_nacos_srv_conf_t *nusf;
ngx_int_t rc; ngx_int_t rc;
ngx_uint_t i, n;
rrp = r->upstream->peer.data; rrp = r->upstream->peer.data;
if (rrp == NULL) { if (rrp == NULL) {
@ -341,7 +534,42 @@ static ngx_int_t ngx_http_nacos_init_peers(ngx_http_request_t *r,
if (peers == NULL || peers->addrs.addrs.nelts == 0) { if (peers == NULL || peers->addrs.addrs.nelts == 0) {
return NGX_ERROR; return NGX_ERROR;
} }
rc = peers->us->peer.init(r, peers->us);
nusf = ngx_http_conf_upstream_srv_conf(us, ngx_http_nacos_upstream_module);
if (!peers->use_cluster) {
selected_us = peers->us;
} else {
selected_us = NULL;
ngx_memzero(&cluster, sizeof(cluster));
if (nusf->cluster_lengths == NULL) {
cluster = nusf->cluster;
} else {
if (ngx_http_script_run(r, &cluster, nusf->cluster_lengths->elts, 0,
nusf->cluster_values->elts) == NULL) {
return NGX_ERROR;
}
}
if (peers->clustered_us == NULL || peers->clustered_us->nelts == 0) {
return NGX_ERROR;
}
n = peers->clustered_us->nelts;
uc = peers->clustered_us->elts;
for (i = 0; i < n; ++i) {
if (cluster.len == uc[i].host.len &&
ngx_strncmp(cluster.data, uc[i].host.data, cluster.len) == 0) {
selected_us = uc + i;
break;
}
}
}
if (selected_us == NULL) {
return NGX_ERROR;
}
rc = selected_us->peer.init(r, selected_us);
if (rc != NGX_OK) { if (rc != NGX_OK) {
return rc; return rc;
} }
@ -369,7 +597,6 @@ static ngx_http_nacos_peers_t *ngx_http_get_nacos_peers(
ngx_http_nacos_peers_t *peers, *new_peers; ngx_http_nacos_peers_t *peers, *new_peers;
ngx_http_nacos_srv_conf_t *nusf; ngx_http_nacos_srv_conf_t *nusf;
ngx_int_t rc; ngx_int_t rc;
ngx_conf_t cf;
peers = us->peer.data; peers = us->peer.data;
@ -377,7 +604,8 @@ static ngx_http_nacos_peers_t *ngx_http_get_nacos_peers(
return peers; return peers;
} }
new_peers = ngx_http_nacos_create_peers(r->pool->log); new_peers =
ngx_http_nacos_create_peers(r->pool->log, peers->use_cluster, us);
if (new_peers == NULL) { if (new_peers == NULL) {
return NULL; return NULL;
} }
@ -390,29 +618,12 @@ static ngx_http_nacos_peers_t *ngx_http_get_nacos_peers(
return NULL; return NULL;
} }
rc = ngx_http_nacos_create_new_us(new_peers, peers->us); nusf = ngx_http_conf_upstream_srv_conf(us, ngx_http_nacos_upstream_module);
if (rc != NGX_OK) { if (ngx_http_nacos_add_server(new_peers, nusf, r->pool) != NGX_OK) {
ngx_destroy_pool(new_peers->pool); ngx_destroy_pool(new_peers->pool);
return NULL; return NULL;
} }
if (ngx_http_nacos_add_server(new_peers) != NGX_OK) {
ngx_destroy_pool(new_peers->pool);
return NULL;
}
if (new_peers->addrs.addrs.nelts > 0) {
memset(&cf, 0, sizeof(cf));
cf.pool = new_peers->pool;
cf.temp_pool = r->pool;
cf.log = r->connection->log;
nusf =
ngx_http_conf_upstream_srv_conf(us, ngx_http_nacos_upstream_module);
if (nusf->original_init_upstream(&cf, new_peers->us) != NGX_OK) {
ngx_destroy_pool(new_peers->pool);
return NULL;
}
}
us->peer.data = new_peers; us->peer.data = new_peers;
if (--peers->ref == 0) { if (--peers->ref == 0) {
ngx_destroy_pool(peers->pool); ngx_destroy_pool(peers->pool);

View File

@ -68,6 +68,7 @@ typedef struct {
ngx_str_t host; ngx_str_t host;
int32_t port; int32_t port;
int32_t weight; int32_t weight;
ngx_str_t cluster;
} ngx_nacos_service_addr_t; } ngx_nacos_service_addr_t;
typedef struct { typedef struct {
uint64_t version; uint64_t version;

View File

@ -77,6 +77,7 @@ ngx_int_t ngx_nacos_write_disk_data(ngx_nacos_main_conf_t *mcf,
ssize_t rd; ssize_t rd;
ngx_fd_t fd; ngx_fd_t fd;
ngx_err_t err; ngx_err_t err;
ngx_flag_t dir_end;
char *c; char *c;
if (cache->adr == NULL) { if (cache->adr == NULL) {
@ -86,15 +87,24 @@ ngx_int_t ngx_nacos_write_disk_data(ngx_nacos_main_conf_t *mcf,
pool = cache->pool; pool = cache->pool;
filename.data = tmp; filename.data = tmp;
filename.len = ngx_snprintf(tmp, sizeof(tmp) - 1, "%V@@%V", &cache->group, filename.len = ngx_snprintf(tmp, sizeof(tmp) - 1, "-%V@@%V", &cache->group,
&cache->data_id) - &cache->data_id) -
tmp; tmp;
dir_end = 0;
if (mcf->cache_dir.data[mcf->cache_dir.len - 1] == '/') {
--filename.len;
++filename.data;
dir_end = 1;
}
if (ngx_get_full_name(pool, &mcf->cache_dir, &filename) != NGX_OK) { if (ngx_get_full_name(pool, &mcf->cache_dir, &filename) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
if (!dir_end) {
filename.data[mcf->cache_dir.len] = '/';
}
fd = ngx_open_file(filename.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, fd = ngx_open_file(filename.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE,
0666); NGX_FILE_DEFAULT_ACCESS);
if (fd == NGX_INVALID_FILE) { if (fd == NGX_INVALID_FILE) {
err = ngx_errno; err = ngx_errno;
ngx_log_error(NGX_LOG_EMERG, pool->log, err, ngx_log_error(NGX_LOG_EMERG, pool->log, err,
@ -420,6 +430,8 @@ static bool ngx_nacos_encode_hosts(pb_ostream_t *stream,
instance.host.funcs.encode = ngx_nacos_data_pb_encode_str; instance.host.funcs.encode = ngx_nacos_data_pb_encode_str;
instance.port = addr->port; instance.port = addr->port;
instance.weight = addr->weight; instance.weight = addr->weight;
instance.cluster.arg = &addr[i].cluster;
instance.cluster.funcs.encode = ngx_nacos_data_pb_encode_str;
if (!pb_encode_submessage(stream, Instance_fields, &instance)) { if (!pb_encode_submessage(stream, Instance_fields, &instance)) {
return false; return false;
} }
@ -428,11 +440,11 @@ static bool ngx_nacos_encode_hosts(pb_ostream_t *stream,
} }
char *ngx_nacos_parse_addrs_from_json(ngx_nacos_resp_json_parser_t *parser) { char *ngx_nacos_parse_addrs_from_json(ngx_nacos_resp_json_parser_t *parser) {
yajl_val json, arr, item, ip, port, ref, weight, enable, healthy; yajl_val json, arr, item, ip, port, ref, weight, enable, healthy, cluster;
size_t i, n; size_t i, n;
int is; int is;
ngx_log_t *log; ngx_log_t *log;
char *ts, *c; char *ts, *c, *cs;
Service service; Service service;
ngx_nacos_service_addrs_t addrs; ngx_nacos_service_addrs_t addrs;
ngx_nacos_service_addr_t *addr; ngx_nacos_service_addr_t *addr;
@ -481,9 +493,11 @@ char *ngx_nacos_parse_addrs_from_json(ngx_nacos_resp_json_parser_t *parser) {
} }
ip = yajl_tree_get_field(item, "ip", yajl_t_string); ip = yajl_tree_get_field(item, "ip", yajl_t_string);
if (!ip) { cluster = yajl_tree_get_field(item, "clusterName", yajl_t_string);
ngx_log_error(NGX_LOG_WARN, log, 0, if (!ip || !cluster) {
"nacos response json hosts ip is not string"); ngx_log_error(
NGX_LOG_WARN, log, 0,
"nacos response json hosts ip or cluster is not string");
return NULL; return NULL;
} }
port = yajl_tree_get_field(item, "port", yajl_t_number); port = yajl_tree_get_field(item, "port", yajl_t_number);
@ -493,6 +507,7 @@ char *ngx_nacos_parse_addrs_from_json(ngx_nacos_resp_json_parser_t *parser) {
return NULL; return NULL;
} }
ts = YAJL_GET_STRING(ip); ts = YAJL_GET_STRING(ip);
cs = YAJL_GET_STRING(cluster);
is = (int) YAJL_GET_INTEGER(port); is = (int) YAJL_GET_INTEGER(port);
weight = yajl_tree_get_field(item, "weight", yajl_t_number); weight = yajl_tree_get_field(item, "weight", yajl_t_number);
@ -514,6 +529,8 @@ char *ngx_nacos_parse_addrs_from_json(ngx_nacos_resp_json_parser_t *parser) {
} }
addr->host.data = (u_char *) ts; addr->host.data = (u_char *) ts;
addr->host.len = strlen(ts); addr->host.len = strlen(ts);
addr->cluster.data = (u_char *) cs;
addr->cluster.len = strlen(cs);
addr->port = is; addr->port = is;
addr->weight = (int32_t) w * 100; addr->weight = (int32_t) w * 100;
} }
@ -567,15 +584,20 @@ static bool ngx_nacos_pb_decode_str(pb_istream_t *stream,
static bool ngx_nacos_decode_instances(pb_istream_t *stream, static bool ngx_nacos_decode_instances(pb_istream_t *stream,
const pb_field_t *field, void **arg) { const pb_field_t *field, void **arg) {
struct ngx_pb_decode_ctx_t *ctx; struct ngx_pb_decode_ctx_t *parent;
ngx_array_t *addrs; ngx_array_t *addrs;
ngx_nacos_service_addr_t *addr; ngx_nacos_service_addr_t *addr;
Instance instance; Instance instance;
struct ngx_pb_decode_ctx_t host, cluster;
ctx = *arg; parent = *arg;
addrs = ctx->arg; addrs = parent->arg;
instance.host.arg = ctx; host.pool = parent->pool;
cluster.pool = parent->pool;
instance.host.arg = &host;
instance.host.funcs.decode = ngx_nacos_pb_decode_str; instance.host.funcs.decode = ngx_nacos_pb_decode_str;
instance.cluster.arg = &cluster;
instance.cluster.funcs.decode = ngx_nacos_pb_decode_str;
addr = ngx_array_push(addrs); addr = ngx_array_push(addrs);
if (addr == NULL) { if (addr == NULL) {
@ -583,13 +605,13 @@ static bool ngx_nacos_decode_instances(pb_istream_t *stream,
} }
instance.port = 0; instance.port = 0;
instance.weight = 0; instance.weight = 0;
ctx->arg = &addr->host; host.arg = &addr->host;
cluster.arg = &addr->cluster;
if (!pb_decode(stream, Instance_fields, &instance)) { if (!pb_decode(stream, Instance_fields, &instance)) {
return false; return false;
} }
addr->weight = instance.weight; addr->weight = instance.weight;
addr->port = instance.port; addr->port = instance.port;
ctx->arg = addrs;
return true; return true;
} }

View File

@ -182,6 +182,7 @@ struct ngx_nacos_grpc_stream_s {
unsigned long_live : 1; unsigned long_live : 1;
unsigned send_buf_block : 1; unsigned send_buf_block : 1;
unsigned send_buf_block_conn : 1; unsigned send_buf_block_conn : 1;
unsigned store_proto_size_buf : 1;
}; };
#define NGX_NACOS_GRPC_DEFAULT_GRPC_STATUS 10000 #define NGX_NACOS_GRPC_DEFAULT_GRPC_STATUS 10000
@ -216,16 +217,18 @@ static ngx_int_t ngx_nacos_grpc_send_buf(ngx_nacos_grpc_buf_t *buf,
static ngx_int_t ngx_nacos_grpc_do_send(ngx_nacos_grpc_stream_t *st); static ngx_int_t ngx_nacos_grpc_do_send(ngx_nacos_grpc_stream_t *st);
#define READ_BUF_CAP 65536 // read buf. 128K. max frame
#define READ_BUF_CAP (1 << 17)
#define MAX_FRAME_SIZE (READ_BUF_CAP - 9)
static u_char ngx_nacos_grpc_connection_start[] = static u_char ngx_nacos_grpc_connection_start[] =
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* connection preface */ "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* connection preface */
"\x00\x00\x12\x04\x00\x00\x00\x00\x00" /* settings frame */ "\x00\x00\x18\x04\x00\x00\x00\x00\x00" /* settings frame */
"\x00\x01\x00\x00\x00\x00" /* header table size */ "\x00\x01\x00\x00\x00\x00" /* header table size */
"\x00\x02\x00\x00\x00\x00" /* disable push */ "\x00\x02\x00\x00\x00\x00" /* disable push */
"\x00\x04\x7f\xff\xff\xff" /* initial window */ "\x00\x04\x7f\xff\xff\xff" /* initial window */
"\x00\x05\x00\x01\xff\xf7" /* max frame size 128K - 9 */
"\x00\x00\x04\x08\x00\x00\x00\x00\x00" /* window update frame */ "\x00\x00\x04\x08\x00\x00\x00\x00\x00" /* window update frame */
"\x7f\xff\x00\x00"; "\x7f\xff\x00\x00";
@ -544,8 +547,14 @@ static void ngx_nacos_grpc_event_handler(ngx_event_t *ev) {
gc = c->data; gc = c->data;
if (ev == c->read) { if (ev == c->read) {
rc = ngx_nacos_grpc_read_handler(gc, ev); rc = ngx_nacos_grpc_read_handler(gc, ev);
if (rc == NGX_AGAIN && ngx_handle_read_event(ev, 0) != NGX_OK) {
rc = NGX_ERROR;
}
} else { } else {
rc = ngx_nacos_grpc_write_handler(gc, ev); rc = ngx_nacos_grpc_write_handler(gc, ev);
if (rc == NGX_AGAIN && ngx_handle_write_event(ev, 0) != NGX_OK) {
rc = NGX_ERROR;
}
} }
if (rc == NGX_ERROR || rc == NGX_DONE) { if (rc == NGX_ERROR || rc == NGX_DONE) {
@ -654,7 +663,7 @@ static ngx_int_t ngx_nacos_grpc_read_handler(ngx_nacos_grpc_conn_t *gc,
} else if (rc == 0) { } else if (rc == 0) {
return NGX_DONE; return NGX_DONE;
} else if (rc == NGX_AGAIN) { } else if (rc == NGX_AGAIN) {
return NGX_OK; return NGX_AGAIN;
} }
} }
} }
@ -672,7 +681,7 @@ static ngx_int_t ngx_nacos_grpc_parse_frame(ngx_nacos_grpc_conn_t *gc) {
if (gc->parse_stat == parse_frame_header) { if (gc->parse_stat == parse_frame_header) {
if (len < 9) { if (len < 9) {
return NGX_AGAIN; break;
} }
gc->frame_size = gc->frame_size =
(((size_t) b->pos[0]) << 16) | (b->pos[1] << 8) | (b->pos[2]); (((size_t) b->pos[0]) << 16) | (b->pos[1] << 8) | (b->pos[2]);
@ -684,43 +693,55 @@ static ngx_int_t ngx_nacos_grpc_parse_frame(ngx_nacos_grpc_conn_t *gc) {
gc->parse_stat = parse_frame_payload; gc->parse_stat = parse_frame_payload;
b->pos += 9; b->pos += 9;
gc->frame_start = 1; gc->frame_start = 1;
gc->frame_end = len - 9 >= gc->frame_size ? 1 : 0; len -= 9;
if (gc->frame_type >
sizeof(frame_handlers) / sizeof(ngx_nacos_grpc_frame_handler)) {
ngx_log_error(NGX_LOG_ERR, gc->conn->log, 0,
"nacos http2 protocol error. error frame type");
return NGX_ERROR;
}
if (gc->frame_size > MAX_FRAME_SIZE) {
ngx_log_error(
NGX_LOG_ERR, gc->conn->log, 0,
"nacos http2 protocol error. exceed max frame size");
return NGX_ERROR;
}
} }
if (gc->parse_stat == parse_frame_payload) { if (gc->parse_stat == parse_frame_payload) {
if (gc->frame_type > gc->frame_end = len >= gc->frame_size ? 1 : 0;
sizeof(frame_handlers) / sizeof(ngx_nacos_grpc_frame_handler)) { if (!gc->frame_end) {
return NGX_ERROR; break;
} }
pp = b->pos;
lp = b->last; lp = b->last;
if ((size_t) (lp - pp) > gc->frame_size) { if ((size_t) (lp - b->pos) > gc->frame_size) {
b->last = pp + gc->frame_size; b->last = b->pos + gc->frame_size;
} }
pp = b->last;
rc = frame_handlers[gc->frame_type](gc); rc = frame_handlers[gc->frame_type](gc);
if (b->pos == b->last) { b->pos = pp;
gc->parse_stat = parse_frame_header;
} else if (b->pos != pp) {
gc->frame_start = 0;
}
b->last = lp; b->last = lp;
if (rc == NGX_ERROR || rc == NGX_DONE) {
if (rc != NGX_OK) {
return rc; return rc;
} else if (rc == NGX_AGAIN) { }
gc->parse_stat = parse_frame_header;
}
}
len = b->last - b->pos; len = b->last - b->pos;
if (len > 0 && len * 4 < (size_t) (b->end - b->start) && if (len == 0) {
(size_t) (b->end - b->pos) * 2 < b->pos = b->last = b->start;
(size_t) (b->end - b->start)) { } else if (len > 0 && len * 4 < (size_t) (b->end - b->start) &&
(size_t) (b->end - b->pos) * 2 < (size_t) (b->end - b->start)) {
ngx_memcpy(b->start, b->pos, len); ngx_memcpy(b->start, b->pos, len);
b->pos = b->start; b->pos = b->start;
b->last = b->pos + len; b->last = b->pos + len;
} else if (len == 0) {
b->pos = b->last = b->start;
}
return rc;
}
}
} }
return NGX_AGAIN;
} }
static ngx_nacos_grpc_stream_t *ngx_nacos_grpc_create_stream( static ngx_nacos_grpc_stream_t *ngx_nacos_grpc_create_stream(
@ -977,7 +998,7 @@ static ngx_int_t ngx_nacos_grpc_parse_unknown_frame(ngx_nacos_grpc_conn_t *gc) {
static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) { static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) {
ngx_nacos_grpc_stream_t *st; ngx_nacos_grpc_stream_t *st;
ngx_buf_t *buf, *tb; ngx_buf_t *buf, *tb;
u_char *p; u_char *p, *t;
ngx_int_t rc; ngx_int_t rc;
size_t len, msg_size; size_t len, msg_size;
ngx_str_t proto_msg; ngx_str_t proto_msg;
@ -1008,6 +1029,11 @@ static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) {
p = buf->pos; p = buf->pos;
len = buf->last - p; len = buf->last - p;
if (len == 0) {
rc = NGX_OK;
break;
}
if (gc->frame_start) { if (gc->frame_start) {
if (gc->frame_flags & HTTP_V2_PADDED_FLAG) { if (gc->frame_flags & HTTP_V2_PADDED_FLAG) {
if (len < 1) { if (len < 1) {
@ -1023,11 +1049,48 @@ static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) {
} }
if (st->parsing_state == parsing_prefix) { if (st->parsing_state == parsing_prefix) {
if (len < 5) { if (st->store_proto_size_buf) {
tb = st->tmp_buf;
if (len > 5 - (size_t) (tb->last - tb->pos)) {
msg_size = 5 - (tb->last - tb->pos);
} else {
msg_size = len;
}
memcpy(tb->last, p, msg_size);
tb->last += msg_size;
p += msg_size;
buf->pos = p;
if (tb->last - tb->pos < 5) {
rc = NGX_OK; rc = NGX_OK;
break; break;
} }
if (p[0] != 0) { } else if (len < 5) {
if (ngx_nacos_grpc_realloc_tmp_buf(st, 256) != NGX_OK) {
rc = NGX_ERROR;
break;
}
tb = st->tmp_buf;
memcpy(tb->last, p, len);
tb->last += len;
p += len;
buf->pos = p;
rc = NGX_OK;
st->store_proto_size_buf = 1;
break;
}
if (st->store_proto_size_buf) {
t = tb->pos;
tb->pos = tb->last = tb->start;
} else {
t = p;
p += 5;
len -= 5;
buf->pos = p;
}
if (t[0] != 0) {
ngx_log_error(NGX_LOG_ERR, gc->conn->log, 0, ngx_log_error(NGX_LOG_ERR, gc->conn->log, 0,
"nacos server sent data frame " "nacos server sent data frame "
"send compressed msg: %uz", "send compressed msg: %uz",
@ -1035,15 +1098,13 @@ static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) {
rc = NGX_ERROR; rc = NGX_ERROR;
break; break;
} }
msg_size = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]; msg_size = (t[1] << 24) | (t[2] << 16) | (t[3] << 8) | t[4];
if (ngx_nacos_grpc_realloc_tmp_buf(st, msg_size) != NGX_OK) { if (ngx_nacos_grpc_realloc_tmp_buf(st, msg_size) != NGX_OK) {
rc = NGX_ERROR; rc = NGX_ERROR;
break; break;
} }
tb = st->tmp_buf; tb = st->tmp_buf;
p += 5;
len -= 5;
buf->pos = p;
st->parsing_state = parsing_msg; st->parsing_state = parsing_msg;
st->proto_len = msg_size; st->proto_len = msg_size;
st->recv_win -= 5; st->recv_win -= 5;
@ -1063,6 +1124,9 @@ static ngx_int_t ngx_nacos_grpc_parse_data_frame(ngx_nacos_grpc_conn_t *gc) {
st->padding = 0; st->padding = 0;
} }
len = tb->last - tb->pos; len = tb->last - tb->pos;
if (st->proto_len > 300000) {
st->padding = 0;
}
if (len == st->proto_len) { if (len == st->proto_len) {
proto_msg.len = len; proto_msg.len = len;
proto_msg.data = tb->pos; proto_msg.data = tb->pos;
@ -1223,8 +1287,7 @@ static ngx_int_t ngx_nacos_grpc_parse_header_frame(ngx_nacos_grpc_conn_t *gc) {
b->pos = p; b->pos = p;
len = b->last - p; len = b->last - p;
gc->frame_size -= min; gc->frame_size -= min;
gc->frame_flags &= gc->frame_flags &= ~(HTTP_V2_PADDED_FLAG | HTTP_V2_PRIORITY_FLAG);
~(HTTP_V2_PADDED_FLAG | HTTP_V2_PRIORITY_FLAG);
st->parsing_state = p_receiving; st->parsing_state = p_receiving;
} }
} }
@ -1372,7 +1435,8 @@ parse_header:
ch = 0; ch = 0;
tp = tmp; tp = tmp;
if (ngx_nacos_http_v2_huff_decode(&ch, p, field_len, &tp, 1, if (ngx_nacos_http_v2_huff_decode(&ch, p, field_len, &tp, 1,
gc->conn->log) != NGX_OK) { gc->conn->log) !=
NGX_OK) {
ngx_log_error( ngx_log_error(
NGX_LOG_ERR, gc->conn->log, 0, NGX_LOG_ERR, gc->conn->log, 0,
"nacos server sent invalid encoded header"); "nacos server sent invalid encoded header");
@ -1421,7 +1485,8 @@ parse_header:
ch = 0; ch = 0;
tp = tmp; tp = tmp;
if (ngx_nacos_http_v2_huff_decode(&ch, p, field_len, &tp, 1, if (ngx_nacos_http_v2_huff_decode(&ch, p, field_len, &tp, 1,
gc->conn->log) != NGX_OK) { gc->conn->log) !=
NGX_OK) {
ngx_log_error( ngx_log_error(
NGX_LOG_ERR, gc->conn->log, 0, NGX_LOG_ERR, gc->conn->log, 0,
"nacos server sent invalid encoded header"); "nacos server sent invalid encoded header");
@ -1634,8 +1699,8 @@ static ngx_int_t ngx_nacos_grpc_parse_ping_frame(ngx_nacos_grpc_conn_t *gc) {
if (buf == NULL) { if (buf == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_nacos_grpc_encode_frame_header( ngx_nacos_grpc_encode_frame_header(gc->m_stream, buf->b, HTTP_V2_PING_FRAME,
gc->m_stream, buf->b, HTTP_V2_PING_FRAME, HTTP_V2_ACK_FLAG, 8); HTTP_V2_ACK_FLAG, 8);
buf->len = 9 + 8; buf->len = 9 + 8;
p = buf->b + 9; p = buf->b + 9;
p[0] = (data >> 56) & 0xFF; p[0] = (data >> 56) & 0xFF;
@ -1849,7 +1914,8 @@ static ngx_nacos_grpc_buf_t *ngx_nacos_grpc_encode_request(
// user-agent // user-agent
*b++ = ngx_nacos_http_v2_inc_indexed(HTTP_V2_USER_AGENT_INDEX); *b++ = ngx_nacos_http_v2_inc_indexed(HTTP_V2_USER_AGENT_INDEX);
b = ngx_nacos_http_v2_write_value(b, (u_char *) "nginx-nacos-grpc-client", b = ngx_nacos_http_v2_write_value(b, (u_char *) "nginx-nacos-grpc-client",
sizeof("nginx-nacos-grpc-client") - 1, tmp); sizeof("nginx-nacos-grpc-client") - 1,
tmp);
// content-type // content-type
*b++ = ngx_nacos_http_v2_inc_indexed(HTTP_V2_CONTENT_TYPE_INDEX); *b++ = ngx_nacos_http_v2_inc_indexed(HTTP_V2_CONTENT_TYPE_INDEX);
b = ngx_nacos_http_v2_write_value(b, (u_char *) "application/grpc", b = ngx_nacos_http_v2_write_value(b, (u_char *) "application/grpc",
@ -2241,6 +2307,8 @@ static ngx_int_t ngx_nacos_grpc_encode_payload_init(
en->payload.body.value.funcs.encode = ngx_nacos_grpc_pb_encode_str; en->payload.body.value.funcs.encode = ngx_nacos_grpc_pb_encode_str;
en->payload.metadata.type.arg = &en->type; en->payload.metadata.type.arg = &en->type;
en->payload.metadata.type.funcs.encode = ngx_nacos_grpc_pb_encode_str; en->payload.metadata.type.funcs.encode = ngx_nacos_grpc_pb_encode_str;
en->payload.has_metadata = 1;
en->payload.has_body = 1;
if (grpc_ctx.ncf->username.len > 0 && grpc_ctx.ncf->password.len > 0) { if (grpc_ctx.ncf->username.len > 0 && grpc_ctx.ncf->password.len > 0) {
en->payload.metadata.headers.arg = grpc_ctx.ncf; en->payload.metadata.headers.arg = grpc_ctx.ncf;
@ -2292,9 +2360,9 @@ static ngx_nacos_grpc_buf_t *ngx_nacos_grpc_encode_data_msg(
goto err; goto err;
} }
b = buf->b; b = buf->b;
ngx_nacos_grpc_encode_frame_header( ngx_nacos_grpc_encode_frame_header(st, b, HTTP_V2_DATA_FRAME,
st, b, HTTP_V2_DATA_FRAME, end_stream ? HTTP_V2_END_STREAM_FLAG : 0,
end_stream ? HTTP_V2_END_STREAM_FLAG : 0, 5 + b_len); 5 + b_len);
b[9] = 0; b[9] = 0;
b[10] = (b_len >> 24) & 0xFF; b[10] = (b_len >> 24) & 0xFF;
b[11] = (b_len >> 16) & 0xFF; b[11] = (b_len >> 16) & 0xFF;
@ -2468,8 +2536,8 @@ static ngx_int_t ngx_nacos_grpc_send_win_update_frame(
if (buf == NULL) { if (buf == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_nacos_grpc_encode_frame_header(st, buf->b, ngx_nacos_grpc_encode_frame_header(st, buf->b, HTTP_V2_WINDOW_UPDATE_FRAME,
HTTP_V2_WINDOW_UPDATE_FRAME, 0, 4); 0, 4);
buf->len = 9 + 4; buf->len = 9 + 4;
p = buf->b + 9; p = buf->b + 9;
p[0] = (win_update >> 24) & 0x7F; p[0] = (win_update >> 24) & 0x7F;
@ -2492,8 +2560,8 @@ static ngx_int_t ngx_nacos_send_ping_frame(ngx_nacos_grpc_conn_t *gc) {
if (buf == NULL) { if (buf == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_nacos_grpc_encode_frame_header(gc->m_stream, buf->b, ngx_nacos_grpc_encode_frame_header(gc->m_stream, buf->b, HTTP_V2_PING_FRAME,
HTTP_V2_PING_FRAME, 0, 8); 0, 8);
p = buf->b + 9; p = buf->b + 9;
data = ++gc->heartbeat; data = ++gc->heartbeat;
p[0] = (data >> 56) & 0xFF; p[0] = (data >> 56) & 0xFF;

View File

@ -500,10 +500,6 @@ static ngx_int_t ngx_nacos_subscribe(ngx_conf_t *cf, ngx_nacos_sub_t *sub,
return NGX_ERROR; return NGX_ERROR;
} }
} }
if (ngx_nacos_write_disk_data(mcf, &tmp) == NGX_ERROR) {
return NGX_ERROR;
}
} }
kptr = ngx_array_push(all_keys); kptr = ngx_array_push(all_keys);

View File

@ -14,16 +14,14 @@
/* #define PB_ENABLE_MALLOC 1 */ /* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU / compiler combination does not support /* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. */ * unaligned memory access to packed structures. Note that packed
* structures are only used when requested in .proto options. */
/* #define PB_NO_PACKED_STRUCTS 1 */ /* #define PB_NO_PACKED_STRUCTS 1 */
/* Increase the number of required fields that are tracked. /* Increase the number of required fields that are tracked.
* A compiler warning will tell if you need this. */ * A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */ /* #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. */ /* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
/* #define PB_FIELD_32BIT 1 */ /* #define PB_FIELD_32BIT 1 */
@ -33,16 +31,32 @@
/* Disable support for custom streams (support only memory buffers). */ /* Disable support for custom streams (support only memory buffers). */
/* #define PB_BUFFER_ONLY 1 */ /* #define PB_BUFFER_ONLY 1 */
/* Switch back to the old-style callback function signature. /* Disable support for 64-bit datatypes, for compilers without int64_t
* This was the default until nanopb-0.2.1. */ or to save some code space. */
/* #define PB_OLD_CALLBACK_STYLE */ /* #define PB_WITHOUT_64BIT 1 */
/* Don't encode scalar arrays as packed. This is only to be used when /* Don't encode scalar arrays as packed. This is only to be used when
* the decoder on the receiving side cannot process packed scalar arrays. * the decoder on the receiving side cannot process packed scalar arrays.
* Such example is older protobuf.js. */ * Such example is older protobuf.js. */
/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ /* #define PB_ENCODE_ARRAYS_UNPACKED 1 */
/* Enable conversion of doubles to floats for platforms that do not
* support 64-bit doubles. Most commonly AVR. */
/* #define PB_CONVERT_DOUBLE_FLOAT 1 */
/* Check whether incoming strings are valid UTF-8 sequences. Slows down
* the string processing slightly and slightly increases code size. */
/* #define PB_VALIDATE_UTF8 1 */
/* This can be defined if the platform is little-endian and has 8-bit bytes.
* Normally it is automatically detected based on __BYTE_ORDER__ macro. */
/* #define PB_LITTLE_ENDIAN_8BIT 1 */
/* Configure static assert mechanism. Instead of changing these, set your
* compiler to C11 standard mode if possible. */
/* #define PB_C99_STATIC_ASSERT 1 */
/* #define PB_NO_STATIC_ASSERT 1 */
/****************************************************************** /******************************************************************
* You usually don't need to change anything below this line. * * You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. * * Feel free to look around and use the defined macros, though. *
@ -51,7 +65,7 @@
/* Version of the nanopb library. Just in case you want to check it in /* Version of the nanopb library. Just in case you want to check it in
* your own program. */ * your own program. */
#define NANOPB_VERSION nanopb-0.3.9.10 #define NANOPB_VERSION "nanopb-0.4.9"
/* Include all the system headers needed by nanopb. You will need the /* Include all the system headers needed by nanopb. You will need the
* definitions of the following: * definitions of the following:
@ -72,12 +86,17 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <ngx_auto_headers.h> #include <ngx_auto_headers.h>
#include <limits.h>
#ifdef PB_ENABLE_MALLOC #ifdef PB_ENABLE_MALLOC
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
/* Macro for defining packed structures (compiler dependent). /* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required. * This just reduces memory requirements, but is not required.
*/ */
@ -108,11 +127,36 @@
# define pb_packed # define pb_packed
#endif #endif
/* Detect endianness */
#ifndef PB_LITTLE_ENDIAN_8BIT
#if ((defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)) \
&& CHAR_BIT == 8
#define PB_LITTLE_ENDIAN_8BIT 1
#endif
#endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ /* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef PB_UNUSED #ifndef PB_UNUSED
#define PB_UNUSED(x) (void)(x) #define PB_UNUSED(x) (void)(x)
#endif #endif
/* Harvard-architecture processors may need special attributes for storing
* field information in program memory. */
#ifndef PB_PROGMEM
#ifdef __AVR__
#include <avr/pgmspace.h>
#define PB_PROGMEM PROGMEM
#define PB_PROGMEM_READU32(x) pgm_read_dword(&x)
#else
#define PB_PROGMEM
#define PB_PROGMEM_READU32(x) (x)
#endif
#endif
/* Compile-time assertion, used for checking compatible compilation options. /* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use * If this does not work properly on your compiler, use
* #define PB_NO_STATIC_ASSERT to disable it. * #define PB_NO_STATIC_ASSERT to disable it.
@ -124,14 +168,38 @@
*/ */
#ifndef PB_NO_STATIC_ASSERT #ifndef PB_NO_STATIC_ASSERT
# ifndef PB_STATIC_ASSERT # ifndef PB_STATIC_ASSERT
# if defined(__ICCARM__)
/* IAR has static_assert keyword but no _Static_assert */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# elif defined(_MSC_VER) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112)
/* MSVC in C89 mode supports static_assert() keyword anyway */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# elif defined(PB_C99_STATIC_ASSERT)
/* Classic negative-size-array static assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; # 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_ASSERT_MSG_(MSG, LINE, COUNTER)
#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER # define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
# elif defined(__cplusplus)
/* C++11 standard static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# else
/* C11 standard _Static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
# endif
# endif # endif
#else #else
/* Static asserts disabled by PB_NO_STATIC_ASSERT */
# define PB_STATIC_ASSERT(COND,MSG) # define PB_STATIC_ASSERT(COND,MSG)
#endif #endif
/* Test that PB_STATIC_ASSERT works
* If you get errors here, you may need to do one of these:
* - Enable C11 standard support in your compiler
* - Define PB_C99_STATIC_ASSERT to enable C99 standard support
* - Define PB_NO_STATIC_ASSERT to disable static asserts altogether
*/
PB_STATIC_ASSERT(1, STATIC_ASSERT_IS_NOT_WORKING)
/* Number of required fields to keep track of. */ /* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS #ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64 #define PB_MAX_REQUIRED_FIELDS 64
@ -141,70 +209,97 @@
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). #error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
#endif #endif
#ifdef PB_WITHOUT_64BIT
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Cannot use doubles without 64-bit types */
#undef PB_CONVERT_DOUBLE_FLOAT
#endif
#endif
/* Data type for storing encoded data and other byte streams.
* This typedef exists to support platforms where uint8_t does not exist.
* You can regard it as equivalent on uint8_t on other platforms.
*/
#if defined(PB_BYTE_T_OVERRIDE)
typedef PB_BYTE_T_OVERRIDE pb_byte_t;
#elif defined(UINT8_MAX)
typedef uint8_t pb_byte_t;
#else
typedef uint_least8_t pb_byte_t;
#endif
/* List of possible field types. These are used in the autogenerated code. /* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type * Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc. * Most-significant 4 bits specify repeated/required/packed etc.
*/ */
typedef pb_byte_t pb_type_t;
typedef uint_least8_t pb_type_t;
/**** Field data types ****/ /**** Field data types ****/
/* Numeric types */ /* Numeric types */
#define PB_LTYPE_BOOL 0x00 /* bool */ #define PB_LTYPE_BOOL 0x00U /* bool */
#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ #define PB_LTYPE_VARINT 0x01U /* int32, int64, enum, bool */
#define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ #define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */
#define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ #define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */
#define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ #define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED64 0x05 /* fixed64, sfixed64, double */ #define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */
/* Marker for last packable field type. */ /* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x05 #define PB_LTYPE_LAST_PACKABLE 0x05U
/* Byte array with pre-allocated buffer. /* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */ * data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x06 #define PB_LTYPE_BYTES 0x06U
/* String with pre-allocated buffer. /* String with pre-allocated buffer.
* data_size is the maximum length. */ * data_size is the maximum length. */
#define PB_LTYPE_STRING 0x07 #define PB_LTYPE_STRING 0x07U
/* Submessage /* Submessage
* submsg_fields is pointer to field descriptions */ * submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x08 #define PB_LTYPE_SUBMESSAGE 0x08U
/* Submessage with pre-decoding callback
* The pre-decoding callback is stored as pb_callback_t right before pSize.
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMSG_W_CB 0x09U
/* Extension pseudo-field /* Extension pseudo-field
* The field contains a pointer to pb_extension_t */ * The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x09 #define PB_LTYPE_EXTENSION 0x0AU
/* Byte array with inline, pre-allocated byffer. /* Byte array with inline, pre-allocated byffer.
* data_size is the length of the inline, allocated buffer. * data_size is the length of the inline, allocated buffer.
* This differs from PB_LTYPE_BYTES by defining the element as * This differs from PB_LTYPE_BYTES by defining the element as
* pb_byte_t[data_size] rather than pb_bytes_array_t. */ * pb_byte_t[data_size] rather than pb_bytes_array_t. */
#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0A #define PB_LTYPE_FIXED_LENGTH_BYTES 0x0BU
/* Number of declared LTYPES */ /* Number of declared LTYPES */
#define PB_LTYPES_COUNT 0x0B #define PB_LTYPES_COUNT 0x0CU
#define PB_LTYPE_MASK 0x0F #define PB_LTYPE_MASK 0x0FU
/**** Field repetition rules ****/ /**** Field repetition rules ****/
#define PB_HTYPE_REQUIRED 0x00 #define PB_HTYPE_REQUIRED 0x00U
#define PB_HTYPE_OPTIONAL 0x10 #define PB_HTYPE_OPTIONAL 0x10U
#define PB_HTYPE_REPEATED 0x20 #define PB_HTYPE_SINGULAR 0x10U
#define PB_HTYPE_ONEOF 0x30 #define PB_HTYPE_REPEATED 0x20U
#define PB_HTYPE_MASK 0x30 #define PB_HTYPE_FIXARRAY 0x20U
#define PB_HTYPE_ONEOF 0x30U
#define PB_HTYPE_MASK 0x30U
/**** Field allocation types ****/ /**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00 #define PB_ATYPE_STATIC 0x00U
#define PB_ATYPE_POINTER 0x80 #define PB_ATYPE_POINTER 0x80U
#define PB_ATYPE_CALLBACK 0x40 #define PB_ATYPE_CALLBACK 0x40U
#define PB_ATYPE_MASK 0xC0 #define PB_ATYPE_MASK 0xC0U
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) #define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) #define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) #define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \
PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB)
/* Data type used for storing sizes of struct fields /* Data type used for storing sizes of struct fields
* and array counts. * and array counts.
@ -212,45 +307,57 @@ typedef uint_least8_t pb_type_t;
#if defined(PB_FIELD_32BIT) #if defined(PB_FIELD_32BIT)
typedef uint32_t pb_size_t; typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t; typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT) #else
typedef uint_least16_t pb_size_t; typedef uint_least16_t pb_size_t;
typedef int_least16_t pb_ssize_t; typedef int_least16_t pb_ssize_t;
#else
typedef uint_least8_t pb_size_t;
typedef int_least8_t pb_ssize_t;
#endif #endif
#define PB_SIZE_MAX ((pb_size_t)-1) #define PB_SIZE_MAX ((pb_size_t)-1)
/* Data type for storing encoded data and other byte streams. /* Forward declaration of struct types */
* This typedef exists to support platforms where uint8_t does not exist. typedef struct pb_istream_s pb_istream_t;
* You can regard it as equivalent on uint8_t on other platforms. typedef struct pb_ostream_s pb_ostream_t;
*/ typedef struct pb_field_iter_s pb_field_iter_t;
typedef uint_least8_t pb_byte_t;
/* This structure is used in auto-generated constants /* This structure is used in auto-generated constants
* to specify struct fields. * 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_msgdesc_s pb_msgdesc_t;
typedef struct pb_field_s pb_field_t; struct pb_msgdesc_s {
struct pb_field_s { const uint32_t *field_info;
pb_size_t tag; const pb_msgdesc_t * const * submsg_info;
pb_type_t type; const pb_byte_t *default_value;
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 bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
* OR default value for all other non-array, non-callback types
* If null, then field will zeroed. */ pb_size_t field_count;
const void *ptr; pb_size_t required_field_count;
} pb_packed; pb_size_t largest_tag;
PB_PACKED_STRUCT_END };
/* Iterator for message descriptor */
struct pb_field_iter_s {
const pb_msgdesc_t *descriptor; /* Pointer to message descriptor constant */
void *message; /* Pointer to start of the structure */
pb_size_t index; /* Index of the field */
pb_size_t field_info_index; /* Index to descriptor->field_info array */
pb_size_t required_field_index; /* Index that counts only the required fields */
pb_size_t submessage_index; /* Index that counts only submessages */
pb_size_t tag; /* Tag of current field */
pb_size_t data_size; /* sizeof() of a single item */
pb_size_t array_size; /* Number of array entries */
pb_type_t type; /* Type of current field */
void *pField; /* Pointer to current field in struct */
void *pData; /* Pointer to current data contents. Different than pField for arrays and pointers. */
void *pSize; /* Pointer to count/has field */
const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */
};
/* For compatibility with legacy code */
typedef pb_field_iter_t pb_field_t;
/* Make sure that the standard integer types are of the expected sizes. /* Make sure that the standard integer types are of the expected sizes.
* Otherwise fixed32/fixed64 fields can break. * Otherwise fixed32/fixed64 fields can break.
@ -294,34 +401,29 @@ typedef struct pb_bytes_array_s pb_bytes_array_t;
* *
* The callback can be null if you want to skip a field. * 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; typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s { struct pb_callback_s {
#ifdef PB_OLD_CALLBACK_STYLE /* Callback functions receive a pointer to the arg field.
/* Deprecated since nanopb-0.2.1 */ * You can access the value of the field as *arg, and modify it if needed.
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 { union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); 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); bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
} funcs; } funcs;
#endif
/* Free arg for use by callback */ /* Free arg for use by callback */
void *arg; void *arg;
}; };
extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
/* Wire types. Library user needs these only in encoder callbacks. */ /* Wire types. Library user needs these only in encoder callbacks. */
typedef enum { typedef enum {
PB_WT_VARINT = 0, PB_WT_VARINT = 0,
PB_WT_64BIT = 1, PB_WT_64BIT = 1,
PB_WT_STRING = 2, PB_WT_STRING = 2,
PB_WT_32BIT = 5 PB_WT_32BIT = 5,
PB_WT_PACKED = 255 /* PB_WT_PACKED is internal marker for packed arrays. */
} pb_wire_type_t; } pb_wire_type_t;
/* Structure for defining the handling of unknown/extension fields. /* Structure for defining the handling of unknown/extension fields.
@ -373,6 +475,8 @@ struct pb_extension_s {
bool found; bool found;
}; };
#define pb_extension_init_zero {NULL,NULL,NULL,false}
/* Memory allocation functions to use. You can define pb_realloc and /* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */ * pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC #ifdef PB_ENABLE_MALLOC
@ -385,7 +489,7 @@ struct pb_extension_s {
#endif #endif
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ /* This is used to inform about need to regenerate .pb.h/.pb.c files. */
#define PB_PROTO_HEADER_VERSION 30 #define PB_PROTO_HEADER_VERSION 40
/* These macros are used to declare pb_field_t's in the constant array. */ /* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */ /* Size of a structure member, in bytes. */
@ -394,103 +498,356 @@ struct pb_extension_s {
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) #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. */ /* 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)) #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 */ /* Force expansion of macro value */
/* data_offset for first field in a message */ #define PB_EXPAND(x) x
#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))
/* data offset for subsequent fields inside an union (oneof) */
#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX)
/* 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 /* Binding of a message field set into a specific structure */
* previous field end, and the size of the field. Pointer is used for #define PB_BIND(msgname, structname, width) \
* submessages and default values. const uint32_t structname ## _field_info[] PB_PROGMEM = \
{ \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
0 \
}; \
const pb_msgdesc_t* const structname ## _submsg_info[] = \
{ \
msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
NULL \
}; \
const pb_msgdesc_t structname ## _msg = \
{ \
structname ## _field_info, \
structname ## _submsg_info, \
msgname ## _DEFAULT, \
msgname ## _CALLBACK, \
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
}; \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
+ (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
* 0 + tag
/* X-macro for generating the entries in struct_field_info[] array. */
#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
/* X-macro for generating asserts that entries fit in struct_field_info[] array.
* The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
* but it is not easily reused because of how macro substitutions work. */
#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername
#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname)
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SI_PB_LTYPE_BOOL(t)
#define PB_SI_PB_LTYPE_BYTES(t)
#define PB_SI_PB_LTYPE_DOUBLE(t)
#define PB_SI_PB_LTYPE_ENUM(t)
#define PB_SI_PB_LTYPE_UENUM(t)
#define PB_SI_PB_LTYPE_FIXED32(t)
#define PB_SI_PB_LTYPE_FIXED64(t)
#define PB_SI_PB_LTYPE_FLOAT(t)
#define PB_SI_PB_LTYPE_INT32(t)
#define PB_SI_PB_LTYPE_INT64(t)
#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_SFIXED32(t)
#define PB_SI_PB_LTYPE_SFIXED64(t)
#define PB_SI_PB_LTYPE_SINT32(t)
#define PB_SI_PB_LTYPE_SINT64(t)
#define PB_SI_PB_LTYPE_STRING(t)
#define PB_SI_PB_LTYPE_UINT32(t)
#define PB_SI_PB_LTYPE_UINT64(t)
#define PB_SI_PB_LTYPE_EXTENSION(t)
#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg),
/* The field descriptors use a variable width format, with width of either
* 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
* encode the descriptor size, 6 lowest bits of field tag number, and 8 bits
* of the field type.
*
* Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words.
*
* Formats, listed starting with the least significant bit of the first word.
* 1 word: [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size]
*
* 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset]
* [16-bit data_offset] [12-bit data_size] [4-bit tag>>6]
*
* 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size]
* [8-bit size_offset] [24-bit tag>>6]
* [32-bit data_offset]
* [32-bit data_size]
*
* 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved]
* [8-bit size_offset] [24-bit tag>>6]
* [32-bit data_offset]
* [32-bit data_size]
* [32-bit array_size]
* [32-bit reserved]
* [32-bit reserved]
* [32-bit reserved]
*/ */
#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_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \
#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ (0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ (((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)),
fd, \
pb_delta(st, has_ ## m, m), \
pb_membersize(st, m), 0, ptr}
#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ #define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ (1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \
fd, 0, pb_membersize(st, m), 0, ptr} (((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x3c0) << 22)),
/* Repeated fields have a _count field and also the maximum number of entries. */ #define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \
#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ (2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
fd, \ (data_offset), (data_size),
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_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ (3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
fd, 0, pb_membersize(st, m[0]), 0, ptr} (data_offset), (data_size), (array_size), 0, 0, 0,
/* Optional fields don't need a has_ variable, as information would be redundant */ /* These assertions verify that the field information fits in the allocated space.
#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ * The generator tries to automatically determine the correct width that can fit all
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ * data associated with a message. These asserts will fail only if there has been a
fd, 0, pb_membersize(st, m[0]), 0, ptr} * problem in the automatic logic - this may be worth reporting as a bug. As a workaround,
* you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting
/* Same as optional fields*/ * descriptorsize option in .options file.
#define PB_SINGULAR_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_SINGULAR_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.
* Furthermore, the combination of OPTIONAL without has_ field is used
* for indicating proto3 style fields. Extensions exist in proto2 mode only,
* so they should be encoded according to proto2 rules. To avoid the conflict,
* extensions are marked as REQUIRED instead.
*/ */
#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ #define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<<bits))
{tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ #define PB_FIELDINFO_ASSERT_1(tag, type, data_offset, data_size, size_offset, array_size) \
0, \ PB_STATIC_ASSERT(PB_FITS(tag,6) && PB_FITS(data_offset,8) && PB_FITS(size_offset,4) && PB_FITS(data_size,4) && PB_FITS(array_size,1), FIELDINFO_DOES_NOT_FIT_width1_field ## tag)
0, \
pb_membersize(st, m), 0, ptr}
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ #define PB_FIELDINFO_ASSERT_2(tag, type, data_offset, data_size, size_offset, array_size) \
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) PB_STATIC_ASSERT(PB_FITS(tag,10) && PB_FITS(data_offset,16) && PB_FITS(size_offset,4) && PB_FITS(data_size,12) && PB_FITS(array_size,12), FIELDINFO_DOES_NOT_FIT_width2_field ## tag)
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ #ifndef PB_FIELD_32BIT
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) /* Maximum field sizes are still 16-bit if pb_size_t is 16-bit */
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
#else
/* Up to 32-bit fields supported.
* Note that the checks are against 31 bits to avoid compiler warnings about shift wider than type in the test.
* I expect that there is no reasonable use for >2GB messages with nanopb anyway.
*/
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
#endif
/* Automatic picking of FIELDINFO width:
* Uses width 1 when possible, otherwise resorts to width 2.
* This is used when PB_BIND() is called with "AUTO" as the argument.
* The generator will give explicit size argument when it knows that a message
* structure grows beyond 1-word format limits.
*/
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
#define PB_FI_WIDTH_PB_LTYPE_BOOL 1
#define PB_FI_WIDTH_PB_LTYPE_BYTES 2
#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1
#define PB_FI_WIDTH_PB_LTYPE_ENUM 1
#define PB_FI_WIDTH_PB_LTYPE_UENUM 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1
#define PB_FI_WIDTH_PB_LTYPE_INT32 1
#define PB_FI_WIDTH_PB_LTYPE_INT64 1
#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2
#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2
#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_SINT32 1
#define PB_FI_WIDTH_PB_LTYPE_SINT64 1
#define PB_FI_WIDTH_PB_LTYPE_STRING 2
#define PB_FI_WIDTH_PB_LTYPE_UINT32 1
#define PB_FI_WIDTH_PB_LTYPE_UINT64 1
#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
/* The mapping from protobuf types to LTYPEs is done using these macros. */ /* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL #define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL
@ -504,6 +861,7 @@ struct pb_extension_s {
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT #define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT #define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE #define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
#define PB_LTYPE_MAP_MSG_W_CB PB_LTYPE_SUBMSG_W_CB
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 #define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 #define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT #define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
@ -514,67 +872,6 @@ struct pb_extension_s {
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION #define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES #define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
/* 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, CALLBACK or POINTER
* - 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 repeated static fixed count fields.*/
#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
0, \
pb_membersize(message, field[0]), \
pb_arraysize(message, field), 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_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, m), \
pb_membersize(st, m), 0, ptr}
#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, m), \
pb_membersize(st, m[0]), 0, ptr}
#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* These macros are used for giving out error messages. /* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information * They are mostly a debugging aid; the main error information
* is the true/false return value from functions. * is the true/false return value from functions.
@ -597,4 +894,30 @@ struct pb_extension_s {
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false #define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
#ifdef __cplusplus
} /* extern "C" */
#endif
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define PB_CONSTEXPR constexpr
#else // __cplusplus >= 201103L
#define PB_CONSTEXPR
#endif // __cplusplus >= 201103L
#if __cplusplus >= 201703L
#define PB_INLINE_CONSTEXPR inline constexpr
#else // __cplusplus >= 201703L
#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
#endif // __cplusplus >= 201703L
extern "C++"
{
namespace nanopb {
// Each type will be partially specialized by the generator.
template <typename GenMessageT> struct MessageDescriptor;
} // namespace nanopb
}
#endif /* __cplusplus */
#endif #endif

View File

@ -5,102 +5,384 @@
#include "pb_common.h" #include "pb_common.h"
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) static bool load_descriptor_values(pb_field_iter_t *iter)
{ {
iter->start = fields; uint32_t word0;
iter->pos = fields; uint32_t data_offset;
iter->required_field_index = 0; int_least8_t size_offset;
iter->dest_struct = dest_struct;
if (!dest_struct) if (iter->index >= iter->descriptor->field_count)
return false;
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
switch(word0 & 3)
{ {
iter->pData = NULL; case 0: {
/* 1-word format */
iter->array_size = 1;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
break;
}
case 1: {
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
break;
}
case 2: {
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
default: {
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
}
if (!iter->message)
{
/* Avoid doing arithmetic on null pointers, it is undefined */
iter->pField = NULL;
iter->pSize = NULL; iter->pSize = NULL;
} }
else else
{ {
iter->pData = (char*)dest_struct + iter->pos->data_offset; iter->pField = (char*)iter->message + data_offset;
iter->pSize = (char*)iter->pData + iter->pos->size_offset;
if (size_offset)
{
iter->pSize = (char*)iter->pField - size_offset;
}
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
{
/* Fixed count array */
iter->pSize = &iter->array_size;
}
else
{
iter->pSize = NULL;
} }
return (iter->pos->tag != 0); if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
{
iter->pData = *(void**)iter->pField;
}
else
{
iter->pData = iter->pField;
}
}
if (PB_LTYPE_IS_SUBMSG(iter->type))
{
iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
}
else
{
iter->submsg_desc = NULL;
}
return true;
}
static void advance_iterator(pb_field_iter_t *iter)
{
iter->index++;
if (iter->index >= iter->descriptor->field_count)
{
/* Restart */
iter->index = 0;
iter->field_info_index = 0;
iter->submessage_index = 0;
iter->required_field_index = 0;
}
else
{
/* Increment indexes based on previous field type.
* All field info formats have the following fields:
* - lowest 2 bits tell the amount of words in the descriptor (2^n words)
* - bits 2..7 give the lowest bits of tag number.
* - bits 8..15 give the field type.
*/
uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
/* Add to fields.
* The cast to pb_size_t is needed to avoid -Wconversion warning.
* Because the data is is constants from generator, there is no danger of overflow.
*/
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
}
}
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
{
memset(iter, 0, sizeof(*iter));
iter->descriptor = desc;
iter->message = message;
return load_descriptor_values(iter);
}
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
{
const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
bool status;
uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
* indirection. */
status = pb_field_iter_begin(iter, msg, &extension->dest);
}
else
{
status = pb_field_iter_begin(iter, msg, extension->dest);
}
iter->pSize = &extension->found;
return status;
} }
bool pb_field_iter_next(pb_field_iter_t *iter) bool pb_field_iter_next(pb_field_iter_t *iter)
{ {
const pb_field_t *prev_field = iter->pos; advance_iterator(iter);
(void)load_descriptor_values(iter);
if (prev_field->tag == 0) return iter->index != 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 &&
iter->pos->data_offset == PB_SIZE_MAX)
{
/* Don't advance pointers inside unions */
return true;
}
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) bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
{ {
const pb_field_t *start = iter->pos; if (iter->tag == tag)
do {
if (iter->pos->tag == tag &&
PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
{ {
/* Found the wanted field */ return true; /* Nothing to do, correct field already. */
}
else if (tag > iter->descriptor->largest_tag)
{
return false;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
if (tag < iter->tag)
{
/* Fields are in tag number order, so we know that tag is between
* 0 and our start position. Setting index to end forces
* advance_iterator() call below to restart from beginning. */
iter->index = iter->descriptor->field_count;
}
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for tag number match */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
{
/* Good candidate, check further */
(void)load_descriptor_values(iter);
if (iter->tag == tag &&
PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
{
/* Found it */
return true;
}
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
{
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
{
return true;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for field type */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
{
return load_descriptor_values(iter);
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. The cast is done using union
* to avoid spurious compiler warnings. */
union {
void *p1;
const void *p2;
} t;
t.p2 = p;
return t.p1;
}
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
{
return pb_field_iter_begin(iter, desc, pb_const_cast(message));
}
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
{
return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
}
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (field->data_size == sizeof(pb_callback_t))
{
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
if (pCallback != NULL)
{
if (istream != NULL && pCallback->funcs.decode != NULL)
{
return pCallback->funcs.decode(istream, field, &pCallback->arg);
}
if (ostream != NULL && pCallback->funcs.encode != NULL)
{
return pCallback->funcs.encode(ostream, field, &pCallback->arg);
}
}
}
return true; /* Success, but didn't do anything */
}
#ifdef PB_VALIDATE_UTF8
/* This function checks whether a string is valid UTF-8 text.
*
* Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
* Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
* Licensed under "Short code license", which allows use under MIT license or
* any compatible with it.
*/
bool pb_validate_utf8(const char *str)
{
const pb_byte_t *s = (const pb_byte_t*)str;
while (*s)
{
if (*s < 0x80)
{
/* 0xxxxxxx */
s++;
}
else if ((s[0] & 0xe0) == 0xc0)
{
/* 110XXXXx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[0] & 0xfe) == 0xc0) /* overlong? */
return false;
else
s += 2;
}
else if ((s[0] & 0xf0) == 0xe0)
{
/* 1110XXXX 10Xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
(s[0] == 0xef && s[1] == 0xbf &&
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
return false;
else
s += 3;
}
else if ((s[0] & 0xf8) == 0xf0)
{
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[3] & 0xc0) != 0x80 ||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
return false;
else
s += 4;
}
else
{
return false;
}
}
return true; return true;
} }
(void)pb_field_iter_next(iter); #endif
} while (iter->pos != start);
/* Searched all the way back to start, and found nothing. */
return false;
}

View File

@ -11,20 +11,18 @@
extern "C" { extern "C" {
#endif #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. /* Initialize the field iterator structure to beginning.
* Returns false if the message type is empty. */ * 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); bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message);
/* Get a field iterator for extension field. */
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension);
/* Same as pb_field_iter_begin(), but for const message pointer.
* Note that the pointers in pb_field_iter_t will be non-const but shouldn't
* be written to when using these functions. */
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message);
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension);
/* Advance the iterator to the next field. /* Advance the iterator to the next field.
* Returns false when the iterator wraps back to the first field. */ * Returns false when the iterator wraps back to the first field. */
@ -34,6 +32,15 @@ bool pb_field_iter_next(pb_field_iter_t *iter);
* Returns false if no such field exists. */ * Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
* There can be only one extension range field per message. */
bool pb_field_iter_find_extension(pb_field_iter_t *iter);
#ifdef PB_VALIDATE_UTF8
/* Validate UTF-8 text string */
bool pb_validate_utf8(const char *s);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -37,14 +37,31 @@ struct pb_istream_s
bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
#endif #endif
void *state; /* Free field for use by callback implementation */ /* state is a free field for use of the callback function defined above.
* Note that when pb_istream_from_buffer() is used, it reserves this field
* for its own use.
*/
void *state;
/* Maximum number of bytes left in this stream. Callback can report
* EOF before this limit is reached. Setting a limit is recommended
* when decoding directly from file or network streams to avoid
* denial-of-service by excessively long messages.
*/
size_t bytes_left; size_t bytes_left;
#ifndef PB_NO_ERRMSG #ifndef PB_NO_ERRMSG
/* Pointer to constant (ROM) string when decoding function returns error */
const char *errmsg; const char *errmsg;
#endif #endif
}; };
#ifndef PB_NO_ERRMSG
#define PB_ISTREAM_EMPTY {0,0,0,0}
#else
#define PB_ISTREAM_EMPTY {0,0,0}
#endif
/*************************** /***************************
* Main decoding functions * * Main decoding functions *
***************************/ ***************************/
@ -65,57 +82,61 @@ struct pb_istream_s
* stream = pb_istream_from_buffer(buffer, count); * stream = pb_istream_from_buffer(buffer, count);
* pb_decode(&stream, MyMessage_fields, &msg); * pb_decode(&stream, MyMessage_fields, &msg);
*/ */
bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
/* Same as pb_decode, except does not initialize the destination structure /* Extended version of pb_decode, with several options to control
* to default values. This is slightly faster if you need no default values * the decoding process:
* and just do memset(struct, 0, sizeof(struct)) yourself.
* *
* This can also be used for 'merging' two messages, i.e. update only the * PB_DECODE_NOINIT: Do not initialize the fields to default values.
* fields that exist in the new message. * This is slightly faster if you do not need the default
* values and instead initialize the structure to 0 using
* e.g. memset(). This can also be used for merging two
* messages, i.e. combine already existing data with new
* values.
* *
* Note: If this function returns with an error, it will not release any * PB_DECODE_DELIMITED: Input message starts with the message size as varint.
* dynamically allocated fields. You will need to call pb_release() yourself. * Corresponds to parseDelimitedFrom() in Google's
*/
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. * protobuf API.
*/ *
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); * PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows
* reading null terminated messages.
/* Same as pb_decode_delimited, except that it does not initialize the destination structure. * NOTE: Until nanopb-0.4.0, pb_decode() also allows
* See pb_decode_noinit * null-termination. This behaviour is not supported in
*/ * most other protobuf implementations, so PB_DECODE_DELIMITED
bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except allows the message to be terminated with a null byte.
* NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour
* is not supported in most other protobuf implementations, so pb_decode_delimited()
* is a better option for compatibility. * is a better option for compatibility.
*
* Multiple flags can be combined with bitwise or (| operator)
*/ */
bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); #define PB_DECODE_NOINIT 0x01U
#define PB_DECODE_DELIMITED 0x02U
#define PB_DECODE_NULLTERMINATED 0x04U
bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT)
#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED)
#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT)
#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED)
#ifdef PB_ENABLE_MALLOC
/* Release any allocated pointer fields. If you use dynamic allocation, you should /* 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 * 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. * pb_decode() returns with an error, the message is already released.
*/ */
void pb_release(const pb_field_t fields[], void *dest_struct); void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
#endif
/************************************** /**************************************
* Functions for manipulating streams * * Functions for manipulating streams *
**************************************/ **************************************/
/* Create an input stream for reading from a memory buffer. /* Create an input stream for reading from a memory buffer.
*
* msglen should be the actual length of the message, not the full size of
* allocated buffer.
* *
* Alternatively, you can use a custom stream that reads directly from e.g. * Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket. * a file or a network socket.
*/ */
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
/* Function to read from a pb_istream_t. You can use this if you need to /* 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. * read some custom header data, or to read data in field callbacks.
@ -167,6 +188,11 @@ bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
bool pb_decode_fixed64(pb_istream_t *stream, void *dest); bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
#endif #endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Decode a double value into float variable. */
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest);
#endif
/* Make a limited-length substream for reading a PB_WT_STRING field. */ /* 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); bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);

File diff suppressed because it is too large Load Diff

View File

@ -33,15 +33,25 @@ struct pb_ostream_s
* Also, NULL pointer marks a 'sizing stream' that does not * Also, NULL pointer marks a 'sizing stream' that does not
* write anything. * write anything.
*/ */
int *callback; const int *callback;
#else #else
bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
#endif #endif
void *state; /* Free field for use by callback implementation. */
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ /* state is a free field for use of the callback function defined above.
size_t bytes_written; /* Number of bytes written so far. */ * Note that when pb_ostream_from_buffer() is used, it reserves this field
* for its own use.
*/
void *state;
/* Limit number of output bytes written. Can be set to SIZE_MAX. */
size_t max_size;
/* Number of bytes written so far. */
size_t bytes_written;
#ifndef PB_NO_ERRMSG #ifndef PB_NO_ERRMSG
/* Pointer to constant (ROM) string when decoding function returns error */
const char *errmsg; const char *errmsg;
#endif #endif
}; };
@ -64,22 +74,31 @@ struct pb_ostream_s
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); * stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
* pb_encode(&stream, MyMessage_fields, &msg); * pb_encode(&stream, MyMessage_fields, &msg);
*/ */
bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
/* Same as pb_encode, but prepends the length of the message as a varint. /* Extended version of pb_encode, with several options to control the
* Corresponds to writeDelimitedTo() in Google's protobuf API. * encoding process:
*/ *
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); * PB_ENCODE_DELIMITED: Prepend the length of message as a varint.
* Corresponds to writeDelimitedTo() in Google's
/* Same as pb_encode, but appends a null byte to the message for termination. * protobuf API.
* NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() *
* PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination.
* NOTE: This behaviour is not supported in most other
* protobuf implementations, so PB_ENCODE_DELIMITED
* is a better option for compatibility. * is a better option for compatibility.
*/ */
bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); #define PB_ENCODE_DELIMITED 0x02U
#define PB_ENCODE_NULLTERMINATED 0x04U
bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags);
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED)
#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED)
/* Encode the message to get the size of the encoded data, but do not store /* Encode the message to get the size of the encoded data, but do not store
* the data. */ * the data. */
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
/************************************** /**************************************
* Functions for manipulating streams * * Functions for manipulating streams *
@ -121,7 +140,7 @@ bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
/* Encode field header based on type and field number defined in the field /* Encode field header based on type and field number defined in the field
* structure. Call this from the callback before writing out field contents. */ * 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); bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
/* Encode field header by manually specifying wire type. You need to use this /* Encode field header by manually specifying wire type. You need to use this
* if you want to write out packed arrays from a callback field. */ * if you want to write out packed arrays from a callback field. */
@ -156,12 +175,18 @@ bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
#endif #endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Encode a float value so that it appears like a double in the encoded
* message. */
bool pb_encode_float_as_double(pb_ostream_t *stream, float value);
#endif
/* Encode a submessage field. /* Encode a submessage field.
* You need to pass the pb_field_t array and pointer to struct, just like * 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 * with pb_encode(). This internally encodes the submessage twice, first to
* calculate message size and then to actually write it out. * 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); bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@ -1,7 +1,7 @@
diff --git a/bundle/nginx-1.25.3/auto/make b/bundle/nginx-1.25.3/auto/make diff --git a/auto/make b/auto/make
index 25ee3fb..d61a188 100644 index 25ee3fb..d61a188 100644
--- a/bundle/nginx-1.25.3/auto/make --- a/auto/make
+++ b/bundle/nginx-1.25.3/auto/make +++ b/auto/make
@@ -38,7 +38,7 @@ fi @@ -38,7 +38,7 @@ fi
# ALL_INCS, required by the addons and by OpenWatcom C precompiled headers # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers
@ -20,10 +20,10 @@ index 25ee3fb..d61a188 100644
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
-e "s/\//$ngx_regex_dirsep/g"` -e "s/\//$ngx_regex_dirsep/g"`
diff --git a/bundle/nginx-1.25.3/auto/modules b/bundle/nginx-1.25.3/auto/modules diff --git a/auto/modules b/auto/modules
index 300d07c..f72c9a9 100644 index 300d07c..f72c9a9 100644
--- a/bundle/nginx-1.25.3/auto/modules --- a/auto/modules
+++ b/bundle/nginx-1.25.3/auto/modules +++ b/auto/modules
@@ -1381,7 +1381,7 @@ if [ $USE_PCRE = YES ]; then @@ -1381,7 +1381,7 @@ if [ $USE_PCRE = YES ]; then
fi fi
@ -33,10 +33,10 @@ index 300d07c..f72c9a9 100644
# thread pool module should be initialized after events # thread pool module should be initialized after events
diff --git a/bundle/nginx-1.25.3/auto/sources b/bundle/nginx-1.25.3/auto/sources diff --git a/auto/sources b/auto/sources
index 46408ee..ab13c93 100644 index 46408ee..ab13c93 100644
--- a/bundle/nginx-1.25.3/auto/sources --- a/auto/sources
+++ b/bundle/nginx-1.25.3/auto/sources +++ b/auto/sources
@@ -81,6 +81,9 @@ CORE_SRCS="src/core/nginx.c \ @@ -81,6 +81,9 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_syslog.c" src/core/ngx_syslog.c"
@ -47,10 +47,10 @@ index 46408ee..ab13c93 100644
EVENT_MODULES="ngx_events_module ngx_event_core_module" EVENT_MODULES="ngx_events_module ngx_event_core_module"
EVENT_INCS="src/event src/event/modules src/event/quic" EVENT_INCS="src/event src/event/modules src/event/quic"
diff --git a/bundle/nginx-1.25.3/src/http/ngx_http_upstream.c b/bundle/nginx-1.25.3/src/http/ngx_http_upstream.c diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 2be233c..f4ee563 100644 index 2be233c..f4ee563 100644
--- a/bundle/nginx-1.25.3/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c
+++ b/bundle/nginx-1.25.3/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c
@@ -6146,11 +6146,13 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) @@ -6146,11 +6146,13 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
return rv; return rv;
} }
@ -65,10 +65,10 @@ index 2be233c..f4ee563 100644
return rv; return rv;
} }
diff --git a/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.c b/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.c diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index dadf03f..d003cc6 100644 index dadf03f..d003cc6 100644
--- a/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c
+++ b/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c
@@ -10,6 +10,9 @@ @@ -10,6 +10,9 @@
#include <ngx_event.h> #include <ngx_event.h>
#include <ngx_channel.h> #include <ngx_channel.h>
@ -130,10 +130,10 @@ index dadf03f..d003cc6 100644
+ ngx_worker_process_init(cycle, -1); + ngx_worker_process_init(cycle, -1);
+} +}
+#endif +#endif
diff --git a/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.h b/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.h diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h
index 5149396..dbce402 100644 index 5149396..dbce402 100644
--- a/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.h --- a/src/os/unix/ngx_process_cycle.h
+++ b/bundle/nginx-1.25.3/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h
@@ -59,4 +59,8 @@ extern sig_atomic_t ngx_reopen; @@ -59,4 +59,8 @@ extern sig_atomic_t ngx_reopen;
extern sig_atomic_t ngx_change_binary; extern sig_atomic_t ngx_change_binary;