first commit
[libutp-c.git] / utp_utils.c
blob665fed2418c8ababe65a1ac3bca0d4e61b3a03e9
1 #include "StdAfx.h"
3 #include "utypes.h"
4 #include <assert.h>
5 #include <stdlib.h>
7 /* XXX: need a sacrificial lamb for win-diarrhea testing */
8 #ifdef WIN32
10 #define WIN32_LEAN_AND_MEAN
11 #include <windows.h>
12 #include <winsock2.h>
13 #include <ws2tcpip.h>
15 typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
16 static GetTickCount64Proc *pt2GetTickCount64;
17 static GetTickCount64Proc *pt2RealGetTickCount;
19 static uint64 startPerformanceCounter;
20 static uint64 startGetTickCount;
21 /* MSVC 6 standard doesn't like division with uint64s */
22 static double counterPerMicrosecond;
24 uint64 UTGetTickCount64()
26 if (pt2GetTickCount64) {
27 return pt2GetTickCount64();
29 if (pt2RealGetTickCount) {
30 uint64 v = pt2RealGetTickCount();
31 /* fix return value from GetTickCount */
32 return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
34 return (uint64)GetTickCount();
37 void Time_Initialize()
39 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
40 pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
41 /* not a typo. GetTickCount actually returns 64 bits */
42 pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
44 uint64 frequency;
45 QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
46 QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
47 counterPerMicrosecond = (double)frequency / 1000000.0f;
48 startGetTickCount = UTGetTickCount64();
51 int64 abs64(int64 x) { return x < 0 ? -x : x; }
53 static uint64 GetMicroseconds(void)
55 static bool time_init = false;
56 if (!time_init) {
57 time_init = true;
58 Time_Initialize();
61 uint64 counter;
62 uint64 tick;
64 QueryPerformanceCounter((LARGE_INTEGER*) &counter);
65 tick = UTGetTickCount64();
67 /* unfortunately, QueryPerformanceCounter is not guaranteed
68 to be monotonic. Make it so. */
69 int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
70 /* if the QPC clock leaps more than one second off GetTickCount64()
71 something is seriously fishy. Adjust QPC to stay monotonic */
72 int64 tick_diff = tick - startGetTickCount;
73 if (abs64(ret / 100000 - tick_diff / 100) > 10) {
74 startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
75 ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
77 return ret;
80 #else /* !WIN32 */
82 #include <time.h>
83 #include <sys/time.h> /* Linux needs both time.h and sys/time.h */
84 #include <stdlib.h>
86 #include <unistd.h>
87 #include <sys/socket.h>
88 #include <arpa/inet.h>
90 /* XXX: need a sacrificial lamb to test this on mac-vomit */
91 #if defined(__APPLE__)
92 #include <mach/mach_time.h>
94 static uint64 GetMicroseconds(void)
96 /* http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
97 http://www.macresearch.org/tutorial_performance_and_time */
98 static mach_timebase_info_data_t sTimebaseInfo;
99 static uint64_t start_tick = 0;
100 uint64_t tick;
101 /* Returns a counter in some fraction of a nanoseconds */
102 tick = mach_absolute_time();
103 if (sTimebaseInfo.denom == 0) {
104 /* Get the timer ratio to convert mach_absolute_time to nanoseconds */
105 mach_timebase_info(&sTimebaseInfo);
106 start_tick = tick;
108 /* Calculate the elapsed time, convert it to microseconds and return it. */
109 return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
112 #else /* !__APPLE__ */
114 /* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
115 POSIX clocks work -- we could be running a recent libc with an ancient
116 kernel (think OpenWRT). -- jch */
118 static uint64_t GetMicroseconds(void)
120 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
121 static int have_posix_clocks = -1;
122 #endif
123 int rc;
125 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
126 if (have_posix_clocks < 0) {
127 struct timespec ts;
128 rc = clock_gettime(CLOCK_MONOTONIC, &ts);
129 if (rc < 0) {
130 have_posix_clocks = 0;
131 } else {
132 have_posix_clocks = 1;
136 if (have_posix_clocks) {
137 struct timespec ts;
138 rc = clock_gettime(CLOCK_MONOTONIC, &ts);
139 (void)rc;
140 return (uint64)(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
142 #endif
144 struct timeval tv;
145 rc = gettimeofday(&tv, NULL);
146 (void)rc;
147 return (uint64)(tv.tv_sec) * 1000000 + tv.tv_usec;
150 #endif /* !__APPLE__ */
152 #endif /* !WIN32 */
154 uint64 UTP_GetMicroseconds(void)
156 static uint64 offset = 0;
157 static uint64 previous = 0;
158 uint64 now;
160 now = GetMicroseconds() + offset;
161 if (previous > now) {
162 /* Eek! */
163 offset += previous - now;
164 now = previous;
166 previous = now;
167 return now;
170 uint32 UTP_GetMilliseconds(void)
172 return UTP_GetMicroseconds() / 1000;
175 #define ETHERNET_MTU 1500
176 #define IPV4_HEADER_SIZE 20
177 #define IPV6_HEADER_SIZE 40
178 #define UDP_HEADER_SIZE 8
179 #define GRE_HEADER_SIZE 24
180 #define PPPOE_HEADER_SIZE 8
181 #define MPPE_HEADER_SIZE 2
182 /* packets have been observed in the wild that were fragmented
183 with a payload of 1416 for the first fragment
184 There are reports of routers that have MTU sizes as small as 1392 */
185 #define FUDGE_HEADER_SIZE 36
186 #define TEREDO_MTU 1280
188 #define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
189 #define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
190 #define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
192 #define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
193 #define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
194 #define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE)
196 uint16 UTP_GetUDPMTU(struct sockaddr *remote, socklen_t remotelen)
198 (void)remotelen;
199 /* Since we don't know the local address of the interface,
200 be conservative and assume all IPv6 connections are Teredo. */
201 return remote->sa_family == AF_INET6 ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
204 uint16 UTP_GetUDPOverhead(struct sockaddr *remote, socklen_t remotelen)
206 (void)remotelen;
207 /* Since we don't know the local address of the interface,
208 be conservative and assume all IPv6 connections are Teredo. */
209 return remote->sa_family == AF_INET6 ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
212 uint32 UTP_Random(void)
214 return rand();
217 void UTP_DelaySample(struct sockaddr *remote, int sample_ms)
219 (void)remote;
220 (void)sample_ms;
223 size_t UTP_sockaddr_GetPacketSize(struct sockaddr *remote)
225 (void)remote;
226 return 1500;