1 /* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef MY_XP_UTIL_INCLUDED
24 #define MY_XP_UTIL_INCLUDED
25 
26 #include <mysql/gcs/mysql_gcs.h>
27 
28 #ifdef _WIN32
29 #include <windows.h>
30 #else
31 #include <unistd.h>
32 #endif
33 
34 #if defined(WIN32) || defined(WIN64)
35 #include <Winsock2.h>
36 #include <ws2tcpip.h>
37 #ifndef INET_ADDRSTRLEN
38 #define socklen_t int
39 #endif
40 #else
41 #include <arpa/inet.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <sys/time.h>
47 #include <time.h>
48 #endif
49 #include <iostream>
50 #include <errno.h>
51 #include <stdint.h>
52 
53 #define INT_MAX32     0x7FFFFFFFL
54 #define MY_MIN(a, b)  ((a) < (b) ? (a) : (b))
55 
56 
57 #ifdef _WIN32
58 
59 #define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
60 #define MS 10000000
61 
62 #ifdef HAVE_STRUCT_TIMESPEC
63 #include<time.h>
64 #endif
65 
66 #endif
67 
68 #ifndef HAVE_STRUCT_TIMESPEC /* Windows before VS2015 */
69 /*
70   Declare a union to make sure FILETIME is properly aligned
71   so it can be used directly as a 64 bit value. The value
72   stored is in 100ns units.
73 */
74 union ft64 {
75   FILETIME ft;
76   __int64 i64;
77  };
78 
79 struct timespec {
80   union ft64 tv;
81   /* The max timeout value in millisecond for native_cond_timedwait */
82   long max_timeout_msec;
83 };
84 
85 #endif /* !HAVE_STRUCT_TIMESPEC */
86 
87 
88 /**
89   @class My_xp_util
90 
91   Class where cross platform utilities reside as static methods.
92 */
93 class My_xp_util
94 {
95 public:
96   /**
97     Current thread sleeps for the parameterized number of seconds.
98 
99     @param seconds number of seconds for invoking thread to sleep
100   */
101 
102   static void sleep_seconds(unsigned int seconds);
103 
104   /* Code ported from MySQL Server to deal with timespec. */
105 #ifdef _WIN32
106   static uint64_t query_performance_frequency, query_performance_offset;
107 
108   static void win_init_time();
109 #endif
110 
111   /**
112     Init time.
113   */
114 
115   static void init_time();
116 
117 
118   /**
119     Get the system's time.
120 
121     @return system's time in 100s of nanoseconds
122   */
123 
124   static uint64_t getsystime(void);
125 
126 
127   /**
128     Set the value of the timespec struct equal to the argument in nanoseconds.
129   */
130 
set_timespec_nsec(struct timespec * abstime,uint64_t nsec)131   static inline void set_timespec_nsec(struct timespec *abstime, uint64_t nsec)
132   {
133   #ifdef HAVE_STRUCT_TIMESPEC
134     uint64_t now= My_xp_util::getsystime() + (nsec / 100);
135     uint64_t tv_sec= now / 10000000ULL;
136   #if SIZEOF_TIME_T < SIZEOF_LONG_LONG
137     /* Ensure that the number of seconds don't overflow. */
138     tv_sec= MY_MIN(tv_sec, ((uint64_t)INT_MAX32));
139   #endif
140     abstime->tv_sec=  (time_t)tv_sec;
141     abstime->tv_nsec= (now % 10000000ULL) * 100 + (nsec % 100);
142   #else /* !HAVE_STRUCT_TIMESPEC */
143     uint64_t max_timeout_msec= (nsec / 1000000);
144     union ft64 tv;
145     GetSystemTimeAsFileTime(&tv.ft);
146     abstime->tv.i64= tv.i64 + (__int64)(nsec / 100);
147   #if SIZEOF_LONG < SIZEOF_LONG_LONG
148     /* Ensure that the msec value doesn't overflow. */
149     max_timeout_msec= MY_MIN(max_timeout_msec, ((uint64_t)INT_MAX32));
150   #endif
151     abstime->max_timeout_msec= (long)max_timeout_msec;
152   #endif /* !HAVE_STRUCT_TIMESPEC */
153   }
154 
155 
156   /**
157     Set the value of the timespec struct equal to the argument in seconds.
158   */
159 
set_timespec(struct timespec * abstime,uint64_t sec)160   static inline void set_timespec(struct timespec *abstime, uint64_t sec)
161   {
162     My_xp_util::set_timespec_nsec(abstime, sec * 1000000000ULL);
163   }
164 
165 
166   /**
167     Compare two timespec structs.
168 
169     @retval  1 If ts1 ends after ts2.
170     @retval -1 If ts1 ends before ts2.
171     @retval  0 If ts1 is equal to ts2.
172   */
173 
cmp_timespec(struct timespec * ts1,struct timespec * ts2)174   static inline int cmp_timespec(struct timespec *ts1, struct timespec *ts2)
175   {
176 #ifdef HAVE_STRUCT_TIMESPEC
177     if (ts1->tv_sec > ts2->tv_sec ||
178         (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec > ts2->tv_nsec))
179       return 1;
180     if (ts1->tv_sec < ts2->tv_sec ||
181         (ts1->tv_sec == ts2->tv_sec && ts1->tv_nsec < ts2->tv_nsec))
182       return -1;
183 #else
184     if (ts1->tv.i64 > ts2->tv.i64)
185       return 1;
186     if (ts1->tv.i64 < ts2->tv.i64)
187       return -1;
188 #endif
189     return 0;
190   }
191 
192 
193   /**
194     Diff two timespec structs.
195 
196     @return  difference between the two arguments.
197   */
198 
diff_timespec(struct timespec * ts1,struct timespec * ts2)199   static inline uint64_t diff_timespec(struct timespec *ts1,
200                                        struct timespec *ts2)
201   {
202 #ifdef HAVE_STRUCT_TIMESPEC
203     return (ts1->tv_sec - ts2->tv_sec) * 1000000000ULL +
204       ts1->tv_nsec - ts2->tv_nsec;
205 #else
206     return (ts1->tv.i64 - ts2->tv.i64) * 100;
207 #endif
208   }
209 };
210 
211 
212 /**
213   @class My_xp_socket_util
214 
215   Interface for socket utility methods.
216 */
217 class My_xp_socket_util
218 {
219 public:
220 
221   /**
222     Disable Nagle algorithm in the specified socket.
223 
224     @param fd file descriptor of the socket
225   */
226 
227   virtual int disable_nagle_in_socket(int fd)= 0;
228 
~My_xp_socket_util()229   virtual ~My_xp_socket_util() {};
230 };
231 
232 
233 class My_xp_socket_util_impl : public My_xp_socket_util
234 {
235 public:
236   int disable_nagle_in_socket(int fd);
My_xp_socket_util_impl()237   explicit My_xp_socket_util_impl() {};
~My_xp_socket_util_impl()238   ~My_xp_socket_util_impl() {};
239 };
240 
241 #endif // MY_XP_UTIL_INCLUDED
242