blob: 0edacaafd354760963250fe93b8b773bbc7cd01f [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Jan Tattermuschfd3d8202016-01-19 20:17:07 -08003 * Copyright 2015-2016, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/transport/chttp2/timeout_encoding.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035
36#include <stdio.h>
37#include <string.h>
38
Jan Tattermusch4b3ecdf2015-12-04 09:33:05 -080039#include <grpc/support/port_platform.h>
Craig Tiller9533d042016-03-25 17:11:06 -070040#include "src/core/lib/support/string.h"
Craig Tiller985463d2015-01-23 11:13:10 -080041
Craig Tiller7536af02015-12-22 13:49:30 -080042static int64_t round_up(int64_t x, int64_t divisor) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043 return (x / divisor + (x % divisor != 0)) * divisor;
44}
45
46/* round an integer up to the next value with three significant figures */
Craig Tiller7536af02015-12-22 13:49:30 -080047static int64_t round_up_to_three_sig_figs(int64_t x) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080048 if (x < 1000) return x;
49 if (x < 10000) return round_up(x, 10);
50 if (x < 100000) return round_up(x, 100);
51 if (x < 1000000) return round_up(x, 1000);
52 if (x < 10000000) return round_up(x, 10000);
53 if (x < 100000000) return round_up(x, 100000);
54 if (x < 1000000000) return round_up(x, 1000000);
55 return round_up(x, 10000000);
56}
57
58/* encode our minimum viable timeout value */
Craig Tiller985463d2015-01-23 11:13:10 -080059static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
60
Craig Tiller7536af02015-12-22 13:49:30 -080061static void enc_ext(char *buffer, int64_t value, char ext) {
62 int n = int64_ttoa(value, buffer);
Craig Tiller985463d2015-01-23 11:13:10 -080063 buffer[n] = ext;
Yang Gao5fd0d292015-01-26 00:19:48 -080064 buffer[n + 1] = 0;
Craig Tiller985463d2015-01-23 11:13:10 -080065}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080066
Craig Tiller7536af02015-12-22 13:49:30 -080067static void enc_seconds(char *buffer, int64_t sec) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068 if (sec % 3600 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -080069 enc_ext(buffer, sec / 3600, 'H');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070 } else if (sec % 60 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -080071 enc_ext(buffer, sec / 60, 'M');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080072 } else {
Craig Tiller985463d2015-01-23 11:13:10 -080073 enc_ext(buffer, sec, 'S');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080074 }
75}
76
Craig Tiller7536af02015-12-22 13:49:30 -080077static void enc_nanos(char *buffer, int64_t x) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080078 x = round_up_to_three_sig_figs(x);
79 if (x < 100000) {
80 if (x % 1000 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -080081 enc_ext(buffer, x / 1000, 'u');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082 } else {
Craig Tiller985463d2015-01-23 11:13:10 -080083 enc_ext(buffer, x, 'n');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080084 }
85 } else if (x < 100000000) {
86 if (x % 1000000 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -080087 enc_ext(buffer, x / 1000000, 'm');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088 } else {
Craig Tiller985463d2015-01-23 11:13:10 -080089 enc_ext(buffer, x / 1000, 'u');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080090 }
91 } else if (x < 1000000000) {
Craig Tiller985463d2015-01-23 11:13:10 -080092 enc_ext(buffer, x / 1000000, 'm');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080093 } 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) */
Craig Tiller985463d2015-01-23 11:13:10 -080097 memcpy(buffer, "1S", 3);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080098 }
99}
100
Craig Tiller7536af02015-12-22 13:49:30 -0800101static void enc_micros(char *buffer, int64_t x) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800102 x = round_up_to_three_sig_figs(x);
103 if (x < 100000) {
104 if (x % 1000 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -0800105 enc_ext(buffer, x / 1000, 'm');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800106 } else {
Craig Tiller985463d2015-01-23 11:13:10 -0800107 enc_ext(buffer, x, 'u');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800108 }
109 } else if (x < 100000000) {
110 if (x % 1000000 == 0) {
Craig Tiller985463d2015-01-23 11:13:10 -0800111 enc_ext(buffer, x / 1000000, 'S');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800112 } else {
Craig Tiller985463d2015-01-23 11:13:10 -0800113 enc_ext(buffer, x / 1000, 'm');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800114 }
115 } else {
Craig Tiller985463d2015-01-23 11:13:10 -0800116 enc_ext(buffer, x / 1000000, 'S');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800117 }
118}
119
120void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
121 if (timeout.tv_sec < 0) {
122 enc_tiny(buffer);
123 } else if (timeout.tv_sec == 0) {
124 enc_nanos(buffer, timeout.tv_nsec);
125 } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
126 enc_micros(buffer,
Craig Tiller7536af02015-12-22 13:49:30 -0800127 (int64_t)(timeout.tv_sec * 1000000) +
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800128 (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
129 } else {
130 enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
131 }
132}
133
134static int is_all_whitespace(const char *p) {
135 while (*p == ' ') p++;
136 return *p == 0;
137}
138
139int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
Jan Tattermusch66336472016-01-19 17:55:40 -0800140 int32_t x = 0;
Craig Tiller7536af02015-12-22 13:49:30 -0800141 const uint8_t *p = (const uint8_t *)buffer;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800142 int have_digit = 0;
143 /* skip whitespace */
144 for (; *p == ' '; p++)
145 ;
146 /* decode numeric part */
147 for (; *p >= '0' && *p <= '9'; p++) {
Jan Tattermusch66336472016-01-19 17:55:40 -0800148 int32_t digit = (int32_t)(*p - (uint8_t)'0');
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800149 have_digit = 1;
Jan Tattermusch66336472016-01-19 17:55:40 -0800150 /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
151 if (x >= (100 * 1000 * 1000)) {
152 if (x != (100 * 1000 * 1000) || digit != 0) {
Craig Tillerd2624542016-03-21 14:31:01 -0700153 *timeout = gpr_inf_future(GPR_TIMESPAN);
Jan Tattermusch66336472016-01-19 17:55:40 -0800154 return 1;
155 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800156 }
Jan Tattermusch66336472016-01-19 17:55:40 -0800157 x = x * 10 + digit;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800158 }
159 if (!have_digit) return 0;
160 /* skip whitespace */
161 for (; *p == ' '; p++)
162 ;
163 /* decode unit specifier */
164 switch (*p) {
165 case 'n':
Craig Tiller58bbc862015-07-13 09:51:17 -0700166 *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800167 break;
168 case 'u':
Craig Tiller58bbc862015-07-13 09:51:17 -0700169 *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800170 break;
171 case 'm':
Craig Tiller58bbc862015-07-13 09:51:17 -0700172 *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800173 break;
174 case 'S':
Craig Tiller58bbc862015-07-13 09:51:17 -0700175 *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800176 break;
177 case 'M':
Craig Tiller58bbc862015-07-13 09:51:17 -0700178 *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800179 break;
180 case 'H':
Craig Tiller58bbc862015-07-13 09:51:17 -0700181 *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800182 break;
183 default:
184 return 0;
185 }
186 p++;
Craig Tiller32ca48c2015-09-10 11:47:15 -0700187 return is_all_whitespace((const char *)p);
Craig Tiller190d3602015-02-18 09:23:38 -0800188}