author | michaelm |
Wed, 29 Nov 2017 16:59:38 +0000 | |
branch | http-client-branch |
changeset 55912 | dfa9489d1cb1 |
parent 47216 | 71c04702a3d5 |
child 48767 | 0c6ce8fdb50a |
permissions | -rw-r--r-- |
2 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
15274
diff
changeset
|
2 |
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
#include <windows.h> |
|
26 |
#include <winsock2.h> |
|
27 |
||
28 |
#include "sysSocket.h" |
|
29 |
#include "socketTransport.h" |
|
30 |
||
31 |
typedef jboolean bool_t; |
|
32 |
||
33 |
/* |
|
34 |
* Table of Windows Sockets errors, the specific exception we |
|
35 |
* throw for the error, and the error text. |
|
36 |
* |
|
37 |
* Note that this table excludes OS dependent errors. |
|
38 |
*/ |
|
39 |
static struct { |
|
40 |
int errCode; |
|
41 |
const char *errString; |
|
42 |
} const winsock_errors[] = { |
|
43 |
{ WSAEPROVIDERFAILEDINIT, "Provider initialization failed (check %SystemRoot%)" }, |
|
44 |
{ WSAEACCES, "Permission denied" }, |
|
45 |
{ WSAEADDRINUSE, "Address already in use" }, |
|
46 |
{ WSAEADDRNOTAVAIL, "Cannot assign requested address" }, |
|
47 |
{ WSAEAFNOSUPPORT, "Address family not supported by protocol family" }, |
|
48 |
{ WSAEALREADY, "Operation already in progress" }, |
|
49 |
{ WSAECONNABORTED, "Software caused connection abort" }, |
|
50 |
{ WSAECONNREFUSED, "Connection refused" }, |
|
51 |
{ WSAECONNRESET, "Connection reset by peer" }, |
|
52 |
{ WSAEDESTADDRREQ, "Destination address required" }, |
|
53 |
{ WSAEFAULT, "Bad address" }, |
|
54 |
{ WSAEHOSTDOWN, "Host is down" }, |
|
55 |
{ WSAEHOSTUNREACH, "No route to host" }, |
|
56 |
{ WSAEINPROGRESS, "Operation now in progress" }, |
|
57 |
{ WSAEINTR, "Interrupted function call" }, |
|
58 |
{ WSAEINVAL, "Invalid argument" }, |
|
59 |
{ WSAEISCONN, "Socket is already connected" }, |
|
60 |
{ WSAEMFILE, "Too many open files" }, |
|
61 |
{ WSAEMSGSIZE, "The message is larger than the maximum supported by the underlying transport" }, |
|
62 |
{ WSAENETDOWN, "Network is down" }, |
|
63 |
{ WSAENETRESET, "Network dropped connection on reset" }, |
|
64 |
{ WSAENETUNREACH, "Network is unreachable" }, |
|
65 |
{ WSAENOBUFS, "No buffer space available (maximum connections reached?)" }, |
|
66 |
{ WSAENOPROTOOPT, "Bad protocol option" }, |
|
67 |
{ WSAENOTCONN, "Socket is not connected" }, |
|
68 |
{ WSAENOTSOCK, "Socket operation on nonsocket" }, |
|
69 |
{ WSAEOPNOTSUPP, "Operation not supported" }, |
|
70 |
{ WSAEPFNOSUPPORT, "Protocol family not supported" }, |
|
71 |
{ WSAEPROCLIM, "Too many processes" }, |
|
72 |
{ WSAEPROTONOSUPPORT, "Protocol not supported" }, |
|
73 |
{ WSAEPROTOTYPE, "Protocol wrong type for socket" }, |
|
74 |
{ WSAESHUTDOWN, "Cannot send after socket shutdown" }, |
|
75 |
{ WSAESOCKTNOSUPPORT, "Socket type not supported" }, |
|
76 |
{ WSAETIMEDOUT, "Connection timed out" }, |
|
77 |
{ WSATYPE_NOT_FOUND, "Class type not found" }, |
|
78 |
{ WSAEWOULDBLOCK, "Resource temporarily unavailable" }, |
|
79 |
{ WSAHOST_NOT_FOUND, "Host not found" }, |
|
80 |
{ WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available" }, |
|
81 |
{ WSANOTINITIALISED, "Successful WSAStartup not yet performed" }, |
|
82 |
{ WSANO_DATA, "Valid name, no data record of requested type" }, |
|
83 |
{ WSANO_RECOVERY, "This is a nonrecoverable error" }, |
|
84 |
{ WSASYSNOTREADY, "Network subsystem is unavailable" }, |
|
85 |
{ WSATRY_AGAIN, "Nonauthoritative host not found" }, |
|
86 |
{ WSAVERNOTSUPPORTED, "Winsock.dll version out of range" }, |
|
87 |
{ WSAEDISCON, "Graceful shutdown in progress" }, |
|
88 |
{ WSA_OPERATION_ABORTED, "Overlapped operation aborted" }, |
|
89 |
}; |
|
90 |
||
91 |
||
92 |
/* |
|
93 |
* Initialize Windows Sockets API support |
|
94 |
*/ |
|
95 |
BOOL WINAPI |
|
96 |
DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) |
|
97 |
{ |
|
98 |
WSADATA wsadata; |
|
99 |
||
100 |
switch (reason) { |
|
101 |
case DLL_PROCESS_ATTACH: |
|
102 |
if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) { |
|
103 |
return FALSE; |
|
104 |
} |
|
105 |
break; |
|
106 |
||
107 |
case DLL_PROCESS_DETACH: |
|
108 |
WSACleanup(); |
|
109 |
break; |
|
110 |
||
111 |
default: |
|
112 |
break; |
|
113 |
} |
|
114 |
return TRUE; |
|
115 |
} |
|
116 |
||
117 |
/* |
|
118 |
* If we get a nonnull function pointer it might still be the case |
|
119 |
* that some other thread is in the process of initializing the socket |
|
120 |
* function pointer table, but our pointer should still be good. |
|
121 |
*/ |
|
122 |
int |
|
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
123 |
dbgsysListen(int fd, int backlog) { |
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
124 |
return listen(fd, backlog); |
2 | 125 |
} |
126 |
||
127 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
128 |
dbgsysConnect(int fd, struct sockaddr *name, socklen_t namelen) { |
2 | 129 |
int rv = connect(fd, name, namelen); |
130 |
if (rv == SOCKET_ERROR) { |
|
131 |
if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) { |
|
132 |
return DBG_EINPROGRESS; |
|
133 |
} |
|
134 |
} |
|
135 |
return rv; |
|
136 |
} |
|
137 |
||
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
138 |
int dbgsysFinishConnect(int fd, int timeout) { |
2 | 139 |
int rv; |
140 |
struct timeval t; |
|
141 |
fd_set wr, ex; |
|
142 |
||
143 |
t.tv_sec = timeout / 1000; |
|
144 |
t.tv_usec = (timeout % 1000) * 1000; |
|
145 |
||
146 |
FD_ZERO(&wr); |
|
147 |
FD_ZERO(&ex); |
|
148 |
FD_SET((unsigned int)fd, &wr); |
|
149 |
FD_SET((unsigned int)fd, &ex); |
|
150 |
||
151 |
rv = select(fd+1, 0, &wr, &ex, &t); |
|
152 |
if (rv == 0) { |
|
153 |
return SYS_ERR; /* timeout */ |
|
154 |
} |
|
155 |
||
156 |
/* |
|
157 |
* Check if there was an error - this is preferable to check if |
|
158 |
* the socket is writable because some versions of Windows don't |
|
159 |
* report a connected socket as being writable. |
|
160 |
*/ |
|
161 |
if (!FD_ISSET(fd, &ex)) { |
|
162 |
return SYS_OK; |
|
163 |
} |
|
164 |
||
165 |
/* |
|
166 |
* Unable to establish connection - to get the reason we must |
|
167 |
* call getsockopt. |
|
168 |
*/ |
|
169 |
return SYS_ERR; |
|
170 |
} |
|
171 |
||
172 |
||
173 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
174 |
dbgsysAccept(int fd, struct sockaddr *name, socklen_t *namelen) { |
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
175 |
return (int)accept(fd, name, namelen); |
2 | 176 |
} |
177 |
||
178 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
179 |
dbgsysRecvFrom(int fd, char *buf, size_t nBytes, |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
180 |
int flags, struct sockaddr *from, socklen_t *fromlen) { |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
181 |
return recvfrom(fd, buf, (int)nBytes, flags, from, fromlen); |
2 | 182 |
} |
183 |
||
184 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
185 |
dbgsysSendTo(int fd, char *buf, size_t len, |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
186 |
int flags, struct sockaddr *to, socklen_t tolen) { |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
187 |
return sendto(fd, buf, (int)len, flags, to, tolen); |
2 | 188 |
} |
189 |
||
190 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
191 |
dbgsysRecv(int fd, char *buf, size_t nBytes, int flags) { |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
192 |
return recv(fd, buf, (int) nBytes, flags); |
2 | 193 |
} |
194 |
||
195 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
196 |
dbgsysSend(int fd, char *buf, size_t nBytes, int flags) { |
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
197 |
return send(fd, buf, (int)nBytes, flags); |
2 | 198 |
} |
199 |
||
200 |
struct hostent * |
|
201 |
dbgsysGetHostByName(char *hostname) { |
|
202 |
return gethostbyname(hostname); |
|
203 |
} |
|
204 |
||
205 |
unsigned short |
|
206 |
dbgsysHostToNetworkShort(unsigned short hostshort) { |
|
207 |
return htons(hostshort); |
|
208 |
} |
|
209 |
||
210 |
int |
|
211 |
dbgsysSocket(int domain, int type, int protocol) { |
|
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
212 |
int fd = (int)socket(domain, type, protocol); |
2 | 213 |
if (fd != SOCKET_ERROR) { |
214 |
SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); |
|
215 |
} |
|
216 |
return fd; |
|
217 |
} |
|
218 |
||
219 |
int |
|
220 |
dbgsysSocketClose(int fd) { |
|
221 |
struct linger l; |
|
222 |
int len = sizeof(l); |
|
223 |
||
224 |
if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&l, &len) == 0) { |
|
225 |
if (l.l_onoff == 0) { |
|
226 |
WSASendDisconnect(fd, NULL); |
|
227 |
} |
|
228 |
} |
|
229 |
return closesocket(fd); |
|
230 |
} |
|
231 |
||
232 |
/* Additions to original follow */ |
|
233 |
||
234 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
235 |
dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) { |
2 | 236 |
return bind(fd, name, namelen); |
237 |
} |
|
238 |
||
239 |
||
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
240 |
uint32_t |
2 | 241 |
dbgsysInetAddr(const char* cp) { |
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
242 |
return (uint32_t)inet_addr(cp); |
2 | 243 |
} |
244 |
||
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
245 |
uint32_t |
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
246 |
dbgsysHostToNetworkLong(uint32_t hostlong) { |
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
247 |
return (uint32_t)htonl((u_long)hostlong); |
2 | 248 |
} |
249 |
||
250 |
unsigned short |
|
251 |
dbgsysNetworkToHostShort(unsigned short netshort) { |
|
252 |
return ntohs(netshort); |
|
253 |
} |
|
254 |
||
255 |
int |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
256 |
dbgsysGetSocketName(int fd, struct sockaddr *name, socklen_t *namelen) { |
2 | 257 |
return getsockname(fd, name, namelen); |
258 |
} |
|
259 |
||
896
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
260 |
uint32_t |
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
261 |
dbgsysNetworkToHostLong(uint32_t netlong) { |
5c02031316bf
6725543: Compiler warnings in serviceability native code
ohair
parents:
2
diff
changeset
|
262 |
return (uint32_t)ntohl((u_long)netlong); |
2 | 263 |
} |
264 |
||
265 |
/* |
|
266 |
* Below Adapted from PlainSocketImpl.c, win32 version 1.18. Changed exception |
|
267 |
* throws to returns of SYS_ERR; we should improve the error codes |
|
268 |
* eventually. Changed java objects to values the debugger back end can |
|
269 |
* more easily deal with. |
|
270 |
*/ |
|
271 |
||
272 |
int |
|
273 |
dbgsysSetSocketOption(int fd, jint cmd, jboolean on, jvalue value) |
|
274 |
{ |
|
275 |
if (cmd == TCP_NODELAY) { |
|
276 |
struct protoent *proto = getprotobyname("TCP"); |
|
277 |
int tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto); |
|
278 |
long onl = (long)on; |
|
279 |
||
280 |
if (setsockopt(fd, tcp_level, TCP_NODELAY, |
|
281 |
(char *)&onl, sizeof(long)) < 0) { |
|
282 |
return SYS_ERR; |
|
283 |
} |
|
284 |
} else if (cmd == SO_LINGER) { |
|
285 |
struct linger arg; |
|
286 |
arg.l_onoff = on; |
|
287 |
||
288 |
if(on) { |
|
289 |
arg.l_linger = (unsigned short)value.i; |
|
290 |
if(setsockopt(fd, SOL_SOCKET, SO_LINGER, |
|
291 |
(char*)&arg, sizeof(arg)) < 0) { |
|
292 |
return SYS_ERR; |
|
293 |
} |
|
294 |
} else { |
|
295 |
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, |
|
296 |
(char*)&arg, sizeof(arg)) < 0) { |
|
297 |
return SYS_ERR; |
|
298 |
} |
|
299 |
} |
|
300 |
} else if (cmd == SO_SNDBUF) { |
|
301 |
jint buflen = value.i; |
|
302 |
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, |
|
303 |
(char *)&buflen, sizeof(buflen)) < 0) { |
|
304 |
return SYS_ERR; |
|
305 |
} |
|
306 |
} else if (cmd == SO_REUSEADDR) { |
|
307 |
/* |
|
308 |
* On Windows the SO_REUSEADDR socket option doesn't implement |
|
309 |
* BSD semantics. Specifically, the socket option allows multiple |
|
310 |
* processes to bind to the same address/port rather than allowing |
|
311 |
* a process to bind with a previous connection in the TIME_WAIT |
|
312 |
* state. Hence on Windows we never enable this option for TCP |
|
313 |
* option. |
|
314 |
*/ |
|
315 |
int sotype, arglen=sizeof(sotype); |
|
316 |
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) == SOCKET_ERROR) { |
|
317 |
return SYS_ERR; |
|
318 |
} |
|
319 |
if (sotype != SOCK_STREAM) { |
|
320 |
int oni = (int)on; |
|
321 |
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, |
|
322 |
(char *)&oni, sizeof(oni)) == SOCKET_ERROR) { |
|
323 |
return SYS_ERR; |
|
324 |
} |
|
325 |
} |
|
326 |
} else { |
|
327 |
return SYS_ERR; |
|
328 |
} |
|
329 |
return SYS_OK; |
|
330 |
} |
|
331 |
||
332 |
int dbgsysConfigureBlocking(int fd, jboolean blocking) { |
|
333 |
u_long argp; |
|
334 |
int result = 0; |
|
335 |
||
336 |
if (blocking == JNI_FALSE) { |
|
337 |
argp = 1; |
|
338 |
} else { |
|
339 |
argp = 0; |
|
340 |
} |
|
341 |
result = ioctlsocket(fd, FIONBIO, &argp); |
|
342 |
if (result == SOCKET_ERROR) { |
|
343 |
return SYS_ERR; |
|
344 |
} else { |
|
345 |
return SYS_OK; |
|
346 |
} |
|
347 |
} |
|
348 |
||
349 |
int |
|
350 |
dbgsysPoll(int fd, jboolean rd, jboolean wr, long timeout) { |
|
351 |
int rv; |
|
352 |
struct timeval t; |
|
353 |
fd_set rd_tbl, wr_tbl; |
|
354 |
||
355 |
t.tv_sec = timeout / 1000; |
|
356 |
t.tv_usec = (timeout % 1000) * 1000; |
|
357 |
||
358 |
FD_ZERO(&rd_tbl); |
|
359 |
if (rd) { |
|
360 |
FD_SET((unsigned int)fd, &rd_tbl); |
|
361 |
} |
|
362 |
||
363 |
FD_ZERO(&wr_tbl); |
|
364 |
if (wr) { |
|
365 |
FD_SET((unsigned int)fd, &wr_tbl); |
|
366 |
} |
|
367 |
||
368 |
rv = select(fd+1, &rd_tbl, &wr_tbl, 0, &t); |
|
369 |
if (rv >= 0) { |
|
370 |
rv = 0; |
|
371 |
if (FD_ISSET(fd, &rd_tbl)) { |
|
372 |
rv |= DBG_POLLIN; |
|
373 |
} |
|
374 |
if (FD_ISSET(fd, &wr_tbl)) { |
|
375 |
rv |= DBG_POLLOUT; |
|
376 |
} |
|
377 |
} |
|
378 |
return rv; |
|
379 |
} |
|
380 |
||
381 |
int |
|
382 |
dbgsysGetLastIOError(char *buf, jint size) { |
|
383 |
int table_size = sizeof(winsock_errors) / |
|
384 |
sizeof(winsock_errors[0]); |
|
385 |
int i; |
|
386 |
int error = WSAGetLastError(); |
|
387 |
||
388 |
/* |
|
389 |
* Check table for known winsock errors |
|
390 |
*/ |
|
391 |
i=0; |
|
392 |
while (i < table_size) { |
|
393 |
if (error == winsock_errors[i].errCode) { |
|
394 |
break; |
|
395 |
} |
|
396 |
i++; |
|
397 |
} |
|
398 |
||
399 |
if (i < table_size) { |
|
400 |
strcpy(buf, winsock_errors[i].errString); |
|
401 |
} else { |
|
402 |
sprintf(buf, "winsock error %d", error); |
|
403 |
} |
|
404 |
return 0; |
|
405 |
} |
|
406 |
||
407 |
||
408 |
int |
|
409 |
dbgsysTlsAlloc() { |
|
410 |
return TlsAlloc(); |
|
411 |
} |
|
412 |
||
413 |
void |
|
414 |
dbgsysTlsFree(int index) { |
|
415 |
TlsFree(index); |
|
416 |
} |
|
417 |
||
418 |
void |
|
419 |
dbgsysTlsPut(int index, void *value) { |
|
420 |
TlsSetValue(index, value); |
|
421 |
} |
|
422 |
||
423 |
void * |
|
424 |
dbgsysTlsGet(int index) { |
|
425 |
return TlsGetValue(index); |
|
426 |
} |
|
427 |
||
428 |
#define FT2INT64(ft) \ |
|
15274
a77cdd5ea6e3
8005120: Compiler warnings in socket transport native code
jzavgren
parents:
5506
diff
changeset
|
429 |
((INT64)(ft).dwHighDateTime << 32 | (INT64)(ft).dwLowDateTime) |
2 | 430 |
|
431 |
long |
|
432 |
dbgsysCurrentTimeMillis() { |
|
433 |
static long fileTime_1_1_70 = 0; /* midnight 1/1/70 */ |
|
434 |
SYSTEMTIME st0; |
|
435 |
FILETIME ft0; |
|
436 |
||
437 |
/* initialize on first usage */ |
|
438 |
if (fileTime_1_1_70 == 0) { |
|
439 |
memset(&st0, 0, sizeof(st0)); |
|
440 |
st0.wYear = 1970; |
|
441 |
st0.wMonth = 1; |
|
442 |
st0.wDay = 1; |
|
443 |
SystemTimeToFileTime(&st0, &ft0); |
|
444 |
fileTime_1_1_70 = FT2INT64(ft0); |
|
445 |
} |
|
446 |
||
447 |
GetSystemTime(&st0); |
|
448 |
SystemTimeToFileTime(&st0, &ft0); |
|
449 |
||
450 |
return (FT2INT64(ft0) - fileTime_1_1_70) / 10000; |
|
451 |
} |