LCOV - code coverage report
Current view: top level - core/transport/chttp2 - timeout_encoding.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 90 94 95.7 %
Date: 2015-12-10 22:15:08 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 <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             : }

Generated by: LCOV version 1.11