src/jdk.sctp/unix/native/libsctp/SctpNet.c
changeset 47216 71c04702a3d5
parent 43100 a7e3457672c7
child 57826 bf4c808a4488
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2009, 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 <stdlib.h>
       
    27 #include <string.h>
       
    28 #include <dlfcn.h>
       
    29 
       
    30 #include "Sctp.h"
       
    31 #include "jni.h"
       
    32 #include "jni_util.h"
       
    33 #include "nio_util.h"
       
    34 #include "nio.h"
       
    35 #include "net_util.h"
       
    36 #include "net_util_md.h"
       
    37 #include "sun_nio_ch_sctp_SctpNet.h"
       
    38 #include "sun_nio_ch_sctp_SctpStdSocketOption.h"
       
    39 
       
    40 static jclass isaCls = 0;
       
    41 static jmethodID isaCtrID = 0;
       
    42 
       
    43 static const char* nativeSctpLib = "libsctp.so.1";
       
    44 static jboolean funcsLoaded = JNI_FALSE;
       
    45 
       
    46 JNIEXPORT jint JNICALL DEF_JNI_OnLoad
       
    47   (JavaVM *vm, void *reserved) {
       
    48     return JNI_VERSION_1_2;
       
    49 }
       
    50 
       
    51 static int preCloseFD = -1;     /* File descriptor to which we dup other fd's
       
    52                                    before closing them for real */
       
    53 
       
    54 /**
       
    55  * Loads the native sctp library that contains the socket extension
       
    56  * functions, as well as locating the individual functions.
       
    57  * There will be a pending exception if this method returns false.
       
    58  */
       
    59 jboolean loadSocketExtensionFuncs
       
    60   (JNIEnv* env) {
       
    61     if (dlopen(nativeSctpLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) {
       
    62         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    63               dlerror());
       
    64         return JNI_FALSE;
       
    65     }
       
    66 
       
    67     if ((nio_sctp_getladdrs = (sctp_getladdrs_func*)
       
    68             dlsym(RTLD_DEFAULT, "sctp_getladdrs")) == NULL) {
       
    69         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    70               dlerror());
       
    71         return JNI_FALSE;
       
    72     }
       
    73 
       
    74     if ((nio_sctp_freeladdrs = (sctp_freeladdrs_func*)
       
    75             dlsym(RTLD_DEFAULT, "sctp_freeladdrs")) == NULL) {
       
    76         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    77               dlerror());
       
    78         return JNI_FALSE;
       
    79     }
       
    80 
       
    81     if ((nio_sctp_getpaddrs = (sctp_getpaddrs_func*)
       
    82             dlsym(RTLD_DEFAULT, "sctp_getpaddrs")) == NULL) {
       
    83         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    84               dlerror());
       
    85         return JNI_FALSE;
       
    86     }
       
    87 
       
    88     if ((nio_sctp_freepaddrs = (sctp_freepaddrs_func*)
       
    89             dlsym(RTLD_DEFAULT, "sctp_freepaddrs")) == NULL) {
       
    90         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    91               dlerror());
       
    92         return JNI_FALSE;
       
    93     }
       
    94 
       
    95     if ((nio_sctp_bindx = (sctp_bindx_func*)
       
    96             dlsym(RTLD_DEFAULT, "sctp_bindx")) == NULL) {
       
    97         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    98               dlerror());
       
    99         return JNI_FALSE;
       
   100     }
       
   101 
       
   102     if ((nio_sctp_peeloff = (sctp_peeloff_func*)
       
   103             dlsym(RTLD_DEFAULT, "sctp_peeloff")) == NULL) {
       
   104         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
   105               dlerror());
       
   106         return JNI_FALSE;
       
   107     }
       
   108 
       
   109     funcsLoaded = JNI_TRUE;
       
   110     return JNI_TRUE;
       
   111 }
       
   112 
       
   113 jint
       
   114 handleSocketError(JNIEnv *env, jint errorValue)
       
   115 {
       
   116     char *xn;
       
   117     switch (errorValue) {
       
   118         case EINPROGRESS:     /* Non-blocking connect */
       
   119             return 0;
       
   120         case EPROTO:
       
   121             xn= JNU_JAVANETPKG "ProtocolException";
       
   122             break;
       
   123         case ECONNREFUSED:
       
   124             xn = JNU_JAVANETPKG "ConnectException";
       
   125             break;
       
   126         case ETIMEDOUT:
       
   127             xn = JNU_JAVANETPKG "ConnectException";
       
   128             break;
       
   129         case EHOSTUNREACH:
       
   130             xn = JNU_JAVANETPKG "NoRouteToHostException";
       
   131             break;
       
   132         case EADDRINUSE:  /* Fall through */
       
   133         case EADDRNOTAVAIL:
       
   134             xn = JNU_JAVANETPKG "BindException";
       
   135             break;
       
   136         default:
       
   137             xn = JNU_JAVANETPKG "SocketException";
       
   138             break;
       
   139     }
       
   140     errno = errorValue;
       
   141     JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
       
   142     return IOS_THROWN;
       
   143 }
       
   144 
       
   145 /*
       
   146  * Class:     sun_nio_ch_sctp_SctpNet
       
   147  * Method:    init
       
   148  * Signature: ()V
       
   149  */
       
   150 JNIEXPORT void JNICALL
       
   151 Java_sun_nio_ch_sctp_SctpNet_init
       
   152   (JNIEnv *env, jclass cl) {
       
   153     int sp[2];
       
   154     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
       
   155         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
       
   156         return;
       
   157     }
       
   158     preCloseFD = sp[0];
       
   159     close(sp[1]);
       
   160     initInetAddressIDs(env);
       
   161 }
       
   162 
       
   163 /*
       
   164  * Class:     sun_nio_ch_sctp_SctpNet
       
   165  * Method:    socket0
       
   166  * Signature: (Z)I
       
   167  */
       
   168 JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpNet_socket0
       
   169   (JNIEnv *env, jclass klass, jboolean oneToOne) {
       
   170     int fd;
       
   171     struct sctp_event_subscribe event;
       
   172 #ifdef AF_INET6
       
   173     int domain = ipv6_available() ? AF_INET6 : AF_INET;
       
   174 #else
       
   175     int domain = AF_INET;
       
   176 #endif
       
   177 
       
   178     /* Try to load the socket API extension functions */
       
   179     if (!funcsLoaded && !loadSocketExtensionFuncs(env)) {
       
   180         return 0;
       
   181     }
       
   182 
       
   183     fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
       
   184 
       
   185     if (fd < 0) {
       
   186         return handleSocketError(env, errno);
       
   187     }
       
   188 
       
   189     /* Enable events */
       
   190     memset(&event, 0, sizeof(event));
       
   191     event.sctp_data_io_event = 1;
       
   192     event.sctp_association_event = 1;
       
   193     event.sctp_address_event = 1;
       
   194     event.sctp_send_failure_event = 1;
       
   195     //event.sctp_peer_error_event = 1;
       
   196     event.sctp_shutdown_event = 1;
       
   197     //event.sctp_partial_delivery_event = 1;
       
   198     //event.sctp_adaptation_layer_event = 1;
       
   199     if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
       
   200        handleSocketError(env, errno);
       
   201     }
       
   202     return fd;
       
   203 }
       
   204 
       
   205 /*
       
   206  * Class:     sun_nio_ch_sctp_SctpNet
       
   207  * Method:    bindx
       
   208  * Signature: (I[Ljava/net/InetAddress;IIZ)V
       
   209  */
       
   210 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_bindx
       
   211   (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port,
       
   212    jint addrsLength, jboolean add, jboolean preferIPv6) {
       
   213     SOCKETADDRESS *sap, *tmpSap;
       
   214     int i;
       
   215     jobject ia;
       
   216 
       
   217     if (addrsLength < 1)
       
   218         return;
       
   219 
       
   220     if ((sap = calloc(addrsLength, sizeof(SOCKETADDRESS))) == NULL) {
       
   221         JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
       
   222         return;
       
   223     }
       
   224 
       
   225     tmpSap = sap;
       
   226     for (i = 0; i < addrsLength; i++) {
       
   227         ia = (*env)->GetObjectArrayElement(env, addrs, i);
       
   228         if (NET_InetAddressToSockaddr(env, ia, port, tmpSap, NULL,
       
   229                                       preferIPv6) != 0) {
       
   230             free(sap);
       
   231             return;
       
   232         }
       
   233         tmpSap++;
       
   234     }
       
   235 
       
   236     if (nio_sctp_bindx(fd, (void *)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR :
       
   237                        SCTP_BINDX_REM_ADDR) != 0) {
       
   238         handleSocketError(env, errno);
       
   239     }
       
   240 
       
   241     free(sap);
       
   242 }
       
   243 
       
   244 /*
       
   245  * Class:     sun_nio_ch_sctp_SctpNet
       
   246  * Method:    listen0
       
   247  * Signature: (II)V
       
   248  */
       
   249 JNIEXPORT void JNICALL
       
   250 Java_sun_nio_ch_sctp_SctpNet_listen0
       
   251   (JNIEnv *env, jclass cl, jint fd, jint backlog) {
       
   252     if (listen(fd, backlog) < 0)
       
   253         handleSocketError(env, errno);
       
   254 }
       
   255 
       
   256 /*
       
   257  * Class:     sun_nio_ch_sctp_SctpNet
       
   258  * Method:    connect0
       
   259  * Signature: (ILjava/net/InetAddress;I)I
       
   260  */
       
   261 JNIEXPORT jint JNICALL
       
   262 Java_sun_nio_ch_sctp_SctpNet_connect0
       
   263   (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) {
       
   264     SOCKETADDRESS sa;
       
   265     int sa_len = 0;
       
   266     int rv;
       
   267 
       
   268     if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
       
   269                                   JNI_TRUE) != 0) {
       
   270         return IOS_THROWN;
       
   271     }
       
   272 
       
   273     rv = connect(fd, &sa.sa, sa_len);
       
   274     if (rv != 0) {
       
   275         if (errno == EINPROGRESS) {
       
   276             return IOS_UNAVAILABLE;
       
   277         } else if (errno == EINTR) {
       
   278             return IOS_INTERRUPTED;
       
   279         }
       
   280         return handleSocketError(env, errno);
       
   281     }
       
   282     return 1;
       
   283 }
       
   284 
       
   285 /*
       
   286  * Class:     sun_nio_ch_sctp_SctpNet
       
   287  * Method:    close0
       
   288  * Signature: (I)V
       
   289  */
       
   290 JNIEXPORT void JNICALL
       
   291 Java_sun_nio_ch_sctp_SctpNet_close0
       
   292   (JNIEnv *env, jclass clazz, jint fd) {
       
   293     if (fd != -1) {
       
   294         int rv = close(fd);
       
   295         if (rv < 0)
       
   296             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
       
   297     }
       
   298 }
       
   299 
       
   300 /*
       
   301  * Class:     sun_nio_ch_sctp_SctpNet
       
   302  * Method:    preClose0
       
   303  * Signature: (I)V
       
   304  */
       
   305 JNIEXPORT void JNICALL
       
   306 Java_sun_nio_ch_sctp_SctpNet_preClose0
       
   307   (JNIEnv *env, jclass clazz, jint fd) {
       
   308     if (preCloseFD >= 0) {
       
   309         if (dup2(preCloseFD, fd) < 0)
       
   310             JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
       
   311     }
       
   312 }
       
   313 
       
   314 void initializeISA(JNIEnv* env) {
       
   315     if (isaCls == 0) {
       
   316         jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
       
   317         CHECK_NULL(c);
       
   318         isaCtrID = (*env)->GetMethodID(env, c, "<init>",
       
   319                                      "(Ljava/net/InetAddress;I)V");
       
   320         CHECK_NULL(isaCtrID);
       
   321         isaCls = (*env)->NewGlobalRef(env, c);
       
   322         CHECK_NULL(isaCls);
       
   323         (*env)->DeleteLocalRef(env, c);
       
   324     }
       
   325 }
       
   326 
       
   327 jobject SockAddrToInetSocketAddress(JNIEnv *env, SOCKETADDRESS *sap) {
       
   328     int port = 0;
       
   329 
       
   330     jobject ia = NET_SockaddrToInetAddress(env, sap, &port);
       
   331     if (ia == NULL)
       
   332         return NULL;
       
   333 
       
   334     if (isaCls == 0) {
       
   335         initializeISA(env);
       
   336         CHECK_NULL_RETURN(isaCls, NULL);
       
   337     }
       
   338 
       
   339     return (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   340 }
       
   341 
       
   342 /*
       
   343  * Class:     sun_nio_ch_sctp_SctpNet
       
   344  * Method:    getLocalAddresses0
       
   345  * Signature: (I)[Ljava/net/SocketAddress;
       
   346  */
       
   347 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0
       
   348   (JNIEnv *env, jclass klass, jint fd)
       
   349 {
       
   350     void *addr_buf, *laddr;
       
   351     int i, addrCount;
       
   352     jobjectArray isaa;
       
   353 
       
   354 #ifdef __solaris__
       
   355     if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
       
   356 #else /* __linux__ */
       
   357     if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
       
   358 #endif
       
   359         handleSocketError(env, errno);
       
   360         return NULL;
       
   361     }
       
   362 
       
   363     if (addrCount < 1)
       
   364         return NULL;
       
   365 
       
   366     if (isaCls == 0) {
       
   367         initializeISA(env);
       
   368         CHECK_NULL_RETURN(isaCls, NULL);
       
   369     }
       
   370 
       
   371     isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
       
   372     if (isaa == NULL) {
       
   373         nio_sctp_freeladdrs(addr_buf);
       
   374         return NULL;
       
   375     }
       
   376 
       
   377     laddr = addr_buf;
       
   378     for (i = 0; i < addrCount; i++) {
       
   379         int port = 0;
       
   380         jobject ia, isa = NULL;
       
   381         ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
       
   382         if (ia != NULL)
       
   383             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   384         if (isa == NULL)
       
   385             break;
       
   386         (*env)->SetObjectArrayElement(env, isaa, i, isa);
       
   387 
       
   388         if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
       
   389             addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
       
   390         else
       
   391             addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
       
   392     }
       
   393 
       
   394     nio_sctp_freeladdrs(laddr);
       
   395     return isaa;
       
   396 }
       
   397 
       
   398 jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) {
       
   399     void *addr_buf, *paddr;
       
   400     int i, addrCount;
       
   401     jobjectArray isaa;
       
   402 
       
   403 #if __solaris__
       
   404     if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
       
   405 #else /* __linux__ */
       
   406     if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) {
       
   407 #endif
       
   408         handleSocketError(env, errno);
       
   409         return NULL;
       
   410     }
       
   411 
       
   412     if (addrCount < 1)
       
   413         return NULL;
       
   414 
       
   415     if (isaCls == 0) {
       
   416         initializeISA(env);
       
   417         CHECK_NULL_RETURN(isaCls, NULL);
       
   418     }
       
   419 
       
   420     isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
       
   421     if (isaa == NULL) {
       
   422         nio_sctp_freepaddrs(addr_buf);
       
   423         return NULL;
       
   424     }
       
   425 
       
   426     paddr = addr_buf;
       
   427     for (i = 0; i < addrCount; i++) {
       
   428         int port = 0;
       
   429         jobject ia, isa = NULL;
       
   430         ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
       
   431         if (ia != NULL)
       
   432             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   433         if (isa == NULL)
       
   434             break;
       
   435         (*env)->SetObjectArrayElement(env, isaa, i, isa);
       
   436 
       
   437         if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
       
   438             addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
       
   439         else
       
   440             addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
       
   441     }
       
   442 
       
   443     nio_sctp_freepaddrs(paddr);
       
   444     return isaa;
       
   445 }
       
   446 
       
   447  /*
       
   448  * Class:     sun_nio_ch_sctp_SctpNet
       
   449  * Method:    getRemoteAddresses0
       
   450  * Signature: (II)[Ljava/net/SocketAddress;
       
   451  */
       
   452 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0
       
   453   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   454     return getRemoteAddresses(env, fd, assocId);
       
   455 }
       
   456 
       
   457 /* Map the Java level option to the native level */
       
   458 int mapSocketOption
       
   459   (jint cmd, int *level, int *optname) {
       
   460     static struct {
       
   461         jint cmd;
       
   462         int level;
       
   463         int optname;
       
   464     } const opts[] = {
       
   465         { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS,   IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
       
   466         { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE,   IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
       
   467         { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
       
   468         { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_NODELAY,             IPPROTO_SCTP, SCTP_NODELAY },
       
   469         { sun_nio_ch_sctp_SctpStdSocketOption_SO_SNDBUF,                SOL_SOCKET,   SO_SNDBUF },
       
   470         { sun_nio_ch_sctp_SctpStdSocketOption_SO_RCVBUF,                SOL_SOCKET,   SO_RCVBUF },
       
   471         { sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER,                SOL_SOCKET,   SO_LINGER } };
       
   472 
       
   473     int i;
       
   474     for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
       
   475         if (cmd == opts[i].cmd) {
       
   476             *level = opts[i].level;
       
   477             *optname = opts[i].optname;
       
   478             return 0;
       
   479         }
       
   480     }
       
   481 
       
   482     /* not found */
       
   483     return -1;
       
   484 }
       
   485 
       
   486 /*
       
   487  * Class:     sun_nio_ch_sctp_SctpNet
       
   488  * Method:    setIntOption0
       
   489  * Signature: (III)V
       
   490  */
       
   491 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setIntOption0
       
   492   (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
       
   493     int klevel, kopt;
       
   494     int result;
       
   495     struct linger linger;
       
   496     void *parg;
       
   497     int arglen;
       
   498 
       
   499     if (mapSocketOption(opt, &klevel, &kopt) < 0) {
       
   500         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   501                                      "Unsupported socket option");
       
   502         return;
       
   503     }
       
   504 
       
   505     if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
       
   506         parg = (void *)&linger;
       
   507         arglen = sizeof(linger);
       
   508         if (arg >= 0) {
       
   509             linger.l_onoff = 1;
       
   510             linger.l_linger = arg;
       
   511         } else {
       
   512             linger.l_onoff = 0;
       
   513             linger.l_linger = 0;
       
   514         }
       
   515     } else {
       
   516         parg = (void *)&arg;
       
   517         arglen = sizeof(arg);
       
   518     }
       
   519 
       
   520     if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) {
       
   521         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   522                                      "sun_nio_ch_sctp_SctpNet.setIntOption0");
       
   523     }
       
   524 }
       
   525 
       
   526 /*
       
   527  * Class:     sun_nio_ch_sctp_SctpNet
       
   528  * Method:    getIntOption0
       
   529  * Signature: (II)I
       
   530  */
       
   531 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_getIntOption0
       
   532   (JNIEnv *env, jclass klass, jint fd, jint opt) {
       
   533     int klevel, kopt;
       
   534     int result;
       
   535     struct linger linger;
       
   536     void *arg;
       
   537     int arglen;
       
   538 
       
   539     memset((char *) &linger, 0, sizeof(linger));
       
   540     if (mapSocketOption(opt, &klevel, &kopt) < 0) {
       
   541         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   542                                      "Unsupported socket option");
       
   543         return -1;
       
   544     }
       
   545 
       
   546     if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
       
   547         arg = (void *)&linger;
       
   548         arglen = sizeof(linger);
       
   549     } else {
       
   550         arg = (void *)&result;
       
   551         arglen = sizeof(result);
       
   552     }
       
   553 
       
   554     if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) {
       
   555         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   556                                      "sun.nio.ch.Net.getIntOption");
       
   557         return -1;
       
   558     }
       
   559 
       
   560     if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER)
       
   561         return linger.l_onoff ? linger.l_linger : -1;
       
   562     else
       
   563         return result;
       
   564 }
       
   565 
       
   566 /*
       
   567  * Class:     sun_nio_ch_sctp_SctpNet
       
   568  * Method:    getPrimAddrOption0
       
   569  * Signature: (II)Ljava/net/SocketAddress;
       
   570  */
       
   571 JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0
       
   572   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   573     struct sctp_setprim prim;
       
   574     unsigned int prim_len = sizeof(prim);
       
   575 
       
   576     prim.ssp_assoc_id = assocId;
       
   577 
       
   578     if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
       
   579         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   580                                      "sun.nio.ch.SctpNet.getPrimAddrOption0");
       
   581         return NULL;
       
   582     }
       
   583 
       
   584     return SockAddrToInetSocketAddress(env, (SOCKETADDRESS *)&prim.ssp_addr);
       
   585 }
       
   586 
       
   587 /*
       
   588  * Class:     sun_nio_ch_sctp_SctpNet
       
   589  * Method:    setPrimAddrOption0
       
   590  * Signature: (IILjava/net/InetAddress;I)V
       
   591  */
       
   592 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0
       
   593   (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
       
   594     struct sctp_setprim prim;
       
   595 
       
   596     if (NET_InetAddressToSockaddr(env, iaObj, port,
       
   597                                   (SOCKETADDRESS *)&prim.ssp_addr,
       
   598                                   NULL, JNI_TRUE) != 0) {
       
   599         return;
       
   600     }
       
   601 
       
   602     prim.ssp_assoc_id = assocId;
       
   603 
       
   604     if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
       
   605         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   606                                      "sun.nio.ch.SctpNet.setPrimAddrOption0");
       
   607     }
       
   608 }
       
   609 
       
   610 /*
       
   611  * Class:     sun_nio_ch_sctp_SctpNet
       
   612  * Method:    setPeerPrimAddrOption0
       
   613  * Signature: (IILjava/net/InetAddress;I)V
       
   614  */
       
   615 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPeerPrimAddrOption0
       
   616   (JNIEnv *env, jclass klass, jint fd, jint assocId,
       
   617    jobject iaObj, jint port, jboolean preferIPv6) {
       
   618     struct sctp_setpeerprim prim;
       
   619 
       
   620     if (NET_InetAddressToSockaddr(env, iaObj, port,
       
   621                                   (SOCKETADDRESS *)&prim.sspp_addr,
       
   622                                   NULL, preferIPv6) != 0) {
       
   623         return;
       
   624     }
       
   625 
       
   626     prim.sspp_assoc_id = assocId;
       
   627 
       
   628     if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
       
   629                    sizeof(prim)) < 0) {
       
   630         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   631                                      "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
       
   632     }
       
   633 }
       
   634 
       
   635 /*
       
   636  * Class:     sun_nio_ch_sctp_SctpNet
       
   637  * Method:    getInitMsgOption0
       
   638  * Signature: (I[I)V
       
   639  */
       
   640 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0
       
   641   (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
       
   642     struct sctp_initmsg sctp_initmsg;
       
   643     unsigned int sim_len = sizeof(sctp_initmsg);
       
   644     int vals[2];
       
   645 
       
   646     if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
       
   647             &sim_len) < 0) {
       
   648         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   649                                      "sun.nio.ch.SctpNet.getInitMsgOption0");
       
   650         return;
       
   651     }
       
   652 
       
   653     vals[0] = sctp_initmsg.sinit_max_instreams;
       
   654     vals[1] = sctp_initmsg.sinit_num_ostreams;
       
   655     (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
       
   656 }
       
   657 
       
   658 /*
       
   659  * Class:     sun_nio_ch_sctp_SctpNet
       
   660  * Method:    setInitMsgOption0
       
   661  * Signature: (III)V
       
   662  */
       
   663 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0
       
   664   (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
       
   665     struct sctp_initmsg sctp_initmsg;
       
   666 
       
   667     sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
       
   668     sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
       
   669     sctp_initmsg.sinit_max_attempts = 0;  // default
       
   670     sctp_initmsg.sinit_max_init_timeo = 0;  // default
       
   671 
       
   672     if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
       
   673           sizeof(sctp_initmsg)) < 0) {
       
   674         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   675                                      "sun.nio.ch.SctpNet.setInitMsgOption0");
       
   676     }
       
   677 }
       
   678 
       
   679 /*
       
   680  * Class:     sun_nio_ch_sctp_SctpNet
       
   681  * Method:    shutdown0
       
   682  * Signature: (II)V
       
   683  */
       
   684 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_shutdown0
       
   685   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   686     int rv;
       
   687     struct msghdr msg[1];
       
   688     struct iovec iov[1];
       
   689     int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
       
   690     char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
       
   691     struct cmsghdr* cmsg;
       
   692     struct sctp_sndrcvinfo *sri;
       
   693 
       
   694     /* SctpSocketChannel */
       
   695     if (assocId < 0) {
       
   696         shutdown(fd, SHUT_WR);
       
   697         return;
       
   698     }
       
   699 
       
   700     memset(msg, 0, sizeof (*msg));
       
   701     memset(cbuf, 0, cbuf_size);
       
   702     msg->msg_name = NULL;
       
   703     msg->msg_namelen = 0;
       
   704     iov->iov_base = NULL;
       
   705     iov->iov_len = 0;
       
   706     msg->msg_iov = iov;
       
   707     msg->msg_iovlen = 1;
       
   708     msg->msg_control = cbuf;
       
   709     msg->msg_controllen = cbuf_size;
       
   710     msg->msg_flags = 0;
       
   711 
       
   712     cmsg = CMSG_FIRSTHDR(msg);
       
   713     cmsg->cmsg_level = IPPROTO_SCTP;
       
   714     cmsg->cmsg_type = SCTP_SNDRCV;
       
   715     cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
       
   716 
       
   717     /* Initialize the payload: */
       
   718     sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
       
   719     memset(sri, 0, sizeof (*sri));
       
   720 
       
   721     if (assocId > 0) {
       
   722         sri->sinfo_assoc_id = assocId;
       
   723     }
       
   724 
       
   725     sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF;
       
   726 
       
   727     /* Sum of the length of all control messages in the buffer. */
       
   728     msg->msg_controllen = cmsg->cmsg_len;
       
   729 
       
   730     if ((rv = sendmsg(fd, msg, 0)) < 0) {
       
   731         handleSocketError(env, errno);
       
   732     }
       
   733 }
       
   734 
       
   735 /*
       
   736  * Class:     sun_nio_ch_sctp_SctpNet
       
   737  * Method:    branch
       
   738  * Signature: (II)I
       
   739  */
       
   740 JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_branch0
       
   741   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   742     int newfd = 0;
       
   743     if ((newfd = nio_sctp_peeloff(fd, assocId)) < 0) {
       
   744         handleSocketError(env, errno);
       
   745     }
       
   746 
       
   747     return newfd;
       
   748 }