1#!/usr/bin/env python3 2 3# Copyright 2017 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import print_function 18 19import collections 20import sys 21 22import perfection 23 24_MAX_HEADER_LIST_SIZE = 16 * 1024 * 1024 25 26Setting = collections.namedtuple('Setting', 'id default min max on_error') 27OnError = collections.namedtuple('OnError', 'behavior code') 28clamp_invalid_value = OnError('CLAMP_INVALID_VALUE', 'PROTOCOL_ERROR') 29disconnect_on_invalid_value = lambda e: OnError('DISCONNECT_ON_INVALID_VALUE', e 30 ) 31DecoratedSetting = collections.namedtuple('DecoratedSetting', 32 'enum name setting') 33 34_SETTINGS = { 35 'HEADER_TABLE_SIZE': 36 Setting(1, 4096, 0, 0xffffffff, clamp_invalid_value), 37 'ENABLE_PUSH': 38 Setting(2, 1, 0, 1, disconnect_on_invalid_value('PROTOCOL_ERROR')), 39 'MAX_CONCURRENT_STREAMS': 40 Setting(3, 0xffffffff, 0, 0xffffffff, 41 disconnect_on_invalid_value('PROTOCOL_ERROR')), 42 'INITIAL_WINDOW_SIZE': 43 Setting(4, 65535, 0, 0x7fffffff, 44 disconnect_on_invalid_value('FLOW_CONTROL_ERROR')), 45 'MAX_FRAME_SIZE': 46 Setting(5, 16384, 16384, 16777215, 47 disconnect_on_invalid_value('PROTOCOL_ERROR')), 48 'MAX_HEADER_LIST_SIZE': 49 Setting(6, _MAX_HEADER_LIST_SIZE, 0, _MAX_HEADER_LIST_SIZE, 50 clamp_invalid_value), 51 'GRPC_ALLOW_TRUE_BINARY_METADATA': 52 Setting(0xfe03, 0, 0, 1, clamp_invalid_value), 53 'GRPC_PREFERRED_RECEIVE_CRYPTO_FRAME_SIZE': 54 Setting(0xfe04, 0, 16384, 0x7fffffff, clamp_invalid_value), 55} 56 57H = open('src/core/ext/transport/chttp2/transport/http2_settings.h', 'w') 58C = open('src/core/ext/transport/chttp2/transport/http2_settings.cc', 'w') 59 60 61# utility: print a big comment block into a set of files 62def put_banner(files, banner): 63 for f in files: 64 print('/*', file=f) 65 for line in banner: 66 print(' * %s' % line, file=f) 67 print(' */', file=f) 68 print(file=f) 69 70 71# copy-paste copyright notice from this file 72with open(sys.argv[0]) as my_source: 73 copyright = [] 74 for line in my_source: 75 if line[0] != '#': 76 break 77 for line in my_source: 78 if line[0] == '#': 79 copyright.append(line) 80 break 81 for line in my_source: 82 if line[0] != '#': 83 break 84 copyright.append(line) 85 put_banner([H, C], [line[2:].rstrip() for line in copyright]) 86 87put_banner( 88 [H, C], 89 ["Automatically generated by tools/codegen/core/gen_settings_ids.py"]) 90 91print("#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", 92 file=H) 93print("#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H", 94 file=H) 95print(file=H) 96print("#include <grpc/support/port_platform.h>", file=H) 97print("#include <stdint.h>", file=H) 98print(file=H) 99 100print("#include <grpc/support/port_platform.h>", file=C) 101print("#include \"src/core/ext/transport/chttp2/transport/http2_settings.h\"", 102 file=C) 103print(file=C) 104print("#include \"src/core/lib/gpr/useful.h\"", file=C) 105print("#include \"src/core/lib/transport/http2_errors.h\"", file=C) 106print(file=C) 107 108p = perfection.hash_parameters(sorted(x.id for x in list(_SETTINGS.values()))) 109print(p) 110 111 112def hash(i): 113 i += p.offset 114 x = i % p.t 115 y = i // p.t 116 return x + p.r[y] 117 118 119decorated_settings = [ 120 DecoratedSetting(hash(setting.id), name, setting) 121 for name, setting in _SETTINGS.items() 122] 123 124print('typedef enum {', file=H) 125for decorated_setting in sorted(decorated_settings): 126 print(' GRPC_CHTTP2_SETTINGS_%s = %d, /* wire id %d */' % 127 (decorated_setting.name, decorated_setting.enum, 128 decorated_setting.setting.id), 129 file=H) 130print('} grpc_chttp2_setting_id;', file=H) 131print(file=H) 132print('#define GRPC_CHTTP2_NUM_SETTINGS %d' % 133 (max(x.enum for x in decorated_settings) + 1), 134 file=H) 135 136print('extern const uint16_t grpc_setting_id_to_wire_id[];', file=H) 137print('const uint16_t grpc_setting_id_to_wire_id[] = {%s};' % 138 ','.join('%d' % s for s in p.slots), 139 file=C) 140print(file=H) 141print( 142 "bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out);", 143 file=H) 144cgargs = { 145 'r': ','.join('%d' % (r if r is not None else 0) for r in p.r), 146 't': p.t, 147 'offset': abs(p.offset), 148 'offset_sign': '+' if p.offset > 0 else '-' 149} 150print(""" 151bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id *out) { 152 uint32_t i = wire_id %(offset_sign)s %(offset)d; 153 uint32_t x = i %% %(t)d; 154 uint32_t y = i / %(t)d; 155 uint32_t h = x; 156 switch (y) { 157""" % cgargs, 158 file=C) 159for i, r in enumerate(p.r): 160 if not r: 161 continue 162 if r < 0: 163 print('case %d: h -= %d; break;' % (i, -r), file=C) 164 else: 165 print('case %d: h += %d; break;' % (i, r), file=C) 166print(""" 167 } 168 *out = static_cast<grpc_chttp2_setting_id>(h); 169 return h < GPR_ARRAY_SIZE(grpc_setting_id_to_wire_id) && grpc_setting_id_to_wire_id[h] == wire_id; 170} 171""" % cgargs, 172 file=C) 173 174print(""" 175typedef enum { 176 GRPC_CHTTP2_CLAMP_INVALID_VALUE, 177 GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE 178} grpc_chttp2_invalid_value_behavior; 179 180typedef struct { 181 const char *name; 182 uint32_t default_value; 183 uint32_t min_value; 184 uint32_t max_value; 185 grpc_chttp2_invalid_value_behavior invalid_value_behavior; 186 uint32_t error_value; 187} grpc_chttp2_setting_parameters; 188 189extern const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS]; 190""", 191 file=H) 192print( 193 "const grpc_chttp2_setting_parameters grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {", 194 file=C) 195i = 0 196for decorated_setting in sorted(decorated_settings): 197 while i < decorated_setting.enum: 198 print( 199 "{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},", 200 file=C) 201 i += 1 202 print("{\"%s\", %du, %du, %du, GRPC_CHTTP2_%s, GRPC_HTTP2_%s}," % ( 203 decorated_setting.name, 204 decorated_setting.setting.default, 205 decorated_setting.setting.min, 206 decorated_setting.setting.max, 207 decorated_setting.setting.on_error.behavior, 208 decorated_setting.setting.on_error.code, 209 ), 210 file=C) 211 i += 1 212print("};", file=C) 213 214print(file=H) 215print("#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */", 216 file=H) 217 218H.close() 219C.close() 220