1/*
2 * Copyright (c) 2001, 2016, 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
26#include <windows.h>
27#include <winsock2.h>
28#include "jni.h"
29#include "jni_util.h"
30#include "jvm.h"
31#include "jlong.h"
32
33#include "nio.h"
34#include "nio_util.h"
35#include "net_util.h"
36
37#include "sun_nio_ch_Net.h"
38#include "sun_nio_ch_PollArrayWrapper.h"
39
40/**
41 * Definitions to allow for building with older SDK include files.
42 */
43
44#ifndef MCAST_BLOCK_SOURCE
45
46#define MCAST_BLOCK_SOURCE          43
47#define MCAST_UNBLOCK_SOURCE        44
48#define MCAST_JOIN_SOURCE_GROUP     45
49#define MCAST_LEAVE_SOURCE_GROUP    46
50
51#endif  /* MCAST_BLOCK_SOURCE */
52
53typedef struct my_ip_mreq_source {
54    IN_ADDR imr_multiaddr;
55    IN_ADDR imr_sourceaddr;
56    IN_ADDR imr_interface;
57};
58
59typedef struct my_group_source_req {
60    ULONG gsr_interface;
61    SOCKADDR_STORAGE gsr_group;
62    SOCKADDR_STORAGE gsr_source;
63};
64
65/**
66 * Copy IPv6 address as jbytearray to target
67 */
68#define COPY_INET6_ADDRESS(env, source, target) \
69    (*env)->GetByteArrayRegion(env, source, 0, 16, target)
70
71/**
72 * Enable or disable receipt of WSAECONNRESET errors.
73 */
74static void setConnectionReset(SOCKET s, BOOL enable) {
75    DWORD bytesReturned = 0;
76    WSAIoctl(s, SIO_UDP_CONNRESET, &enable, sizeof(enable),
77             NULL, 0, &bytesReturned, NULL, NULL);
78}
79
80
81JNIEXPORT void JNICALL
82Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
83{
84    initInetAddressIDs(env);
85}
86
87JNIEXPORT jboolean JNICALL
88Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
89{
90    /*
91     * Return true if IPv6 is configured
92     */
93    return ipv6_available() ? JNI_TRUE : JNI_FALSE;
94}
95
96JNIEXPORT jboolean JNICALL
97Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
98{
99    // SO_REUSEPORT is not supported on Windows
100    return JNI_FALSE;
101}
102
103JNIEXPORT jint JNICALL
104Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
105    return 1;
106}
107
108
109JNIEXPORT jboolean JNICALL
110Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
111{
112    return JNI_FALSE;
113}
114
115JNIEXPORT jboolean JNICALL
116Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
117{
118    return JNI_FALSE;
119}
120
121JNIEXPORT jint JNICALL
122Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
123                            jboolean stream, jboolean reuse, jboolean fastLoopback)
124{
125    SOCKET s;
126    int domain = (preferIPv6) ? AF_INET6 : AF_INET;
127
128    s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
129    if (s != INVALID_SOCKET) {
130        SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
131
132        /* IPV6_V6ONLY is true by default */
133        if (domain == AF_INET6) {
134            int opt = 0;
135            setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
136                       (const char *)&opt, sizeof(opt));
137        }
138
139        /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */
140        if (!stream) {
141            setConnectionReset(s, FALSE);
142        }
143
144    } else {
145        NET_ThrowNew(env, WSAGetLastError(), "socket");
146    }
147
148    if (stream && fastLoopback) {
149        static int loopback_available = 1;
150        if (loopback_available) {
151            int rv = NET_EnableFastTcpLoopback((jint)s);
152            if (rv) {
153                if (rv == WSAEOPNOTSUPP) {
154                    loopback_available = 0;
155                } else {
156                    NET_ThrowNew(env, rv, "fastLoopback");
157                }
158            }
159        }
160    }
161
162    return (jint)s;
163}
164
165JNIEXPORT void JNICALL
166Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
167                          jboolean isExclBind, jobject iao, jint port)
168{
169    SOCKETADDRESS sa;
170    int rv;
171    int sa_len = 0;
172
173    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
174        return;
175    }
176
177    rv = NET_WinBind(fdval(env, fdo), &sa, sa_len, isExclBind);
178    if (rv == SOCKET_ERROR)
179        NET_ThrowNew(env, WSAGetLastError(), "bind");
180}
181
182JNIEXPORT void JNICALL
183Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
184{
185    if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) {
186        NET_ThrowNew(env, WSAGetLastError(), "listen");
187    }
188}
189
190
191JNIEXPORT jint JNICALL
192Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo,
193                             jobject iao, jint port)
194{
195    SOCKETADDRESS sa;
196    int rv;
197    int sa_len = 0;
198    SOCKET s = (SOCKET)fdval(env, fdo);
199
200    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
201        return IOS_THROWN;
202    }
203
204    rv = connect(s, &sa.sa, sa_len);
205    if (rv != 0) {
206        int err = WSAGetLastError();
207        if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
208            return IOS_UNAVAILABLE;
209        }
210        NET_ThrowNew(env, err, "connect");
211        return IOS_THROWN;
212    } else {
213        /* Enable WSAECONNRESET errors when a UDP socket is connected */
214        int type = 0, optlen = sizeof(type);
215        rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen);
216        if (rv == 0 && type == SOCK_DGRAM) {
217            setConnectionReset(s, TRUE);
218        }
219    }
220    return 1;
221}
222
223JNIEXPORT jint JNICALL
224Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
225{
226    SOCKETADDRESS sa;
227    int sa_len = sizeof(sa);
228
229    if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
230        int error = WSAGetLastError();
231        if (error == WSAEINVAL) {
232            return 0;
233        }
234        NET_ThrowNew(env, error, "getsockname");
235        return IOS_THROWN;
236    }
237    return NET_GetPortFromSockaddr(&sa);
238}
239
240JNIEXPORT jobject JNICALL
241Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
242{
243    SOCKETADDRESS sa;
244    int sa_len = sizeof(sa);
245    int port;
246
247    if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
248        NET_ThrowNew(env, WSAGetLastError(), "getsockname");
249        return NULL;
250    }
251    return NET_SockaddrToInetAddress(env, &sa, &port);
252}
253
254JNIEXPORT jint JNICALL
255Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
256{
257    SOCKETADDRESS sa;
258    int sa_len = sizeof(sa);
259
260    if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
261        int error = WSAGetLastError();
262        if (error == WSAEINVAL) {
263            return 0;
264        }
265        NET_ThrowNew(env, error, "getsockname");
266        return IOS_THROWN;
267    }
268    return NET_GetPortFromSockaddr(&sa);
269}
270
271JNIEXPORT jobject JNICALL
272Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
273{
274    SOCKETADDRESS sa;
275    int sa_len = sizeof(sa);
276    int port;
277
278    if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
279        NET_ThrowNew(env, WSAGetLastError(), "getsockname");
280        return NULL;
281    }
282    return NET_SockaddrToInetAddress(env, &sa, &port);
283}
284
285JNIEXPORT jint JNICALL
286Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
287                                  jboolean mayNeedConversion, jint level, jint opt)
288{
289    int result = 0;
290    struct linger linger;
291    char *arg;
292    int arglen, n;
293
294    if (level == SOL_SOCKET && opt == SO_LINGER) {
295        arg = (char *)&linger;
296        arglen = sizeof(linger);
297    } else {
298        arg = (char *)&result;
299        arglen = sizeof(result);
300    }
301
302    /**
303     * HACK: IP_TOS is deprecated on Windows and querying the option
304     * returns a protocol error. NET_GetSockOpt handles this and uses
305     * a fallback mechanism. Same applies to IPV6_TCLASS
306     */
307    if ((level == IPPROTO_IP && opt == IP_TOS) || (level == IPPROTO_IPV6 && opt == IPV6_TCLASS)) {
308        mayNeedConversion = JNI_TRUE;
309    }
310
311    if (mayNeedConversion) {
312        n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen);
313    } else {
314        n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
315    }
316    if (n < 0) {
317        handleSocketError(env, WSAGetLastError());
318        return IOS_THROWN;
319    }
320
321    if (level == SOL_SOCKET && opt == SO_LINGER)
322        return linger.l_onoff ? linger.l_linger : -1;
323    else
324        return result;
325}
326
327JNIEXPORT void JNICALL
328Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
329                                  jboolean mayNeedConversion, jint level, jint opt, jint arg, jboolean ipv6)
330{
331    struct linger linger;
332    char *parg;
333    int arglen, n;
334
335    if (level == SOL_SOCKET && opt == SO_LINGER) {
336        parg = (char *)&linger;
337        arglen = sizeof(linger);
338        if (arg >= 0) {
339            linger.l_onoff = 1;
340            linger.l_linger = (unsigned short)arg;
341        } else {
342            linger.l_onoff = 0;
343            linger.l_linger = 0;
344        }
345    } else {
346        parg = (char *)&arg;
347        arglen = sizeof(arg);
348    }
349
350    if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS) {
351        /* No op */
352        return;
353    }
354
355    if (mayNeedConversion) {
356        n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
357    } else {
358        n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
359    }
360    if (n < 0)
361        handleSocketError(env, WSAGetLastError());
362}
363
364JNIEXPORT jint JNICALL
365Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
366                                jint group, jint interf, jint source)
367{
368    struct ip_mreq mreq;
369    struct my_ip_mreq_source mreq_source;
370    int opt, n, optlen;
371    void* optval;
372
373    if (source == 0) {
374        mreq.imr_multiaddr.s_addr = htonl(group);
375        mreq.imr_interface.s_addr = htonl(interf);
376        opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
377        optval = (void*)&mreq;
378        optlen = sizeof(mreq);
379    } else {
380        mreq_source.imr_multiaddr.s_addr = htonl(group);
381        mreq_source.imr_sourceaddr.s_addr = htonl(source);
382        mreq_source.imr_interface.s_addr = htonl(interf);
383        opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
384        optval = (void*)&mreq_source;
385        optlen = sizeof(mreq_source);
386    }
387
388    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
389    if (n < 0) {
390        if (join && (WSAGetLastError() == WSAENOPROTOOPT))
391            return IOS_UNAVAILABLE;
392        handleSocketError(env, WSAGetLastError());
393    }
394    return 0;
395}
396
397JNIEXPORT jint JNICALL
398Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
399                                   jint group, jint interf, jint source)
400{
401    struct my_ip_mreq_source mreq_source;
402    int n;
403    int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
404
405    mreq_source.imr_multiaddr.s_addr = htonl(group);
406    mreq_source.imr_sourceaddr.s_addr = htonl(source);
407    mreq_source.imr_interface.s_addr = htonl(interf);
408
409    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
410                   (void*)&mreq_source, sizeof(mreq_source));
411    if (n < 0) {
412        if (block && (WSAGetLastError() == WSAENOPROTOOPT))
413            return IOS_UNAVAILABLE;
414        handleSocketError(env, WSAGetLastError());
415    }
416    return 0;
417}
418
419/**
420 * Call setsockopt with a IPPROTO_IPV6 level socket option
421 * and a group_source_req structure as the option value. The
422 * given IPv6 group, interface index, and IPv6 source address
423 * are copied into the structure.
424 */
425static int setGroupSourceReqOption(JNIEnv* env,
426                                   jobject fdo,
427                                   int opt,
428                                   jbyteArray group,
429                                   jint index,
430                                   jbyteArray source)
431{
432    struct my_group_source_req req;
433    struct sockaddr_in6* sin6;
434
435    req.gsr_interface = (ULONG)index;
436
437    sin6 = (struct sockaddr_in6*)&(req.gsr_group);
438    sin6->sin6_family = AF_INET6;
439    COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
440
441    sin6 = (struct sockaddr_in6*)&(req.gsr_source);
442    sin6->sin6_family = AF_INET6;
443    COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
444
445    return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req));
446}
447
448JNIEXPORT jint JNICALL
449Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
450                                jbyteArray group, jint index, jbyteArray source)
451{
452    struct ipv6_mreq mreq6;
453    int n;
454
455    if (source == NULL) {
456        int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
457        COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
458        mreq6.ipv6mr_interface = (int)index;
459        n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
460                       (void*)&mreq6, sizeof(mreq6));
461    } else {
462        int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
463        n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
464    }
465
466    if (n < 0) {
467        handleSocketError(env, errno);
468    }
469    return 0;
470}
471
472JNIEXPORT jint JNICALL
473Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
474                                    jbyteArray group, jint index, jbyteArray source)
475{
476    int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
477    int n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
478    if (n < 0) {
479        handleSocketError(env, errno);
480    }
481    return 0;
482}
483
484JNIEXPORT void JNICALL
485Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
486{
487    struct in_addr in;
488    int arglen = sizeof(struct in_addr);
489    int n;
490
491    in.s_addr = htonl(interf);
492
493    n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
494                   (void*)&(in.s_addr), arglen);
495    if (n < 0) {
496        handleSocketError(env, WSAGetLastError());
497    }
498}
499
500JNIEXPORT jint JNICALL
501Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
502{
503    struct in_addr in;
504    int arglen = sizeof(struct in_addr);
505    int n;
506
507    n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
508    if (n < 0) {
509        handleSocketError(env, WSAGetLastError());
510        return IOS_THROWN;
511    }
512    return ntohl(in.s_addr);
513}
514
515JNIEXPORT void JNICALL
516Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
517{
518    int value = (jint)index;
519    int arglen = sizeof(value);
520    int n;
521
522    n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
523                   (void*)&(index), arglen);
524    if (n < 0) {
525        handleSocketError(env, errno);
526    }
527}
528
529JNIEXPORT jint JNICALL
530Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
531{
532    int index;
533    int arglen = sizeof(index);
534    int n;
535
536    n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
537    if (n < 0) {
538        handleSocketError(env, errno);
539        return -1;
540    }
541    return (jint)index;
542}
543
544JNIEXPORT void JNICALL
545Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) {
546    int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE :
547        (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH;
548    if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) {
549        NET_ThrowNew(env, WSAGetLastError(), "shutdown");
550    }
551}
552
553JNIEXPORT jint JNICALL
554Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlong timeout)
555{
556    int rv;
557    int revents = 0;
558    struct timeval t;
559    int lastError = 0;
560    fd_set rd, wr, ex;
561    jint fd = fdval(env, fdo);
562
563    t.tv_sec = (long)(timeout / 1000);
564    t.tv_usec = (timeout % 1000) * 1000;
565
566    FD_ZERO(&rd);
567    FD_ZERO(&wr);
568    FD_ZERO(&ex);
569    if (events & POLLIN) {
570        FD_SET(fd, &rd);
571    }
572    if (events & POLLOUT ||
573        events & POLLCONN) {
574        FD_SET(fd, &wr);
575    }
576    FD_SET(fd, &ex);
577
578    rv = select(fd+1, &rd, &wr, &ex, &t);
579
580    /* save last winsock error */
581    if (rv == SOCKET_ERROR) {
582        handleSocketError(env, lastError);
583        return IOS_THROWN;
584    } else if (rv >= 0) {
585        rv = 0;
586        if (FD_ISSET(fd, &rd)) {
587            rv |= POLLIN;
588        }
589        if (FD_ISSET(fd, &wr)) {
590            rv |= POLLOUT;
591        }
592        if (FD_ISSET(fd, &ex)) {
593            rv |= POLLERR;
594        }
595    }
596    return rv;
597}
598
599JNIEXPORT jshort JNICALL
600Java_sun_nio_ch_Net_pollinValue(JNIEnv *env, jclass this)
601{
602    return (jshort)POLLIN;
603}
604
605JNIEXPORT jshort JNICALL
606Java_sun_nio_ch_Net_polloutValue(JNIEnv *env, jclass this)
607{
608    return (jshort)POLLOUT;
609}
610
611JNIEXPORT jshort JNICALL
612Java_sun_nio_ch_Net_pollerrValue(JNIEnv *env, jclass this)
613{
614    return (jshort)POLLERR;
615}
616
617JNIEXPORT jshort JNICALL
618Java_sun_nio_ch_Net_pollhupValue(JNIEnv *env, jclass this)
619{
620    return (jshort)POLLHUP;
621}
622
623JNIEXPORT jshort JNICALL
624Java_sun_nio_ch_Net_pollnvalValue(JNIEnv *env, jclass this)
625{
626    return (jshort)POLLNVAL;
627}
628
629JNIEXPORT jshort JNICALL
630Java_sun_nio_ch_Net_pollconnValue(JNIEnv *env, jclass this)
631{
632    return (jshort)POLLCONN;
633}
634