1/*
2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
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
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
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 *
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.
24 */
25#include <windows.h>
26#include <winsock2.h>
27
28#include "sysSocket.h"
29#include "socketTransport.h"
30
31typedef 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 */
39static 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 */
95BOOL WINAPI
96DllMain(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 */
122int
123dbgsysListen(int fd, int backlog) {
124    return listen(fd, backlog);
125}
126
127int
128dbgsysConnect(int fd, struct sockaddr *name, socklen_t namelen) {
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
138int dbgsysFinishConnect(int fd, int timeout) {
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
173int
174dbgsysAccept(int fd, struct sockaddr *name, socklen_t *namelen) {
175    return (int)accept(fd, name, namelen);
176}
177
178int
179dbgsysRecvFrom(int fd, char *buf, size_t nBytes,
180                  int flags, struct sockaddr *from, socklen_t *fromlen) {
181    return recvfrom(fd, buf, (int)nBytes, flags, from, fromlen);
182}
183
184int
185dbgsysSendTo(int fd, char *buf, size_t len,
186                int flags, struct sockaddr *to, socklen_t tolen) {
187    return sendto(fd, buf, (int)len, flags, to, tolen);
188}
189
190int
191dbgsysRecv(int fd, char *buf, size_t nBytes, int flags) {
192    return recv(fd, buf, (int) nBytes, flags);
193}
194
195int
196dbgsysSend(int fd, char *buf, size_t nBytes, int flags) {
197    return send(fd, buf, (int)nBytes, flags);
198}
199
200struct hostent *
201dbgsysGetHostByName(char *hostname) {
202    return gethostbyname(hostname);
203}
204
205unsigned short
206dbgsysHostToNetworkShort(unsigned short hostshort) {
207    return htons(hostshort);
208}
209
210int
211dbgsysSocket(int domain, int type, int protocol) {
212  int fd = (int)socket(domain, type, protocol);
213  if (fd != SOCKET_ERROR) {
214      SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
215  }
216  return fd;
217}
218
219int
220dbgsysSocketClose(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
234int
235dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) {
236    return bind(fd, name, namelen);
237}
238
239
240uint32_t
241dbgsysInetAddr(const char* cp) {
242    return (uint32_t)inet_addr(cp);
243}
244
245uint32_t
246dbgsysHostToNetworkLong(uint32_t hostlong) {
247    return (uint32_t)htonl((u_long)hostlong);
248}
249
250unsigned short
251dbgsysNetworkToHostShort(unsigned short netshort) {
252    return ntohs(netshort);
253}
254
255int
256dbgsysGetSocketName(int fd, struct sockaddr *name, socklen_t *namelen) {
257    return getsockname(fd, name, namelen);
258}
259
260uint32_t
261dbgsysNetworkToHostLong(uint32_t netlong) {
262    return (uint32_t)ntohl((u_long)netlong);
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
272int
273dbgsysSetSocketOption(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
332int 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
349int
350dbgsysPoll(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
381int
382dbgsysGetLastIOError(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
408int
409dbgsysTlsAlloc() {
410    return TlsAlloc();
411}
412
413void
414dbgsysTlsFree(int index) {
415    TlsFree(index);
416}
417
418void
419dbgsysTlsPut(int index, void *value) {
420    TlsSetValue(index, value);
421}
422
423void *
424dbgsysTlsGet(int index) {
425    return TlsGetValue(index);
426}
427
428#define FT2INT64(ft) \
429        ((INT64)(ft).dwHighDateTime << 32 | (INT64)(ft).dwLowDateTime)
430
431long
432dbgsysCurrentTimeMillis() {
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}
452