3a2f2e6cbe7a78a7879bb47251450a6acc59f499
[platform/upstream/libnice.git] / stun / usages / timer.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2008-2009 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  * (C) 2007-2009 Nokia Corporation. All rights reserved.
7  *  Contact: Rémi Denis-Courmont
8  *
9  * The contents of this file are subject to the Mozilla Public License Version
10  * 1.1 (the "License"); you may not use this file except in compliance with
11  * the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS" basis,
15  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16  * for the specific language governing rights and limitations under the
17  * License.
18  *
19  * The Original Code is the Nice GLib ICE library.
20  *
21  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22  * Corporation. All Rights Reserved.
23  *
24  * Contributors:
25  *   Youness Alaoui, Collabora Ltd.
26  *   Rémi Denis-Courmont, Nokia
27  *
28  * Alternatively, the contents of this file may be used under the terms of the
29  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
30  * case the provisions of LGPL are applicable instead of those above. If you
31  * wish to allow use of your version of this file only under the terms of the
32  * LGPL and not to allow others to use your version of this file under the
33  * MPL, indicate your decision by deleting the provisions above and replace
34  * them with the notice and other provisions required by the LGPL. If you do
35  * not delete the provisions above, a recipient may use your version of this
36  * file under either the MPL or the LGPL.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 # include <config.h>
41 #endif
42
43 #ifdef _WIN32
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #else
47 #include <unistd.h>
48 #endif
49
50 #include "timer.h"
51
52 #include <stdlib.h> /* div() */
53
54 /*
55  * Clock used throughout the STUN code.
56  * STUN requires a monotonic 1kHz clock to operate properly.
57  */
58 static void stun_gettime (struct timeval *now)
59 {
60 #ifdef _WIN32
61   FILETIME ft;
62   unsigned long long *time64 = (unsigned long long *) &ft;
63
64   GetSystemTimeAsFileTime (&ft);
65
66   /* Convert from 100s of nanoseconds since 1601-01-01
67    * to Unix epoch. Yes, this is Y2038 unsafe.
68    */
69   *time64 -= (unsigned long long) 116444736000000000;
70   *time64 /= 10;
71
72   now->tv_sec = (long)(*time64 / 1000000);
73   now->tv_usec = *time64 % 1000000;
74 #else
75 #if defined (_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
76   struct timespec spec;
77   if (!clock_gettime (CLOCK_MONOTONIC, &spec)) {
78     now->tv_sec = spec.tv_sec;
79     now->tv_usec = spec.tv_nsec / 1000;
80   } else
81 #endif
82   {  // fallback to wall clock
83     gettimeofday (now, NULL);
84   }
85 #endif
86 }
87
88
89 static void set_delay (struct timeval *ts, unsigned delay)
90 {
91   stun_gettime (ts);
92
93   /* Delay is in ms. */
94   ts->tv_sec += delay / 1000;
95   ts->tv_usec += (delay % 1000) * 1000;
96
97   while (ts->tv_usec > 1000000)
98   {
99     ts->tv_usec -= 1000000;
100     ts->tv_sec++;
101   }
102 }
103
104
105 void stun_timer_start (StunTimer *timer, unsigned int initial_timeout,
106     unsigned int max_retransmissions)
107 {
108   timer->retransmissions = 1;
109   timer->delay = initial_timeout;
110   timer->max_retransmissions = max_retransmissions;
111   set_delay (&timer->deadline, timer->delay);
112 }
113
114
115 void stun_timer_start_reliable (StunTimer *timer, unsigned int initial_timeout)
116 {
117   stun_timer_start (timer, initial_timeout, 0);
118 }
119
120
121
122 unsigned stun_timer_remainder (const StunTimer *timer)
123 {
124   unsigned delay;
125   struct timeval now;
126
127   stun_gettime (&now);
128   if (now.tv_sec > timer->deadline.tv_sec)
129     return 0;
130
131   delay = timer->deadline.tv_sec - now.tv_sec;
132   if ((delay == 0) && (now.tv_usec >= timer->deadline.tv_usec))
133     return 0;
134
135   delay *= 1000;
136   delay += ((signed)(timer->deadline.tv_usec - now.tv_usec)) / 1000;
137   return delay;
138 }
139
140
141 StunUsageTimerReturn stun_timer_refresh (StunTimer *timer)
142 {
143   unsigned delay = stun_timer_remainder (timer);
144   if (delay == 0)
145   {
146     if (timer->retransmissions >= timer->max_retransmissions)
147       return STUN_USAGE_TIMER_RETURN_TIMEOUT;
148
149     if (timer->retransmissions == timer->max_retransmissions - 1)
150       timer->delay = timer->delay / 2;
151     else
152       timer->delay = timer->delay * 2;
153     set_delay (&timer->deadline, timer->delay);
154     timer->retransmissions++;
155     return STUN_USAGE_TIMER_RETURN_RETRANSMIT;
156   }
157
158   return STUN_USAGE_TIMER_RETURN_SUCCESS;
159 }