Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "src/core/transport/chttp2/timeout_encoding.h"
35 :
36 : #include <stdio.h>
37 : #include <string.h>
38 :
39 : #include <grpc/support/port_platform.h>
40 : #include "src/core/support/string.h"
41 :
42 1048084 : static int round_up(int x, int divisor) {
43 1048090 : return (x / divisor + (x % divisor != 0)) * divisor;
44 : }
45 :
46 : /* round an integer up to the next value with three significant figures */
47 1048091 : static int round_up_to_three_sig_figs(int x) {
48 1048091 : if (x < 1000) return x;
49 1048090 : if (x < 10000) return round_up(x, 10);
50 1048089 : if (x < 100000) return round_up(x, 100);
51 1048087 : if (x < 1000000) return round_up(x, 1000);
52 1048082 : if (x < 10000000) return round_up(x, 10000);
53 284 : if (x < 100000000) return round_up(x, 100000);
54 104 : if (x < 1000000000) return round_up(x, 1000000);
55 0 : return round_up(x, 10000000);
56 : }
57 :
58 : /* encode our minimum viable timeout value */
59 24 : static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
60 :
61 1048115 : static void enc_ext(char *buffer, gpr_int64 value, char ext) {
62 1048117 : int n = gpr_int64toa(value, buffer);
63 1048117 : buffer[n] = ext;
64 1048117 : buffer[n + 1] = 0;
65 1048115 : }
66 :
67 32 : static void enc_seconds(char *buffer, gpr_int64 sec) {
68 32 : if (sec % 3600 == 0) {
69 22 : enc_ext(buffer, sec / 3600, 'H');
70 10 : } else if (sec % 60 == 0) {
71 3 : enc_ext(buffer, sec / 60, 'M');
72 : } else {
73 7 : enc_ext(buffer, sec, 'S');
74 : }
75 32 : }
76 :
77 60 : static void enc_nanos(char *buffer, int x) {
78 60 : x = round_up_to_three_sig_figs(x);
79 60 : if (x < 100000) {
80 4 : if (x % 1000 == 0) {
81 2 : enc_ext(buffer, x / 1000, 'u');
82 : } else {
83 2 : enc_ext(buffer, x, 'n');
84 : }
85 56 : } else if (x < 100000000) {
86 46 : if (x % 1000000 == 0) {
87 2 : enc_ext(buffer, x / 1000000, 'm');
88 : } else {
89 44 : enc_ext(buffer, x / 1000, 'u');
90 : }
91 10 : } else if (x < 1000000000) {
92 4 : enc_ext(buffer, x / 1000000, 'm');
93 : } else {
94 : /* note that this is only ever called with times of less than one second,
95 : so if we reach here the time must have been rounded up to a whole second
96 : (and no more) */
97 6 : memcpy(buffer, "1S", 3);
98 : }
99 60 : }
100 :
101 1048031 : static void enc_micros(char *buffer, int x) {
102 1048031 : x = round_up_to_three_sig_figs(x);
103 1048031 : if (x < 100000) {
104 0 : if (x % 1000 == 0) {
105 0 : enc_ext(buffer, x / 1000, 'm');
106 : } else {
107 0 : enc_ext(buffer, x, 'u');
108 : }
109 1048031 : } else if (x < 100000000) {
110 1047931 : if (x % 1000000 == 0) {
111 1045922 : enc_ext(buffer, x / 1000000, 'S');
112 : } else {
113 2009 : enc_ext(buffer, x / 1000, 'm');
114 : }
115 : } else {
116 100 : enc_ext(buffer, x / 1000000, 'S');
117 : }
118 1048031 : }
119 :
120 1048147 : void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
121 1048147 : if (timeout.tv_sec < 0) {
122 24 : enc_tiny(buffer);
123 1048123 : } else if (timeout.tv_sec == 0) {
124 60 : enc_nanos(buffer, timeout.tv_nsec);
125 1048063 : } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
126 1048031 : enc_micros(buffer,
127 1048031 : (int)(timeout.tv_sec * 1000000) +
128 1048031 : (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
129 : } else {
130 32 : enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
131 : }
132 1048147 : }
133 :
134 1528 : static int is_all_whitespace(const char *p) {
135 1528 : while (*p == ' ') p++;
136 1530 : return *p == 0;
137 : }
138 :
139 1541 : int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
140 1539 : gpr_uint32 x = 0;
141 1539 : const gpr_uint8 *p = (const gpr_uint8 *)buffer;
142 1539 : int have_digit = 0;
143 : /* skip whitespace */
144 1541 : for (; *p == ' '; p++)
145 : ;
146 : /* decode numeric part */
147 6607 : for (; *p >= '0' && *p <= '9'; p++) {
148 5069 : gpr_uint32 xp = x * 10u + (gpr_uint32)*p - (gpr_uint32)'0';
149 5065 : have_digit = 1;
150 5069 : if (xp < x) {
151 1 : *timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
152 1 : return 1;
153 : }
154 5064 : x = xp;
155 : }
156 1540 : if (!have_digit) return 0;
157 : /* skip whitespace */
158 1532 : for (; *p == ' '; p++)
159 : ;
160 : /* decode unit specifier */
161 1534 : switch (*p) {
162 : case 'n':
163 69 : *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
164 69 : break;
165 : case 'u':
166 108 : *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
167 108 : break;
168 : case 'm':
169 650 : *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
170 650 : break;
171 : case 'S':
172 562 : *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
173 562 : break;
174 : case 'M':
175 68 : *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
176 68 : break;
177 : case 'H':
178 73 : *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
179 73 : break;
180 : default:
181 4 : return 0;
182 : }
183 1530 : p++;
184 1530 : return is_all_whitespace((const char *)p);
185 : }
|