LCOV - code coverage report
Current view: top level - src/core/transport/chttp2 - timeout_encoding.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 89 94 94.7 %
Date: 2015-10-10 Functions: 10 10 100.0 %

          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 "src/core/support/string.h"
      40             : 
      41        5273 : static int round_up(int x, int divisor) {
      42        5273 :   return (x / divisor + (x % divisor != 0)) * divisor;
      43             : }
      44             : 
      45             : /* round an integer up to the next value with three significant figures */
      46        5274 : static int round_up_to_three_sig_figs(int x) {
      47        5274 :   if (x < 1000) return x;
      48        5273 :   if (x < 10000) return round_up(x, 10);
      49        5272 :   if (x < 100000) return round_up(x, 100);
      50        5271 :   if (x < 1000000) return round_up(x, 1000);
      51        5267 :   if (x < 10000000) return round_up(x, 10000);
      52         331 :   if (x < 100000000) return round_up(x, 100000);
      53          82 :   if (x < 1000000000) return round_up(x, 1000000);
      54           0 :   return round_up(x, 10000000);
      55             : }
      56             : 
      57             : /* encode our minimum viable timeout value */
      58           2 : static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
      59             : 
      60        5296 : static void enc_ext(char *buffer, long value, char ext) {
      61        5296 :   int n = gpr_ltoa(value, buffer);
      62        5296 :   buffer[n] = ext;
      63        5296 :   buffer[n + 1] = 0;
      64        5296 : }
      65             : 
      66          24 : static void enc_seconds(char *buffer, long sec) {
      67          24 :   if (sec % 3600 == 0) {
      68          14 :     enc_ext(buffer, sec / 3600, 'H');
      69          10 :   } else if (sec % 60 == 0) {
      70           3 :     enc_ext(buffer, sec / 60, 'M');
      71             :   } else {
      72           7 :     enc_ext(buffer, sec, 'S');
      73             :   }
      74          24 : }
      75             : 
      76          55 : static void enc_nanos(char *buffer, int x) {
      77          55 :   x = round_up_to_three_sig_figs(x);
      78          55 :   if (x < 100000) {
      79           3 :     if (x % 1000 == 0) {
      80           2 :       enc_ext(buffer, x / 1000, 'u');
      81             :     } else {
      82           1 :       enc_ext(buffer, x, 'n');
      83             :     }
      84          52 :   } else if (x < 100000000) {
      85          50 :     if (x % 1000000 == 0) {
      86           2 :       enc_ext(buffer, x / 1000000, 'm');
      87             :     } else {
      88          48 :       enc_ext(buffer, x / 1000, 'u');
      89             :     }
      90           2 :   } else if (x < 1000000000) {
      91           0 :     enc_ext(buffer, x / 1000000, 'm');
      92             :   } else {
      93             :     /* note that this is only ever called with times of less than one second,
      94             :        so if we reach here the time must have been rounded up to a whole second
      95             :        (and no more) */
      96           2 :     memcpy(buffer, "1S", 3);
      97             :   }
      98          55 : }
      99             : 
     100        5219 : static void enc_micros(char *buffer, int x) {
     101        5219 :   x = round_up_to_three_sig_figs(x);
     102        5219 :   if (x < 100000) {
     103           0 :     if (x % 1000 == 0) {
     104           0 :       enc_ext(buffer, x / 1000, 'm');
     105             :     } else {
     106           0 :       enc_ext(buffer, x, 'u');
     107             :     }
     108        5219 :   } else if (x < 100000000) {
     109        5127 :     if (x % 1000000 == 0) {
     110        4585 :       enc_ext(buffer, x / 1000000, 'S');
     111             :     } else {
     112         542 :       enc_ext(buffer, x / 1000, 'm');
     113             :     }
     114             :   } else {
     115          92 :     enc_ext(buffer, x / 1000000, 'S');
     116             :   }
     117        5219 : }
     118             : 
     119        5300 : void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
     120        5300 :   if (timeout.tv_sec < 0) {
     121           2 :     enc_tiny(buffer);
     122        5298 :   } else if (timeout.tv_sec == 0) {
     123          55 :     enc_nanos(buffer, timeout.tv_nsec);
     124        5243 :   } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
     125        5219 :     enc_micros(buffer,
     126        5219 :                (int)(timeout.tv_sec * 1000000) +
     127        5219 :                    (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
     128             :   } else {
     129          24 :     enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
     130             :   }
     131        5300 : }
     132             : 
     133        3492 : static int is_all_whitespace(const char *p) {
     134        3492 :   while (*p == ' ') p++;
     135        3492 :   return *p == 0;
     136             : }
     137             : 
     138        3501 : int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
     139        3501 :   gpr_uint32 x = 0;
     140        3501 :   const gpr_uint8 *p = (const gpr_uint8 *)buffer;
     141        3501 :   int have_digit = 0;
     142             :   /* skip whitespace */
     143        3501 :   for (; *p == ' '; p++)
     144             :     ;
     145             :   /* decode numeric part */
     146       10593 :   for (; *p >= '0' && *p <= '9'; p++) {
     147        7093 :     gpr_uint32 xp = x * 10u + (gpr_uint32)*p - (gpr_uint32)'0';
     148        7093 :     have_digit = 1;
     149        7093 :     if (xp < x) {
     150           1 :       *timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
     151           1 :       return 1;
     152             :     }
     153        7092 :     x = xp;
     154             :   }
     155        3500 :   if (!have_digit) return 0;
     156             :   /* skip whitespace */
     157        3494 :   for (; *p == ' '; p++)
     158             :     ;
     159             :   /* decode unit specifier */
     160        3494 :   switch (*p) {
     161             :     case 'n':
     162          68 :       *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
     163          68 :       break;
     164             :     case 'u':
     165         112 :       *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
     166         112 :       break;
     167             :     case 'm':
     168         577 :       *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
     169         577 :       break;
     170             :     case 'S':
     171        2587 :       *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
     172        2587 :       break;
     173             :     case 'M':
     174          68 :       *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
     175          68 :       break;
     176             :     case 'H':
     177          80 :       *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
     178          80 :       break;
     179             :     default:
     180           2 :       return 0;
     181             :   }
     182        3492 :   p++;
     183        3492 :   return is_all_whitespace((const char *)p);
     184             : }

Generated by: LCOV version 1.10