• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 1998 Massachusetts Institute of Technology
4  * Copyright (c) The c-ares project and its contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * SPDX-License-Identifier: MIT
26  */
27 
28 #include "ares_private.h"
29 
30 #ifdef HAVE_LIMITS_H
31 #  include <limits.h>
32 #endif
33 
34 
ares_timeval_remaining(ares_timeval_t * remaining,const ares_timeval_t * now,const ares_timeval_t * tout)35 void ares_timeval_remaining(ares_timeval_t       *remaining,
36                             const ares_timeval_t *now,
37                             const ares_timeval_t *tout)
38 {
39   memset(remaining, 0, sizeof(*remaining));
40 
41   /* Expired! */
42   if (tout->sec < now->sec ||
43       (tout->sec == now->sec && tout->usec < now->usec)) {
44     return;
45   }
46 
47   remaining->sec = tout->sec - now->sec;
48   if (tout->usec < now->usec) {
49     remaining->sec  -= 1;
50     remaining->usec  = (tout->usec + 1000000) - now->usec;
51   } else {
52     remaining->usec = tout->usec - now->usec;
53   }
54 }
55 
ares_timeval_diff(ares_timeval_t * tvdiff,const ares_timeval_t * tvstart,const ares_timeval_t * tvstop)56 void ares_timeval_diff(ares_timeval_t *tvdiff, const ares_timeval_t *tvstart,
57                        const ares_timeval_t *tvstop)
58 {
59   tvdiff->sec = tvstop->sec - tvstart->sec;
60   if (tvstop->usec > tvstart->usec) {
61     tvdiff->usec = tvstop->usec - tvstart->usec;
62   } else {
63     tvdiff->sec  -= 1;
64     tvdiff->usec  = tvstop->usec + 1000000 - tvstart->usec;
65   }
66 }
67 
ares_timeval_to_struct_timeval(struct timeval * tv,const ares_timeval_t * atv)68 static void ares_timeval_to_struct_timeval(struct timeval       *tv,
69                                            const ares_timeval_t *atv)
70 {
71 #ifdef USE_WINSOCK
72   tv->tv_sec = (long)atv->sec;
73 #else
74   tv->tv_sec = (time_t)atv->sec;
75 #endif
76 
77   tv->tv_usec = (int)atv->usec;
78 }
79 
struct_timeval_to_ares_timeval(ares_timeval_t * atv,const struct timeval * tv)80 static void struct_timeval_to_ares_timeval(ares_timeval_t       *atv,
81                                            const struct timeval *tv)
82 {
83   atv->sec  = (ares_int64_t)tv->tv_sec;
84   atv->usec = (unsigned int)tv->tv_usec;
85 }
86 
ares_timeout_int(const ares_channel_t * channel,struct timeval * maxtv,struct timeval * tvbuf)87 static struct timeval *ares_timeout_int(const ares_channel_t *channel,
88                                         struct timeval       *maxtv,
89                                         struct timeval       *tvbuf)
90 {
91   const ares_query_t *query;
92   ares_slist_node_t  *node;
93   ares_timeval_t      now;
94   ares_timeval_t      atvbuf;
95   ares_timeval_t      amaxtv;
96 
97   /* The minimum timeout of all queries is always the first entry in
98    * channel->queries_by_timeout */
99   node = ares_slist_node_first(channel->queries_by_timeout);
100   /* no queries/timeout */
101   if (node == NULL) {
102     return maxtv;
103   }
104 
105   query = ares_slist_node_val(node);
106 
107   ares_tvnow(&now);
108 
109   ares_timeval_remaining(&atvbuf, &now, &query->timeout);
110 
111   ares_timeval_to_struct_timeval(tvbuf, &atvbuf);
112 
113   if (maxtv == NULL) {
114     return tvbuf;
115   }
116 
117   /* Return the minimum time between maxtv and tvbuf */
118   struct_timeval_to_ares_timeval(&amaxtv, maxtv);
119 
120   if (atvbuf.sec > amaxtv.sec) {
121     return maxtv;
122   }
123 
124   if (atvbuf.sec < amaxtv.sec) {
125     return tvbuf;
126   }
127 
128   if (atvbuf.usec > amaxtv.usec) {
129     return maxtv;
130   }
131 
132   return tvbuf;
133 }
134 
ares_timeout(const ares_channel_t * channel,struct timeval * maxtv,struct timeval * tvbuf)135 struct timeval *ares_timeout(const ares_channel_t *channel,
136                              struct timeval *maxtv, struct timeval *tvbuf)
137 {
138   struct timeval *rv;
139 
140   if (channel == NULL || tvbuf == NULL) {
141     return NULL;
142   }
143 
144   ares_channel_lock(channel);
145 
146   rv = ares_timeout_int(channel, maxtv, tvbuf);
147 
148   ares_channel_unlock(channel);
149 
150   return rv;
151 }
152